LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* (no subject)
From: Jochen Maes @ 2006-07-06 12:21 UTC (permalink / raw)
  To: linuxppc-dev+unsubscribe



^ permalink raw reply

* Xilinx BSP for linux 2.6
From: Ming Liu @ 2006-07-06 12:49 UTC (permalink / raw)
  To: ammubhai; +Cc: linuxppc-embedded
In-Reply-To: <44A580F5.8050900@gmail.com>

Dear Ameet,
Now I am using your patch for SystemACE in Linux 2.6. My linux version is 
2.6.16-rc5 and I have applied the patch for SystemACE and Temac. 

When I generate BSP in EDK, how can I implement it in my linux kernel? I 
know the EDK BSP is for Linux 2.4 and the directory stucture is the same as 
2.4(e.g. arch/ppc/platform/xilinx_ocp/......) But in 2.6, the directory 
tree is different and I cannot simply copy and replace the original files 
there. Also, there is a file called xparameters_ml403.h in Linux kernel but 
in BSP there is only xparameters_ml300.h. Shall I rename the 
xparameters_ml300 as ml403, or configure the board as ml300 in menuconfig? 
In these xparameters files, the peripheral addresses are defined. How can I 
include these xparameters defination in the kernel? It looks complicate and 
you didn't mention how to replace these files in your article. So if you 
can provide some guidance, I will appreciate a lot because it will save me 
much time. 

By the way, I am still waiting for the last part of your article. Where are 
they? :)

Thanks for your help.

Regards
Ming

_________________________________________________________________
享用世界上最大的电子邮件系统― MSN Hotmail。  http://www.hotmail.com  

^ permalink raw reply

* Re: Xilinx BSP for linux 2.6
From: Ameet Patil @ 2006-07-06 13:31 UTC (permalink / raw)
  Cc: linuxppc-embedded
In-Reply-To: <BAY110-F18951B1690B257545F5EEB2770@phx.gbl>

Hi Ming,
  I DONOT have a ML403 with me. But does Xilinx EDK generate
xparameters_ml300.h in the BSP instead of xparameters_ml403.h for the
ML403 board?

Anyway, for linux 2.6 theres no xilinx_ocp directory in the code tree.
You need to just copy the xparameters_ml300.h file (if that is what
xilinx EDK generates) as xparameters_ml403.h in
arch/ppc/platforms/4xx/xparameters/ folder. Configure the kernel as ML403.

Like I said to you before, if you want to get started quickly and
without much headache.. then please go step-by-step. Try the things I
mention in the article PART I without applying any patches.

http://www.linux.get2knowmore.com/2006/06/30/quick-guide-linux-26-on-xilinx-virtex-ii-pro-boards-part-i/

Then if your kernel boots and shows some messages, it would be much
easier to relate to problems after applying patches.

Please DONOT hesitate to ask further clarifications!

-Ameet

Ming Liu wrote:
> Dear Ameet,
> Now I am using your patch for SystemACE in Linux 2.6. My linux version 
> is 2.6.16-rc5 and I have applied the patch for SystemACE and Temac.
> When I generate BSP in EDK, how can I implement it in my linux kernel? I 
> know the EDK BSP is for Linux 2.4 and the directory stucture is the same 
> as 2.4(e.g. arch/ppc/platform/xilinx_ocp/......) But in 2.6, the 
> directory tree is different and I cannot simply copy and replace the 
> original files there. Also, there is a file called xparameters_ml403.h 
> in Linux kernel but in BSP there is only xparameters_ml300.h. Shall I 
> rename the xparameters_ml300 as ml403, or configure the board as ml300 
> in menuconfig? In these xparameters files, the peripheral addresses are 
> defined. How can I include these xparameters defination in the kernel? 
> It looks complicate and you didn't mention how to replace these files in 
> your article. So if you can provide some guidance, I will appreciate a 
> lot because it will save me much time.
> By the way, I am still waiting for the last part of your article. Where 
> are they? :)
> 
> Thanks for your help.
> 
> Regards
> Ming
> 
> _________________________________________________________________
> 享用世界上最大的电子邮件系统― MSN Hotmail。  http://www.hotmail.com 
> 

^ permalink raw reply

* Re: [PATCH 1/3] Freescale QE UCC gigabit ethernet driver
From: Kumar Gala @ 2006-07-06 13:44 UTC (permalink / raw)
  To: Li Yang-r58472; +Cc: Andrew Morton, netdev, jgarzik, linuxppc-dev
In-Reply-To: <4879B0C6C249214CBE7AB04453F84E4DF208@zch01exm20.fsl.freescale.net>

Nack.  Here are some high level things that should be addressed:
* There is a ton of debug code that should probably be stripped out,  
such as dump_regs, etc..
* The phy support should use the phylib instead
* convert from being a platform_device to of_device

- kumar

On Jul 6, 2006, at 7:02 AM, Li Yang-r58472 wrote:

> This is a re-submission of the patch after some fix. First version of
> the patch may be blocked by the list due to size problem.
>
> QE(QUICC Engine) is a new generation communication coprocessor, which
> can be found on some of the latest Freescale PowerQUICC CPUs(e.g.
> MPC8360).  The UCC(Unified Communications Controller) module of QE can
> work as gigabit Ethernet device.  This patch provides driver for the
> device.
>
> Signed-off-by: Shlomi Gridish <gridish@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
>
> The patch is cut into 3 pieces for size reason.
> ---
>  drivers/net/Kconfig        |   27
>  drivers/net/Makefile       |    3
>  drivers/net/ucc_geth.c     | 4278
> ++++++++++++++++++++++++++++++++++++++++++++
>  drivers/net/ucc_geth.h     | 1334 ++++++++++++++
>  drivers/net/ucc_geth_phy.c |  801 ++++++++
>  drivers/net/ucc_geth_phy.h |  217 ++
>  6 files changed, 6660 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index bdaaad8..b0f6e22 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -2189,6 +2189,33 @@ config GFAR_NAPI
>  	bool "NAPI Support"
>  	depends on GIANFAR
>
> +config UCC_GETH
> +	tristate "Freescale QE UCC GETH"
> +	depends on QUICC_ENGINE && UCC_FAST
> +	help
> +	  This driver supports the Gigabit Ethernet mode of QE UCC.
> +	  QE can be found on MPC836x CPUs.
> +
> +config UGETH_NAPI
> +	bool "NAPI Support"
> +	depends on UCC_GETH
> +	
> +config UGETH_MAGIC_PACKET
> +	bool "Magic Packet detection support"
> +	depends on UCC_GETH
> +
> +config UGETH_FILTERING
> +	bool "Mac address filtering support"
> +	depends on UCC_GETH
> +
> +config UGETH_TX_ON_DEMOND
> +	bool "Transmit on Demond support"
> +	depends on UCC_GETH
> +
> +config UGETH_HAS_GIGA
> +	bool
> +	depends on UCC_GETH && MPC836x
> +
>  config MV643XX_ETH
>  	tristate "MV-643XX Ethernet support"
>  	depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 ||
> MOMENCO_OCELOT_3 || PPC_MULTIPLATFORM
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index b90468a..2054033 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -18,6 +18,9 @@ gianfar_driver-objs := gianfar.o \
>  		gianfar_mii.o \
>  		gianfar_sysfs.o
>
> +obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
> +ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o
> +
>  #
>  # link order important here
>  #
> diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
> new file mode 100644
> index 0000000..01cfca0
> --- /dev/null
> +++ b/drivers/net/ucc_geth.c
> @@ -0,0 +1,4278 @@
> +/*
> + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights
> reserved.
> + *
> + * Author: Shlomi Gridish <gridish@freescale.com>
> + *
> + * Description:
> + * QE UCC Gigabit Ethernet Driver
> + *
> + * Changelog:
> + * Jul 6, 2006 Li Yang <LeoLi@freescale.com>
> + * - Rearrange code and style fixes
> + *
> + * 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/kernel.h>
> +#include <linux/init.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/stddef.h>
> +#include <linux/interrupt.h>
> +#include <linux/netdevice.h>
> +#include <linux/etherdevice.h>
> +#include <linux/skbuff.h>
> +#include <linux/spinlock.h>
> +#include <linux/mm.h>
> +#include <linux/ethtool.h>
> +#include <linux/delay.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/fsl_devices.h>
> +#include <linux/ethtool.h>
> +#include <linux/platform_device.h>
> +#include <linux/mii.h>
> +
> +#include <asm/uaccess.h>
> +#include <asm/irq.h>
> +#include <asm/io.h>
> +#include <asm/immap_qe.h>
> +#include <asm/qe.h>
> +#include <asm/ucc.h>
> +#include <asm/ucc_fast.h>
> +
> +#include "ucc_geth.h"
> +#include "ucc_geth_phy.h"
> +
> +#undef DEBUG
> +
> +#define DRV_DESC "QE UCC Gigabit Ethernet Controller version:June 20,
> 2006"
> +#define DRV_NAME "ucc_geth"
> +
> +#define ugeth_printk(level, format, arg...)  \
> +        printk(level format "\n", ## arg)
> +
> +#define ugeth_dbg(format, arg...)            \
> +        ugeth_printk(KERN_DEBUG , format , ## arg)
> +#define ugeth_err(format, arg...)            \
> +        ugeth_printk(KERN_ERR , format , ## arg)
> +#define ugeth_info(format, arg...)           \
> +        ugeth_printk(KERN_INFO , format , ## arg)
> +#define ugeth_warn(format, arg...)           \
> +        ugeth_printk(KERN_WARNING , format , ## arg)
> +
> +#ifdef UGETH_VERBOSE_DEBUG
> +#define ugeth_vdbg ugeth_dbg
> +#else
> +#define ugeth_vdbg(fmt, args...) do { } while (0)
> +#endif				/* UGETH_VERBOSE_DEBUG */
> +
> +static DEFINE_SPINLOCK(ugeth_lock);
> +
> +static ucc_geth_info_t ugeth_primary_info = {
> +	.uf_info = {
> +		    .bd_mem_part = MEM_PART_SYSTEM,
> +		    .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES,
> +		    .max_rx_buf_length = 1536,
> +/* FIXME: should be changed in run time for 1G and 100M */
> +#ifdef CONFIG_UGETH_HAS_GIGA
> +		    .urfs = UCC_GETH_URFS_GIGA_INIT,
> +		    .urfet = UCC_GETH_URFET_GIGA_INIT,
> +		    .urfset = UCC_GETH_URFSET_GIGA_INIT,
> +		    .utfs = UCC_GETH_UTFS_GIGA_INIT,
> +		    .utfet = UCC_GETH_UTFET_GIGA_INIT,
> +		    .utftt = UCC_GETH_UTFTT_GIGA_INIT,
> +#else
> +		    .urfs = UCC_GETH_URFS_INIT,
> +		    .urfet = UCC_GETH_URFET_INIT,
> +		    .urfset = UCC_GETH_URFSET_INIT,
> +		    .utfs = UCC_GETH_UTFS_INIT,
> +		    .utfet = UCC_GETH_UTFET_INIT,
> +		    .utftt = UCC_GETH_UTFTT_INIT,
> +#endif
> +		    .ufpt = 256,
> +		    .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET,
> +		    .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL,
> +		    .tenc = UCC_FAST_TX_ENCODING_NRZ,
> +		    .renc = UCC_FAST_RX_ENCODING_NRZ,
> +		    .tcrc = UCC_FAST_16_BIT_CRC,
> +		    .synl = UCC_FAST_SYNC_LEN_NOT_USED,
> +		    },
> +	.numQueuesTx = 1,
> +	.numQueuesRx = 1,
> +	.extendedFilteringChainPointer = ((uint32_t) NULL),
> +	.typeorlen = 3072 /*1536 */ ,
> +	.nonBackToBackIfgPart1 = 0x40,
> +	.nonBackToBackIfgPart2 = 0x60,
> +	.miminumInterFrameGapEnforcement = 0x50,
> +	.backToBackInterFrameGap = 0x60,
> +	.mblinterval = 128,
> +	.nortsrbytetime = 5,
> +	.fracsiz = 1,
> +	.strictpriorityq = 0xff,
> +	.altBebTruncation = 0xa,
> +	.excessDefer = 1,
> +	.maxRetransmission = 0xf,
> +	.collisionWindow = 0x37,
> +	.receiveFlowControl = 1,
> +	.maxGroupAddrInHash = 4,
> +	.maxIndAddrInHash = 4,
> +	.prel = 7,
> +	.maxFrameLength = 1518,
> +	.minFrameLength = 64,
> +	.maxD1Length = 1520,
> +	.maxD2Length = 1520,
> +	.vlantype = 0x8100,
> +	.ecamptr = ((uint32_t) NULL),
> +	.eventRegMask = UCCE_OTHER,
> +	.pausePeriod = 0xf000,
> +	.interruptcoalescingmaxvalue = {1, 1, 1, 1, 1, 1, 1, 1},
> +	.bdRingLenTx = {
> +			TX_BD_RING_LEN,
> +			TX_BD_RING_LEN,
> +			TX_BD_RING_LEN,
> +			TX_BD_RING_LEN,
> +			TX_BD_RING_LEN,
> +			TX_BD_RING_LEN,
> +			TX_BD_RING_LEN,
> +			TX_BD_RING_LEN},
> +
> +	.bdRingLenRx = {
> +			RX_BD_RING_LEN,
> +			RX_BD_RING_LEN,
> +			RX_BD_RING_LEN,
> +			RX_BD_RING_LEN,
> +			RX_BD_RING_LEN,
> +			RX_BD_RING_LEN,
> +			RX_BD_RING_LEN,
> +			RX_BD_RING_LEN},
> +
> +	.numStationAddresses = UCC_GETH_NUM_OF_STATION_ADDRESSES_1,
> +	.largestexternallookupkeysize =
> +	    QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE,
> +	.statisticsMode = UCC_GETH_STATISTICS_GATHERING_MODE_NONE,
> +	.vlanOperationTagged = UCC_GETH_VLAN_OPERATION_TAGGED_NOP,
> +	.vlanOperationNonTagged =
> UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP,
> +	.rxQoSMode = UCC_GETH_QOS_MODE_DEFAULT,
> +	.aufc = UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_NONE,
> +	.padAndCrc = MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC,
> +	.numThreadsTx = UCC_GETH_NUM_OF_THREADS_4,
> +	.numThreadsRx = UCC_GETH_NUM_OF_THREADS_4,
> +	.riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
> +	.riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
> +};
> +
> +static ucc_geth_info_t ugeth_info[8];
> +
> +#ifdef DEBUG
> +static void mem_disp(u8 *addr, int size)
> +{
> +	u8 *i;
> +	int size16Aling = (size >> 4) << 4;
> +	int size4Aling = (size >> 2) << 2;
> +	int notAlign = 0;
> +	if (size % 16)
> +		notAlign = 1;
> +
> +	for (i = addr; (u32) i < (u32) addr + size16Aling; i += 16)
> +		printk("0x%08x: %08x %08x %08x %08x\r\n",
> +		       (u32) i,
> +		       *((u32 *) (i)),
> +		       *((u32 *) (i + 4)),
> +		       *((u32 *) (i + 8)), *((u32 *) (i + 12)));
> +	if (notAlign == 1)
> +		printk("0x%08x: ", (u32) i);
> +	for (; (u32) i < (u32) addr + size4Aling; i += 4)
> +		printk("%08x ", *((u32 *) (i)));
> +	for (; (u32) i < (u32) addr + size; i++)
> +		printk("%02x", *((u8 *) (i)));
> +	if (notAlign == 1)
> +		printk("\r\n");
> +}
> +#endif /* DEBUG */
> +
> +#ifdef CONFIG_UGETH_FILTERING
> +static void enqueue(struct list_head *node, struct list_head *lh)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(ugeth_lock, flags);
> +	list_add_tail(node, lh);
> +	spin_unlock_irqrestore(ugeth_lock, flags);
> +}
> +#endif /* CONFIG_UGETH_FILTERING */
> +
> +static struct list_head *dequeue(struct list_head *lh)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(ugeth_lock, flags);
> +	if (!list_empty(lh)) {
> +		struct list_head *node = lh->next;
> +		list_del(node);
> +		spin_unlock_irqrestore(ugeth_lock, flags);
> +		return node;
> +	} else {
> +		spin_unlock_irqrestore(ugeth_lock, flags);
> +		return NULL;
> +	}
> +}
> +
> +static int get_interface_details(enet_interface_e enet_interface,
> +				 enet_speed_e *speed,
> +				 int *r10m,
> +				 int *rmm,
> +				 int *rpm,
> +				 int *tbi, int *limited_to_full_duplex)
> +{
> +	/* Analyze enet_interface according to Interface Mode
> +	Configuration table */
> +	switch (enet_interface) {
> +	case ENET_10_MII:
> +		*speed = ENET_SPEED_10BT;
> +		break;
> +	case ENET_10_RMII:
> +		*speed = ENET_SPEED_10BT;
> +		*r10m = 1;
> +		*rmm = 1;
> +		break;
> +	case ENET_10_RGMII:
> +		*speed = ENET_SPEED_10BT;
> +		*rpm = 1;
> +		*r10m = 1;
> +		*limited_to_full_duplex = 1;
> +		break;
> +	case ENET_100_MII:
> +		*speed = ENET_SPEED_100BT;
> +		break;
> +	case ENET_100_RMII:
> +		*speed = ENET_SPEED_100BT;
> +		*rmm = 1;
> +		break;
> +	case ENET_100_RGMII:
> +		*speed = ENET_SPEED_100BT;
> +		*rpm = 1;
> +		*limited_to_full_duplex = 1;
> +		break;
> +	case ENET_1000_GMII:
> +		*speed = ENET_SPEED_1000BT;
> +		*limited_to_full_duplex = 1;
> +		break;
> +	case ENET_1000_RGMII:
> +		*speed = ENET_SPEED_1000BT;
> +		*rpm = 1;
> +		*limited_to_full_duplex = 1;
> +		break;
> +	case ENET_1000_TBI:
> +		*speed = ENET_SPEED_1000BT;
> +		*tbi = 1;
> +		*limited_to_full_duplex = 1;
> +		break;
> +	case ENET_1000_RTBI:
> +		*speed = ENET_SPEED_1000BT;
> +		*rpm = 1;
> +		*tbi = 1;
> +		*limited_to_full_duplex = 1;
> +		break;
> +	default:
> +		return -EINVAL;
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct sk_buff *get_new_skb(ucc_geth_private_t *ugeth, u8 *bd)
> +{
> +	struct sk_buff *skb = NULL;
> +
> +	skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
> +				  UCC_GETH_RX_DATA_BUF_ALIGNMENT);
> +
> +	if (skb == NULL)
> +		return NULL;
> +
> +	/* We need the data buffer to be aligned properly.  We will
> reserve
> +	 * as many bytes as needed to align the data properly
> +	 */
> +	skb_reserve(skb,
> +		    UCC_GETH_RX_DATA_BUF_ALIGNMENT -
> +		    (((unsigned)skb->data) &
> (UCC_GETH_RX_DATA_BUF_ALIGNMENT -
> +					      1)));
> +
> +	skb->dev = ugeth->dev;
> +
> +	BD_BUFFER_SET(bd,
> +		      dma_map_single(NULL,
> +				     skb->data,
> +
> ugeth->ug_info->uf_info.max_rx_buf_length +
> +				     UCC_GETH_RX_DATA_BUF_ALIGNMENT,
> +				     DMA_FROM_DEVICE));
> +
> +	BD_STATUS_AND_LENGTH_SET(bd,
> +				 (R_E | R_I |
> +				  (BD_STATUS_AND_LENGTH(bd) & R_W)));
> +
> +	return skb;
> +}
> +
> +static int rx_bd_buffer_set(ucc_geth_private_t *ugeth, u8 rxQ)
> +{
> +	u8 *bd;
> +	u32 bd_status;
> +	struct sk_buff *skb;
> +	int i;
> +
> +	bd = ugeth->p_rx_bd_ring[rxQ];
> +	i = 0;
> +
> +	do {
> +		bd_status = BD_STATUS_AND_LENGTH(bd);
> +		skb = get_new_skb(ugeth, bd);
> +
> +		if (!skb)	/* If can not allocate data buffer,
> +				abort. Cleanup will be elsewhere */
> +			return -ENOMEM;
> +
> +		ugeth->rx_skbuff[rxQ][i] = skb;
> +
> +		/* advance the BD pointer */
> +		bd += UCC_GETH_SIZE_OF_BD;
> +		i++;
> +	} while (!(bd_status & R_W));
> +
> +	return 0;
> +}
> +
> +static int fill_init_enet_entries(ucc_geth_private_t *ugeth,
> +				  volatile u32 *p_start,
> +				  u8 num_entries,
> +				  u32 thread_size,
> +				  u32 thread_alignment,
> +				  qe_risc_allocation_e risc,
> +				  int skip_page_for_first_entry)
> +{
> +	u32 init_enet_offset;
> +	u8 i;
> +	int snum;
> +
> +	for (i = 0; i < num_entries; i++) {
> +		if ((snum = qe_get_snum()) < 0) {
> +			ugeth_err("fill_init_enet_entries: Can not get
> SNUM.");
> +			return snum;
> +		}
> +		if ((i == 0) && skip_page_for_first_entry)
> +		/* First entry of Rx does not have page */
> +			init_enet_offset = 0;
> +		else {
> +			init_enet_offset =
> +			    qe_muram_alloc(thread_size,
> thread_alignment);
> +			if (IS_MURAM_ERR(init_enet_offset)) {
> +				ugeth_err
> +		("fill_init_enet_entries: Can not allocate DPRAM
> memory.");
> +				qe_put_snum((u8) snum);
> +				return -ENOMEM;
> +			}
> +		}
> +		*(p_start++) =
> +		    ((u8) snum << ENET_INIT_PARAM_SNUM_SHIFT) |
> init_enet_offset
> +		    | risc;
> +	}
> +
> +	return 0;
> +}
> +
> +static int return_init_enet_entries(ucc_geth_private_t *ugeth,
> +				    volatile u32 *p_start,
> +				    u8 num_entries,
> +				    qe_risc_allocation_e risc,
> +				    int skip_page_for_first_entry)
> +{
> +	u32 init_enet_offset;
> +	u8 i;
> +	int snum;
> +
> +	for (i = 0; i < num_entries; i++) {
> +		/* Check that this entry was actually valid --
> +		needed in case failed in allocations */
> +		if ((*p_start & ENET_INIT_PARAM_RISC_MASK) == risc) {
> +			snum =
> +			    (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK)
>>>
> +			    ENET_INIT_PARAM_SNUM_SHIFT;
> +			qe_put_snum((u8) snum);
> +			if (!((i == 0) && skip_page_for_first_entry)) {	
> +			/* First entry of Rx does not have page */
> +				init_enet_offset =
> +				    (in_be32(p_start) &
> +				     ENET_INIT_PARAM_PTR_MASK);
> +				qe_muram_free(init_enet_offset);
> +			}
> +			*(p_start++) = 0;	/* Just for cosmetics */
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +#ifdef DEBUG
> +static int dump_init_enet_entries(ucc_geth_private_t *ugeth,
> +				  volatile u32 *p_start,
> +				  u8 num_entries,
> +				  u32 thread_size,
> +				  qe_risc_allocation_e risc,
> +				  int skip_page_for_first_entry)
> +{
> +	u32 init_enet_offset;
> +	u8 i;
> +	int snum;
> +
> +	for (i = 0; i < num_entries; i++) {
> +		/* Check that this entry was actually valid --
> +		needed in case failed in allocations */
> +		if ((*p_start & ENET_INIT_PARAM_RISC_MASK) == risc) {
> +			snum =
> +			    (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK)
>>>
> +			    ENET_INIT_PARAM_SNUM_SHIFT;
> +			qe_put_snum((u8) snum);
> +			if (!((i == 0) && skip_page_for_first_entry)) {	
> +			/* First entry of Rx does not have page */
> +				init_enet_offset =
> +				    (in_be32(p_start) &
> +				     ENET_INIT_PARAM_PTR_MASK);
> +				ugeth_info("Init enet entry %d:", i);
> +				ugeth_info("Base address: 0x%08x",
> +					   (u32)
> +
> qe_muram_addr(init_enet_offset));
> +
> mem_disp(qe_muram_addr(init_enet_offset),
> +					 thread_size);
> +			}
> +			p_start++;
> +		}
> +	}
> +
> +	return 0;
> +}
> +#endif
> +
> +#ifdef CONFIG_UGETH_FILTERING
> +static enet_addr_container_t *get_enet_addr_container(void)
> +{
> +	enet_addr_container_t *enet_addr_cont;
> +
> +	/* allocate memory */
> +	enet_addr_cont = kmalloc(sizeof(enet_addr_container_t),
> GFP_KERNEL);
> +	if (!enet_addr_cont) {
> +		ugeth_err("%s: No memory for enet_addr_container_t
> object.",
> +			  __FUNCTION__);
> +		return NULL;
> +	}
> +
> +	return enet_addr_cont;
> +}
> +#endif /* CONFIG_UGETH_FILTERING */
> +
> +static void put_enet_addr_container(enet_addr_container_t
> *enet_addr_cont)
> +{
> +	kfree(enet_addr_cont);
> +}
> +
> +#ifdef CONFIG_UGETH_FILTERING
> +static int hw_add_addr_in_paddr(ucc_geth_private_t *ugeth,
> +				enet_addr_t *p_enet_addr, u8 paddr_num)
> +{
> +	ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
> +
> +	if (!(paddr_num < NUM_OF_PADDRS)) {
> +		ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__);
> +		return -EINVAL;
> +	}
> +
> +	p_82xx_addr_filt =
> +	    (ucc_geth_82xx_address_filtering_pram_t *)
> ugeth->p_rx_glbl_pram->
> +	    addressfiltering;
> +
> +	/* Ethernet frames are defined in Little Endian mode,    */
> +	/* therefore to insert the address we reverse the bytes. */
> +	out_be16(&p_82xx_addr_filt->paddr[paddr_num].h,
> +		 (u16) (((u16) (((u16) ((*p_enet_addr)[5])) << 8)) |
> +			(u16) (*p_enet_addr)[4]));
> +	out_be16(&p_82xx_addr_filt->paddr[paddr_num].m,
> +		 (u16) (((u16) (((u16) ((*p_enet_addr)[3])) << 8)) |
> +			(u16) (*p_enet_addr)[2]));
> +	out_be16(&p_82xx_addr_filt->paddr[paddr_num].l,
> +		 (u16) (((u16) (((u16) ((*p_enet_addr)[1])) << 8)) |
> +			(u16) (*p_enet_addr)[0]));
> +
> +	return 0;
> +}
> +#endif /* CONFIG_UGETH_FILTERING */
> +
> +static int hw_clear_addr_in_paddr(ucc_geth_private_t *ugeth, u8
> paddr_num)
> +{
> +	ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
> +
> +	if (!(paddr_num < NUM_OF_PADDRS)) {
> +		ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__);
> +		return -EINVAL;
> +	}
> +
> +	p_82xx_addr_filt =
> +	    (ucc_geth_82xx_address_filtering_pram_t *)
> ugeth->p_rx_glbl_pram->
> +	    addressfiltering;
> +
> +	/* Writing address ff.ff.ff.ff.ff.ff disables address
> +	recognition for this register */
> +	out_be16(&p_82xx_addr_filt->paddr[paddr_num].h, 0xffff);
> +	out_be16(&p_82xx_addr_filt->paddr[paddr_num].m, 0xffff);
> +	out_be16(&p_82xx_addr_filt->paddr[paddr_num].l, 0xffff);
> +
> +	return 0;
> +}
> +
> +static void hw_add_addr_in_hash(ucc_geth_private_t *ugeth,
> +				enet_addr_t *p_enet_addr)
> +{
> +	ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
> +	u32 cecr_subblock;
> +
> +	p_82xx_addr_filt =
> +	    (ucc_geth_82xx_address_filtering_pram_t *)
> ugeth->p_rx_glbl_pram->
> +	    addressfiltering;
> +
> +	cecr_subblock =
> +
> ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
> +
> +	/* Ethernet frames are defined in Little Endian mode,
> +	therefor to insert */
> +	/* the address to the hash (Big Endian mode), we reverse the
> bytes.*/
> +	out_be16(&p_82xx_addr_filt->taddr.h,
> +		 (u16) (((u16) (((u16) ((*p_enet_addr)[5])) << 8)) |
> +			(u16) (*p_enet_addr)[4]));
> +	out_be16(&p_82xx_addr_filt->taddr.m,
> +		 (u16) (((u16) (((u16) ((*p_enet_addr)[3])) << 8)) |
> +			(u16) (*p_enet_addr)[2]));
> +	out_be16(&p_82xx_addr_filt->taddr.l,
> +		 (u16) (((u16) (((u16) ((*p_enet_addr)[1])) << 8)) |
> +			(u16) (*p_enet_addr)[0]));
> +
> +	qe_issue_cmd(QE_SET_GROUP_ADDRESS, cecr_subblock,
> +		     (u8) QE_CR_PROTOCOL_ETHERNET, 0);
> +}
> +
> +#ifdef CONFIG_UGETH_MAGIC_PACKET
> +static void magic_packet_detection_enable(ucc_geth_private_t *ugeth)
> +{
> +	ucc_fast_private_t *uccf;
> +	ucc_geth_t *ug_regs;
> +	u32 maccfg2, uccm;
> +
> +	uccf = ugeth->uccf;
> +	ug_regs = ugeth->ug_regs;
> +
> +	/* Enable interrupts for magic packet detection */
> +	uccm = in_be32(uccf->p_uccm);
> +	uccm |= UCCE_MPD;
> +	out_be32(uccf->p_uccm, uccm);
> +
> +	/* Enable magic packet detection */
> +	maccfg2 = in_be32(&ug_regs->maccfg2);
> +	maccfg2 |= MACCFG2_MPE;
> +	out_be32(&ug_regs->maccfg2, maccfg2);
> +}
> +
> +static void magic_packet_detection_disable(ucc_geth_private_t *ugeth)
> +{
> +	ucc_fast_private_t *uccf;
> +	ucc_geth_t *ug_regs;
> +	u32 maccfg2, uccm;
> +
> +	uccf = ugeth->uccf;
> +	ug_regs = ugeth->ug_regs;
> +
> +	/* Disable interrupts for magic packet detection */
> +	uccm = in_be32(uccf->p_uccm);
> +	uccm &= ~UCCE_MPD;
> +	out_be32(uccf->p_uccm, uccm);
> +
> +	/* Disable magic packet detection */
> +	maccfg2 = in_be32(&ug_regs->maccfg2);
> +	maccfg2 &= ~MACCFG2_MPE;
> +	out_be32(&ug_regs->maccfg2, maccfg2);
> +}
> +#endif /* MAGIC_PACKET */
> +
> +static inline int compare_addr(enet_addr_t *addr1, enet_addr_t  
> *addr2)
> +{
> +	return memcmp(addr1, addr2, ENET_NUM_OCTETS_PER_ADDRESS);
> +}
> +
> +#ifdef DEBUG
> +static void get_statistics(ucc_geth_private_t *ugeth,
> +			   ucc_geth_tx_firmware_statistics_t *
> +			   tx_firmware_statistics,
> +			   ucc_geth_rx_firmware_statistics_t *
> +			   rx_firmware_statistics,
> +			   ucc_geth_hardware_statistics_t
> *hardware_statistics)
> +{
> +	ucc_fast_t *uf_regs;
> +	ucc_geth_t *ug_regs;
> +	ucc_geth_tx_firmware_statistics_pram_t *p_tx_fw_statistics_pram;
> +	ucc_geth_rx_firmware_statistics_pram_t *p_rx_fw_statistics_pram;
> +
> +	ug_regs = ugeth->ug_regs;
> +	uf_regs = (ucc_fast_t *) ug_regs;
> +	p_tx_fw_statistics_pram = ugeth->p_tx_fw_statistics_pram;
> +	p_rx_fw_statistics_pram = ugeth->p_rx_fw_statistics_pram;
> +
> +	/* Tx firmware only if user handed pointer and driver actually
> +	gathers Tx firmware statistics */
> +	if (tx_firmware_statistics && p_tx_fw_statistics_pram) {
> +		tx_firmware_statistics->sicoltx =
> +		    in_be32(&p_tx_fw_statistics_pram->sicoltx);
> +		tx_firmware_statistics->mulcoltx =
> +		    in_be32(&p_tx_fw_statistics_pram->mulcoltx);
> +		tx_firmware_statistics->latecoltxfr =
> +		    in_be32(&p_tx_fw_statistics_pram->latecoltxfr);
> +		tx_firmware_statistics->frabortduecol =
> +		    in_be32(&p_tx_fw_statistics_pram->frabortduecol);
> +		tx_firmware_statistics->frlostinmactxer =
> +		    in_be32(&p_tx_fw_statistics_pram->frlostinmactxer);
> +		tx_firmware_statistics->carriersenseertx =
> +		    in_be32(&p_tx_fw_statistics_pram->carriersenseertx);
> +		tx_firmware_statistics->frtxok =
> +		    in_be32(&p_tx_fw_statistics_pram->frtxok);
> +		tx_firmware_statistics->txfrexcessivedefer =
> +
> in_be32(&p_tx_fw_statistics_pram->txfrexcessivedefer);
> +		tx_firmware_statistics->txpkts256 =
> +		    in_be32(&p_tx_fw_statistics_pram->txpkts256);
> +		tx_firmware_statistics->txpkts512 =
> +		    in_be32(&p_tx_fw_statistics_pram->txpkts512);
> +		tx_firmware_statistics->txpkts1024 =
> +		    in_be32(&p_tx_fw_statistics_pram->txpkts1024);
> +		tx_firmware_statistics->txpktsjumbo =
> +		    in_be32(&p_tx_fw_statistics_pram->txpktsjumbo);
> +	}
> +
> +	/* Rx firmware only if user handed pointer and driver actually
> +	 * gathers Rx firmware statistics */
> +	if (rx_firmware_statistics && p_rx_fw_statistics_pram) {
> +		int i;
> +		rx_firmware_statistics->frrxfcser =
> +		    in_be32(&p_rx_fw_statistics_pram->frrxfcser);
> +		rx_firmware_statistics->fraligner =
> +		    in_be32(&p_rx_fw_statistics_pram->fraligner);
> +		rx_firmware_statistics->inrangelenrxer =
> +		    in_be32(&p_rx_fw_statistics_pram->inrangelenrxer);
> +		rx_firmware_statistics->outrangelenrxer =
> +		    in_be32(&p_rx_fw_statistics_pram->outrangelenrxer);
> +		rx_firmware_statistics->frtoolong =
> +		    in_be32(&p_rx_fw_statistics_pram->frtoolong);
> +		rx_firmware_statistics->runt =
> +		    in_be32(&p_rx_fw_statistics_pram->runt);
> +		rx_firmware_statistics->verylongevent =
> +		    in_be32(&p_rx_fw_statistics_pram->verylongevent);
> +		rx_firmware_statistics->symbolerror =
> +		    in_be32(&p_rx_fw_statistics_pram->symbolerror);
> +		rx_firmware_statistics->dropbsy =
> +		    in_be32(&p_rx_fw_statistics_pram->dropbsy);
> +		for (i = 0; i < 0x8; i++)
> +			rx_firmware_statistics->res0[i] =
> +			    p_rx_fw_statistics_pram->res0[i];
> +		rx_firmware_statistics->mismatchdrop =
> +		    in_be32(&p_rx_fw_statistics_pram->mismatchdrop);
> +		rx_firmware_statistics->underpkts =
> +		    in_be32(&p_rx_fw_statistics_pram->underpkts);
> +		rx_firmware_statistics->pkts256 =
> +		    in_be32(&p_rx_fw_statistics_pram->pkts256);
> +		rx_firmware_statistics->pkts512 =
> +		    in_be32(&p_rx_fw_statistics_pram->pkts512);
> +		rx_firmware_statistics->pkts1024 =
> +		    in_be32(&p_rx_fw_statistics_pram->pkts1024);
> +		rx_firmware_statistics->pktsjumbo =
> +		    in_be32(&p_rx_fw_statistics_pram->pktsjumbo);
> +		rx_firmware_statistics->frlossinmacer =
> +		    in_be32(&p_rx_fw_statistics_pram->frlossinmacer);
> +		rx_firmware_statistics->pausefr =
> +		    in_be32(&p_rx_fw_statistics_pram->pausefr);
> +		for (i = 0; i < 0x4; i++)
> +			rx_firmware_statistics->res1[i] =
> +			    p_rx_fw_statistics_pram->res1[i];
> +		rx_firmware_statistics->removevlan =
> +		    in_be32(&p_rx_fw_statistics_pram->removevlan);
> +		rx_firmware_statistics->replacevlan =
> +		    in_be32(&p_rx_fw_statistics_pram->replacevlan);
> +		rx_firmware_statistics->insertvlan =
> +		    in_be32(&p_rx_fw_statistics_pram->insertvlan);
> +	}
> +
> +	/* Hardware only if user handed pointer and driver actually
> +	gathers hardware statistics */
> +	if (hardware_statistics && (in_be32(&uf_regs->upsmr) &
> UPSMR_HSE)) {
> +		hardware_statistics->tx64 = in_be32(&ug_regs->tx64);
> +		hardware_statistics->tx127 = in_be32(&ug_regs->tx127);
> +		hardware_statistics->tx255 = in_be32(&ug_regs->tx255);
> +		hardware_statistics->rx64 = in_be32(&ug_regs->rx64);
> +		hardware_statistics->rx127 = in_be32(&ug_regs->rx127);
> +		hardware_statistics->rx255 = in_be32(&ug_regs->rx255);
> +		hardware_statistics->txok = in_be32(&ug_regs->txok);
> +		hardware_statistics->txcf = in_be16(&ug_regs->txcf);
> +		hardware_statistics->tmca = in_be32(&ug_regs->tmca);
> +		hardware_statistics->tbca = in_be32(&ug_regs->tbca);
> +		hardware_statistics->rxfok = in_be32(&ug_regs->rxfok);
> +		hardware_statistics->rxbok = in_be32(&ug_regs->rxbok);
> +		hardware_statistics->rbyt = in_be32(&ug_regs->rbyt);
> +		hardware_statistics->rmca = in_be32(&ug_regs->rmca);
> +		hardware_statistics->rbca = in_be32(&ug_regs->rbca);
> +	}
> +}
> +
> +static void dump_bds(ucc_geth_private_t *ugeth)
> +{
> +	int i;
> +	int length;
> +
> +	for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) {
> +		if (ugeth->p_tx_bd_ring[i]) {
> +			length =
> +			    (ugeth->ug_info->bdRingLenTx[i] *
> +			     UCC_GETH_SIZE_OF_BD);
> +			ugeth_info("TX BDs[%d]", i);
> +			mem_disp(ugeth->p_tx_bd_ring[i], length);
> +		}
> +	}
> +	for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) {
> +		if (ugeth->p_rx_bd_ring[i]) {
> +			length =
> +			    (ugeth->ug_info->bdRingLenRx[i] *
> +			     UCC_GETH_SIZE_OF_BD);
> +			ugeth_info("RX BDs[%d]", i);
> +			mem_disp(ugeth->p_rx_bd_ring[i], length);
> +		}
> +	}
> +}
> +
> +static void dump_regs(ucc_geth_private_t *ugeth)
> +{
> +	int i;
> +
> +	ugeth_info("UCC%d Geth registers:",
> ugeth->ug_info->uf_info.ucc_num);
> +	ugeth_info("Base address: 0x%08x", (u32) ugeth->ug_regs);
> +
> +	ugeth_info("maccfg1    : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->maccfg1,
> +		   in_be32(&ugeth->ug_regs->maccfg1));
> +	ugeth_info("maccfg2    : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->maccfg2,
> +		   in_be32(&ugeth->ug_regs->maccfg2));
> +	ugeth_info("ipgifg     : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->ipgifg,
> +		   in_be32(&ugeth->ug_regs->ipgifg));
> +	ugeth_info("hafdup     : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->hafdup,
> +		   in_be32(&ugeth->ug_regs->hafdup));
> +	ugeth_info("miimcfg    : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->miimng.miimcfg,
> +		   in_be32(&ugeth->ug_regs->miimng.miimcfg));
> +	ugeth_info("miimcom    : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->miimng.miimcom,
> +		   in_be32(&ugeth->ug_regs->miimng.miimcom));
> +	ugeth_info("miimadd    : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->miimng.miimadd,
> +		   in_be32(&ugeth->ug_regs->miimng.miimadd));
> +	ugeth_info("miimcon    : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->miimng.miimcon,
> +		   in_be32(&ugeth->ug_regs->miimng.miimcon));
> +	ugeth_info("miimstat   : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->miimng.miimstat,
> +		   in_be32(&ugeth->ug_regs->miimng.miimstat));
> +	ugeth_info("miimmind   : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->miimng.miimind,
> +		   in_be32(&ugeth->ug_regs->miimng.miimind));
> +	ugeth_info("ifctl      : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->ifctl,
> +		   in_be32(&ugeth->ug_regs->ifctl));
> +	ugeth_info("ifstat     : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->ifstat,
> +		   in_be32(&ugeth->ug_regs->ifstat));
> +	ugeth_info("macstnaddr1: addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->macstnaddr1,
> +		   in_be32(&ugeth->ug_regs->macstnaddr1));
> +	ugeth_info("macstnaddr2: addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->macstnaddr2,
> +		   in_be32(&ugeth->ug_regs->macstnaddr2));
> +	ugeth_info("uempr      : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->uempr,
> +		   in_be32(&ugeth->ug_regs->uempr));
> +	ugeth_info("utbipar    : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->utbipar,
> +		   in_be32(&ugeth->ug_regs->utbipar));
> +	ugeth_info("uescr      : addr - 0x%08x, val - 0x%04x",
> +		   (u32) & ugeth->ug_regs->uescr,
> +		   in_be16(&ugeth->ug_regs->uescr));
> +	ugeth_info("tx64       : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->tx64,
> +		   in_be32(&ugeth->ug_regs->tx64));
> +	ugeth_info("tx127      : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->tx127,
> +		   in_be32(&ugeth->ug_regs->tx127));
> +	ugeth_info("tx255      : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->tx255,
> +		   in_be32(&ugeth->ug_regs->tx255));
> +	ugeth_info("rx64       : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->rx64,
> +		   in_be32(&ugeth->ug_regs->rx64));
> +	ugeth_info("rx127      : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->rx127,
> +		   in_be32(&ugeth->ug_regs->rx127));
> +	ugeth_info("rx255      : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->rx255,
> +		   in_be32(&ugeth->ug_regs->rx255));
> +	ugeth_info("txok       : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->txok,
> +		   in_be32(&ugeth->ug_regs->txok));
> +	ugeth_info("txcf       : addr - 0x%08x, val - 0x%04x",
> +		   (u32) & ugeth->ug_regs->txcf,
> +		   in_be16(&ugeth->ug_regs->txcf));
> +	ugeth_info("tmca       : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->tmca,
> +		   in_be32(&ugeth->ug_regs->tmca));
> +	ugeth_info("tbca       : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->tbca,
> +		   in_be32(&ugeth->ug_regs->tbca));
> +	ugeth_info("rxfok      : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->rxfok,
> +		   in_be32(&ugeth->ug_regs->rxfok));
> +	ugeth_info("rxbok      : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->rxbok,
> +		   in_be32(&ugeth->ug_regs->rxbok));
> +	ugeth_info("rbyt       : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->rbyt,
> +		   in_be32(&ugeth->ug_regs->rbyt));
> +	ugeth_info("rmca       : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->rmca,
> +		   in_be32(&ugeth->ug_regs->rmca));
> +	ugeth_info("rbca       : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->rbca,
> +		   in_be32(&ugeth->ug_regs->rbca));
> +	ugeth_info("scar       : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->scar,
> +		   in_be32(&ugeth->ug_regs->scar));
> +	ugeth_info("scam       : addr - 0x%08x, val - 0x%08x",
> +		   (u32) & ugeth->ug_regs->scam,
> +		   in_be32(&ugeth->ug_regs->scam));
> +
> +	if (ugeth->p_thread_data_tx) {
> +		int numThreadsTxNumerical;
> +		switch (ugeth->ug_info->numThreadsTx) {
> +		case UCC_GETH_NUM_OF_THREADS_1:
> +			numThreadsTxNumerical = 1;
> +			break;
> +		case UCC_GETH_NUM_OF_THREADS_2:
> +			numThreadsTxNumerical = 2;
> +			break;
> +		case UCC_GETH_NUM_OF_THREADS_4:
> +			numThreadsTxNumerical = 4;
> +			break;
> +		case UCC_GETH_NUM_OF_THREADS_6:
> +			numThreadsTxNumerical = 6;
> +			break;
> +		case UCC_GETH_NUM_OF_THREADS_8:
> +			numThreadsTxNumerical = 8;
> +			break;
> +		default:
> +			numThreadsTxNumerical = 0;
> +			break;
> +		}
> +
> +		ugeth_info("Thread data TXs:");
> +		ugeth_info("Base address: 0x%08x",
> +			   (u32) ugeth->p_thread_data_tx);
> +		for (i = 0; i < numThreadsTxNumerical; i++) {
> +			ugeth_info("Thread data TX[%d]:", i);
> +			ugeth_info("Base address: 0x%08x",
> +				   (u32) & ugeth->p_thread_data_tx[i]);
> +			mem_disp((u8 *) & ugeth->p_thread_data_tx[i],
> +				 sizeof(ucc_geth_thread_data_tx_t));
> +		}
> +	}
> +	if (ugeth->p_thread_data_rx) {
> +		int numThreadsRxNumerical;
> +		switch (ugeth->ug_info->numThreadsRx) {
> +		case UCC_GETH_NUM_OF_THREADS_1:
> +			numThreadsRxNumerical = 1;
> +			break;
> +		case UCC_GETH_NUM_OF_THREADS_2:
> +			numThreadsRxNumerical = 2;
> +			break;
> +		case UCC_GETH_NUM_OF_THREADS_4:
> +			numThreadsRxNumerical = 4;
> +			break;
> +		case UCC_GETH_NUM_OF_THREADS_6:
> +			numThreadsRxNumerical = 6;
> +			break;
> +		case UCC_GETH_NUM_OF_THREADS_8:
> +			numThreadsRxNumerical = 8;
> +			break;
> +		default:
> +			numThreadsRxNumerical = 0;
> +			break;
> +		}
> +
> +		ugeth_info("Thread data RX:");
> +		ugeth_info("Base address: 0x%08x",
> +			   (u32) ugeth->p_thread_data_rx);
> +		for (i = 0; i < numThreadsRxNumerical; i++) {
> +			ugeth_info("Thread data RX[%d]:", i);
> +			ugeth_info("Base address: 0x%08x",
> +				   (u32) & ugeth->p_thread_data_rx[i]);
> +			mem_disp((u8 *) & ugeth->p_thread_data_rx[i],
> +				 sizeof(ucc_geth_thread_data_rx_t));
> +		}
> +	}
> +	if (ugeth->p_exf_glbl_param) {
> +		ugeth_info("EXF global param:");
> +		ugeth_info("Base address: 0x%08x",
> +			   (u32) ugeth->p_exf_glbl_param);
> +		mem_disp((u8 *) ugeth->p_exf_glbl_param,
> +			 sizeof(*ugeth->p_exf_glbl_param));
> +	}
> +	if (ugeth->p_tx_glbl_pram) {
> +		ugeth_info("TX global param:");
> +		ugeth_info("Base address: 0x%08x", (u32)
> ugeth->p_tx_glbl_pram);
> +		ugeth_info("temoder      : addr - 0x%08x, val - 0x%04x",
> +			   (u32) & ugeth->p_tx_glbl_pram->temoder,
> +			   in_be16(&ugeth->p_tx_glbl_pram->temoder));
> +		ugeth_info("sqptr        : addr - 0x%08x, val - 0x%08x",
> +			   (u32) & ugeth->p_tx_glbl_pram->sqptr,
> +			   in_be32(&ugeth->p_tx_glbl_pram->sqptr));
> +		ugeth_info("schedulerbasepointer: addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) &
> ugeth->p_tx_glbl_pram->schedulerbasepointer,
> +			   in_be32(&ugeth->p_tx_glbl_pram->
> +				   schedulerbasepointer));
> +		ugeth_info("txrmonbaseptr: addr - 0x%08x, val - 0x%08x",
> +			   (u32) & ugeth->p_tx_glbl_pram->txrmonbaseptr,
> +
> in_be32(&ugeth->p_tx_glbl_pram->txrmonbaseptr));
> +		ugeth_info("tstate       : addr - 0x%08x, val - 0x%08x",
> +			   (u32) & ugeth->p_tx_glbl_pram->tstate,
> +			   in_be32(&ugeth->p_tx_glbl_pram->tstate));
> +		ugeth_info("iphoffset[0] : addr - 0x%08x, val - 0x%02x",
> +			   (u32) & ugeth->p_tx_glbl_pram->iphoffset[0],
> +			   ugeth->p_tx_glbl_pram->iphoffset[0]);
> +		ugeth_info("iphoffset[1] : addr - 0x%08x, val - 0x%02x",
> +			   (u32) & ugeth->p_tx_glbl_pram->iphoffset[1],
> +			   ugeth->p_tx_glbl_pram->iphoffset[1]);
> +		ugeth_info("iphoffset[2] : addr - 0x%08x, val - 0x%02x",
> +			   (u32) & ugeth->p_tx_glbl_pram->iphoffset[2],
> +			   ugeth->p_tx_glbl_pram->iphoffset[2]);
> +		ugeth_info("iphoffset[3] : addr - 0x%08x, val - 0x%02x",
> +			   (u32) & ugeth->p_tx_glbl_pram->iphoffset[3],
> +			   ugeth->p_tx_glbl_pram->iphoffset[3]);
> +		ugeth_info("iphoffset[4] : addr - 0x%08x, val - 0x%02x",
> +			   (u32) & ugeth->p_tx_glbl_pram->iphoffset[4],
> +			   ugeth->p_tx_glbl_pram->iphoffset[4]);
> +		ugeth_info("iphoffset[5] : addr - 0x%08x, val - 0x%02x",
> +			   (u32) & ugeth->p_tx_glbl_pram->iphoffset[5],
> +			   ugeth->p_tx_glbl_pram->iphoffset[5]);
> +		ugeth_info("iphoffset[6] : addr - 0x%08x, val - 0x%02x",
> +			   (u32) & ugeth->p_tx_glbl_pram->iphoffset[6],
> +			   ugeth->p_tx_glbl_pram->iphoffset[6]);
> +		ugeth_info("iphoffset[7] : addr - 0x%08x, val - 0x%02x",
> +			   (u32) & ugeth->p_tx_glbl_pram->iphoffset[7],
> +			   ugeth->p_tx_glbl_pram->iphoffset[7]);
> +		ugeth_info("vtagtable[0] : addr - 0x%08x, val - 0x%08x",
> +			   (u32) & ugeth->p_tx_glbl_pram->vtagtable[0],
> +
> in_be32(&ugeth->p_tx_glbl_pram->vtagtable[0]));
> +		ugeth_info("vtagtable[1] : addr - 0x%08x, val - 0x%08x",
> +			   (u32) & ugeth->p_tx_glbl_pram->vtagtable[1],
> +
> in_be32(&ugeth->p_tx_glbl_pram->vtagtable[1]));
> +		ugeth_info("vtagtable[2] : addr - 0x%08x, val - 0x%08x",
> +			   (u32) & ugeth->p_tx_glbl_pram->vtagtable[2],
> +
> in_be32(&ugeth->p_tx_glbl_pram->vtagtable[2]));
> +		ugeth_info("vtagtable[3] : addr - 0x%08x, val - 0x%08x",
> +			   (u32) & ugeth->p_tx_glbl_pram->vtagtable[3],
> +
> in_be32(&ugeth->p_tx_glbl_pram->vtagtable[3]));
> +		ugeth_info("vtagtable[4] : addr - 0x%08x, val - 0x%08x",
> +			   (u32) & ugeth->p_tx_glbl_pram->vtagtable[4],
> +
> in_be32(&ugeth->p_tx_glbl_pram->vtagtable[4]));
> +		ugeth_info("vtagtable[5] : addr - 0x%08x, val - 0x%08x",
> +			   (u32) & ugeth->p_tx_glbl_pram->vtagtable[5],
> +
> in_be32(&ugeth->p_tx_glbl_pram->vtagtable[5]));
> +		ugeth_info("vtagtable[6] : addr - 0x%08x, val - 0x%08x",
> +			   (u32) & ugeth->p_tx_glbl_pram->vtagtable[6],
> +
> in_be32(&ugeth->p_tx_glbl_pram->vtagtable[6]));
> +		ugeth_info("vtagtable[7] : addr - 0x%08x, val - 0x%08x",
> +			   (u32) & ugeth->p_tx_glbl_pram->vtagtable[7],
> +
> in_be32(&ugeth->p_tx_glbl_pram->vtagtable[7]));
> +		ugeth_info("tqptr        : addr - 0x%08x, val - 0x%08x",
> +			   (u32) & ugeth->p_tx_glbl_pram->tqptr,
> +			   in_be32(&ugeth->p_tx_glbl_pram->tqptr));
> +	}
> +	if (ugeth->p_rx_glbl_pram) {
> +		ugeth_info("RX global param:");
> +		ugeth_info("Base address: 0x%08x", (u32)
> ugeth->p_rx_glbl_pram);
> +		ugeth_info("remoder         : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) & ugeth->p_rx_glbl_pram->remoder,
> +			   in_be32(&ugeth->p_rx_glbl_pram->remoder));
> +		ugeth_info("rqptr           : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) & ugeth->p_rx_glbl_pram->rqptr,
> +			   in_be32(&ugeth->p_rx_glbl_pram->rqptr));
> +		ugeth_info("typeorlen       : addr - 0x%08x, val -
> 0x%04x",
> +			   (u32) & ugeth->p_rx_glbl_pram->typeorlen,
> +			   in_be16(&ugeth->p_rx_glbl_pram->typeorlen));
> +		ugeth_info("rxgstpack       : addr - 0x%08x, val -
> 0x%02x",
> +			   (u32) & ugeth->p_rx_glbl_pram->rxgstpack,
> +			   ugeth->p_rx_glbl_pram->rxgstpack);
> +		ugeth_info("rxrmonbaseptr   : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) & ugeth->p_rx_glbl_pram->rxrmonbaseptr,
> +
> in_be32(&ugeth->p_rx_glbl_pram->rxrmonbaseptr));
> +		ugeth_info("intcoalescingptr: addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) &
> ugeth->p_rx_glbl_pram->intcoalescingptr,
> +
> in_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr));
> +		ugeth_info("rstate          : addr - 0x%08x, val -
> 0x%02x",
> +			   (u32) & ugeth->p_rx_glbl_pram->rstate,
> +			   ugeth->p_rx_glbl_pram->rstate);
> +		ugeth_info("mrblr           : addr - 0x%08x, val -
> 0x%04x",
> +			   (u32) & ugeth->p_rx_glbl_pram->mrblr,
> +			   in_be16(&ugeth->p_rx_glbl_pram->mrblr));
> +		ugeth_info("rbdqptr         : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) & ugeth->p_rx_glbl_pram->rbdqptr,
> +			   in_be32(&ugeth->p_rx_glbl_pram->rbdqptr));
> +		ugeth_info("mflr            : addr - 0x%08x, val -
> 0x%04x",
> +			   (u32) & ugeth->p_rx_glbl_pram->mflr,
> +			   in_be16(&ugeth->p_rx_glbl_pram->mflr));
> +		ugeth_info("minflr          : addr - 0x%08x, val -
> 0x%04x",
> +			   (u32) & ugeth->p_rx_glbl_pram->minflr,
> +			   in_be16(&ugeth->p_rx_glbl_pram->minflr));
> +		ugeth_info("maxd1           : addr - 0x%08x, val -
> 0x%04x",
> +			   (u32) & ugeth->p_rx_glbl_pram->maxd1,
> +			   in_be16(&ugeth->p_rx_glbl_pram->maxd1));
> +		ugeth_info("maxd2           : addr - 0x%08x, val -
> 0x%04x",
> +			   (u32) & ugeth->p_rx_glbl_pram->maxd2,
> +			   in_be16(&ugeth->p_rx_glbl_pram->maxd2));
> +		ugeth_info("ecamptr         : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) & ugeth->p_rx_glbl_pram->ecamptr,
> +			   in_be32(&ugeth->p_rx_glbl_pram->ecamptr));
> +		ugeth_info("l2qt            : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) & ugeth->p_rx_glbl_pram->l2qt,
> +			   in_be32(&ugeth->p_rx_glbl_pram->l2qt));
> +		ugeth_info("l3qt[0]         : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) & ugeth->p_rx_glbl_pram->l3qt[0],
> +			   in_be32(&ugeth->p_rx_glbl_pram->l3qt[0]));
> +		ugeth_info("l3qt[1]         : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) & ugeth->p_rx_glbl_pram->l3qt[1],
> +			   in_be32(&ugeth->p_rx_glbl_pram->l3qt[1]));
> +		ugeth_info("l3qt[2]         : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) & ugeth->p_rx_glbl_pram->l3qt[2],
> +			   in_be32(&ugeth->p_rx_glbl_pram->l3qt[2]));
> +		ugeth_info("l3qt[3]         : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) & ugeth->p_rx_glbl_pram->l3qt[3],
> +			   in_be32(&ugeth->p_rx_glbl_pram->l3qt[3]));
> +		ugeth_info("l3qt[4]         : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) & ugeth->p_rx_glbl_pram->l3qt[4],
> +			   in_be32(&ugeth->p_rx_glbl_pram->l3qt[4]));
> +		ugeth_info("l3qt[5]         : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) & ugeth->p_rx_glbl_pram->l3qt[5],
> +			   in_be32(&ugeth->p_rx_glbl_pram->l3qt[5]));
> +		ugeth_info("l3qt[6]         : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) & ugeth->p_rx_glbl_pram->l3qt[6],
> +			   in_be32(&ugeth->p_rx_glbl_pram->l3qt[6]));
> +		ugeth_info("l3qt[7]         : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) & ugeth->p_rx_glbl_pram->l3qt[7],
> +			   in_be32(&ugeth->p_rx_glbl_pram->l3qt[7]));
> +		ugeth_info("vlantype        : addr - 0x%08x, val -
> 0x%04x",
> +			   (u32) & ugeth->p_rx_glbl_pram->vlantype,
> +			   in_be16(&ugeth->p_rx_glbl_pram->vlantype));
> +		ugeth_info("vlantci         : addr - 0x%08x, val -
> 0x%04x",
> +			   (u32) & ugeth->p_rx_glbl_pram->vlantci,
> +			   in_be16(&ugeth->p_rx_glbl_pram->vlantci));
> +		for (i = 0; i < 64; i++)
> +			ugeth_info
> +		    ("addressfiltering[%d]: addr - 0x%08x, val -
> 0x%02x",
> +			     i,
> +			     (u32) &
> ugeth->p_rx_glbl_pram->addressfiltering[i],
> +
> ugeth->p_rx_glbl_pram->addressfiltering[i]);
> +		ugeth_info("exfGlobalParam  : addr - 0x%08x, val -
> 0x%08x",
> +			   (u32) &
> ugeth->p_rx_glbl_pram->exfGlobalParam,
> +
> in_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam));
> +	}
> +	if (ugeth->p_send_q_mem_reg) {
> +		ugeth_info("Send Q memory registers:");
> +		ugeth_info("Base address: 0x%08x",
> +			   (u32) ugeth->p_send_q_mem_reg);
> +		for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) {
> +			ugeth_info("SQQD[%d]:", i);
> +			ugeth_info("Base address: 0x%08x",
> +				   (u32) &
> ugeth->p_send_q_mem_reg->sqqd[i]);
> +			mem_disp((u8 *) &
> ugeth->p_send_q_mem_reg->sqqd[i],
> +				 sizeof(ucc_geth_send_queue_qd_t));
> +		}
> +	}
> +	if (ugeth->p_scheduler) {
> +		ugeth_info("Scheduler:");
> +		ugeth_info("Base address: 0x%08x", (u32)
> ugeth->p_scheduler);
> +		mem_disp((u8 *) ugeth->p_scheduler,
> +			 sizeof(*ugeth->p_scheduler));
> +	}
> +	if (ugeth->p_tx_fw_statistics_pram) {
> +		ugeth_info("TX FW statistics pram:");
> +		ugeth_info("Base address: 0x%08x",
> +			   (u32) ugeth->p_tx_fw_statistics_pram);
> +		mem_disp((u8 *) ugeth->p_tx_fw_statistics_pram,
> +			 sizeof(*ugeth->p_tx_fw_statistics_pram));
> +	}
> +	if (ugeth->p_rx_fw_statistics_pram) {
> +		ugeth_info("RX FW statistics pram:");
> +		ugeth_info("Base address: 0x%08x",
> +			   (u32) ugeth->p_rx_fw_statistics_pram);
> +		mem_disp((u8 *) ugeth->p_rx_fw_statistics_pram,
> +			 sizeof(*ugeth->p_rx_fw_statistics_pram));
> +	}
> +	if (ugeth->p_rx_irq_coalescing_tbl) {
> +		ugeth_info("RX IRQ coalescing tables:");
> +		ugeth_info("Base address: 0x%08x",
> +			   (u32) ugeth->p_rx_irq_coalescing_tbl);
> +		for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) {
> +			ugeth_info("RX IRQ coalescing table entry[%d]:",
> i);
> +			ugeth_info("Base address: 0x%08x",
> +				   (u32) &
> ugeth->p_rx_irq_coalescing_tbl->
> +				   coalescingentry[i]);
> +			ugeth_info
> +		("interruptcoalescingmaxvalue: addr - 0x%08x, val -
> 0x%08x",
> +			     (u32) & ugeth->p_rx_irq_coalescing_tbl->
> +
> coalescingentry[i].interruptcoalescingmaxvalue,
> +			     in_be32(&ugeth->p_rx_irq_coalescing_tbl->
> +				     coalescingentry[i].
> +				     interruptcoalescingmaxvalue));
> +			ugeth_info
> +		("interruptcoalescingcounter : addr - 0x%08x, val -
> 0x%08x",
> +			     (u32) & ugeth->p_rx_irq_coalescing_tbl->
> +
> coalescingentry[i].interruptcoalescingcounter,
> +			     in_be32(&ugeth->p_rx_irq_coalescing_tbl->
> +				     coalescingentry[i].
> +				     interruptcoalescingcounter));
> +		}
> +	}
> +	if (ugeth->p_rx_bd_qs_tbl) {
> +		ugeth_info("RX BD QS tables:");
> +		ugeth_info("Base address: 0x%08x", (u32)
> ugeth->p_rx_bd_qs_tbl);
> +		for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) {
> +			ugeth_info("RX BD QS table[%d]:", i);
> +			ugeth_info("Base address: 0x%08x",
> +				   (u32) & ugeth->p_rx_bd_qs_tbl[i]);
> +			ugeth_info
> +			    ("bdbaseptr        : addr - 0x%08x, val -
> 0x%08x",
> +			     (u32) & ugeth->p_rx_bd_qs_tbl[i].bdbaseptr,
> +
> in_be32(&ugeth->p_rx_bd_qs_tbl[i].bdbaseptr));
> +			ugeth_info
> +			    ("bdptr            : addr - 0x%08x, val -
> 0x%08x",
> +			     (u32) & ugeth->p_rx_bd_qs_tbl[i].bdptr,
> +			     in_be32(&ugeth->p_rx_bd_qs_tbl[i].bdptr));
> +			ugeth_info
> +			    ("externalbdbaseptr: addr - 0x%08x, val -
> 0x%08x",
> +			     (u32) &
> ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr,
> +			     in_be32(&ugeth->p_rx_bd_qs_tbl[i].
> +				     externalbdbaseptr));
> +			ugeth_info
> +			    ("externalbdptr    : addr - 0x%08x, val -
> 0x%08x",
> +			     (u32) &
> ugeth->p_rx_bd_qs_tbl[i].externalbdptr,
> +
> in_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdptr));
> +			ugeth_info("ucode RX Prefetched BDs:");
> +			ugeth_info("Base address: 0x%08x",
> +				   (u32)
> +				   qe_muram_addr(in_be32
> +
> (&ugeth->p_rx_bd_qs_tbl[i].
> +						  bdbaseptr)));
> +			mem_disp((u8 *)
> +				 qe_muram_addr(in_be32
> +
> (&ugeth->p_rx_bd_qs_tbl[i].
> +						bdbaseptr)),
> +				 sizeof(ucc_geth_rx_prefetched_bds_t));
> +		}
> +	}
> +	if (ugeth->p_init_enet_param_shadow) {
> +		int size;
> +		ugeth_info("Init enet param shadow:");
> +		ugeth_info("Base address: 0x%08x",
> +			   (u32) ugeth->p_init_enet_param_shadow);
> +		mem_disp((u8 *) ugeth->p_init_enet_param_shadow,
> +			 sizeof(*ugeth->p_init_enet_param_shadow));
> +
> +		size = sizeof(ucc_geth_thread_rx_pram_t);
> +		if (ugeth->ug_info->rxExtendedFiltering) {
> +			size +=
> +
> THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING;
> +			if (ugeth->ug_info->largestexternallookupkeysize
> ==
> +			    QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES)
> +				size +=
> +
> THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8;
> +			if (ugeth->ug_info->largestexternallookupkeysize
> ==
> +			    QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES)
> +				size +=
> +
> THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16;
> +		}
> +
> +		dump_init_enet_entries(ugeth,
> +
> &(ugeth->p_init_enet_param_shadow->
> +					 txthread[0]),
> +				       ENET_INIT_PARAM_MAX_ENTRIES_TX,
> +
> sizeof(ucc_geth_thread_tx_pram_t),
> +				       ugeth->ug_info->riscTx, 0);
> +		dump_init_enet_entries(ugeth,
> +
> &(ugeth->p_init_enet_param_shadow->
> +					 rxthread[0]),
> +				       ENET_INIT_PARAM_MAX_ENTRIES_RX,
> size,
> +				       ugeth->ug_info->riscRx, 1);
> +	}
> +}
> +#endif /* DEBUG */
> +
> +static void init_default_reg_vals(volatile u32 *upsmr_register,
> +				  volatile u32 *maccfg1_register,
> +				  volatile u32 *maccfg2_register)
> +{
> +	out_be32(upsmr_register, UCC_GETH_UPSMR_INIT);
> +	out_be32(maccfg1_register, UCC_GETH_MACCFG1_INIT);
> +	out_be32(maccfg2_register, UCC_GETH_MACCFG2_INIT);
> +}
> +
> +static int init_half_duplex_params(int alt_beb,
> +				   int back_pressure_no_backoff,
> +				   int no_backoff,
> +				   int excess_defer,
> +				   u8 alt_beb_truncation,
> +				   u8 max_retransmissions,
> +				   u8 collision_window,
> +				   volatile u32 *hafdup_register)
> +{
> +	u32 value = 0;
> +
> +	if ((alt_beb_truncation > HALFDUP_ALT_BEB_TRUNCATION_MAX) ||
> +	    (max_retransmissions > HALFDUP_MAX_RETRANSMISSION_MAX) ||
> +	    (collision_window > HALFDUP_COLLISION_WINDOW_MAX))
> +		return -EINVAL;
> +
> +	value = (u32) (alt_beb_truncation <<
> HALFDUP_ALT_BEB_TRUNCATION_SHIFT);
> +
> +	if (alt_beb)
> +		value |= HALFDUP_ALT_BEB;
> +	if (back_pressure_no_backoff)
> +		value |= HALFDUP_BACK_PRESSURE_NO_BACKOFF;
> +	if (no_backoff)
> +		value |= HALFDUP_NO_BACKOFF;
> +	if (excess_defer)
> +		value |= HALFDUP_EXCESSIVE_DEFER;
> +
> +	value |= (max_retransmissions <<
> HALFDUP_MAX_RETRANSMISSION_SHIFT);
> +
> +	value |= collision_window;
> +
> +	out_be32(hafdup_register, value);
> +	return 0;
> +}
> +
> +static int init_inter_frame_gap_params(u8 non_btb_cs_ipg,
> +				       u8 non_btb_ipg,
> +				       u8 min_ifg,
> +				       u8 btb_ipg,
> +				       volatile u32 *ipgifg_register)
> +{
> +	u32 value = 0;
> +
> +	/* Non-Back-to-back IPG part 1 should be <= Non-Back-to-back
> +	IPG part 2 */
> +	if (non_btb_cs_ipg > non_btb_ipg)
> +		return -EINVAL;
> +
> +	if ((non_btb_cs_ipg > IPGIFG_NON_BACK_TO_BACK_IFG_PART1_MAX) ||
> +	    (non_btb_ipg > IPGIFG_NON_BACK_TO_BACK_IFG_PART2_MAX) ||
> +	    /*(min_ifg        > IPGIFG_MINIMUM_IFG_ENFORCEMENT_MAX) ||
> */
> +	    (btb_ipg > IPGIFG_BACK_TO_BACK_IFG_MAX))
> +		return -EINVAL;
> +
> +	value |=
> +	    ((non_btb_cs_ipg << IPGIFG_NON_BACK_TO_BACK_IFG_PART1_SHIFT)
> &
> +	     IPGIFG_NBTB_CS_IPG_MASK);
> +	value |=
> +	    ((non_btb_ipg << IPGIFG_NON_BACK_TO_BACK_IFG_PART2_SHIFT) &
> +	     IPGIFG_NBTB_IPG_MASK);
> +	value |=
> +	    ((min_ifg << IPGIFG_MINIMUM_IFG_ENFORCEMENT_SHIFT) &
> +	     IPGIFG_MIN_IFG_MASK);
> +	value |= (btb_ipg & IPGIFG_BTB_IPG_MASK);
> +
> +	out_be32(ipgifg_register, value);
> +	return 0;
> +}
> +
> +static int init_flow_control_params(u32 automatic_flow_control_mode,
> +				    int rx_flow_control_enable,
> +				    int tx_flow_control_enable,
> +				    u16 pause_period,
> +				    u16 extension_field,
> +				    volatile u32 *upsmr_register,
> +				    volatile u32 *uempr_register,
> +				    volatile u32 *maccfg1_register)
> +{
> +	u32 value = 0;
> +
> +	/* Set UEMPR register */
> +	value = (u32) pause_period << UEMPR_PAUSE_TIME_VALUE_SHIFT;
> +	value |= (u32) extension_field <<
> UEMPR_EXTENDED_PAUSE_TIME_VALUE_SHIFT;
> +	out_be32(uempr_register, value);
> +
> +	/* Set UPSMR register */
> +	value = in_be32(upsmr_register);
> +	value |= automatic_flow_control_mode;
> +	out_be32(upsmr_register, value);
> +
> +	value = in_be32(maccfg1_register);
> +	if (rx_flow_control_enable)
> +		value |= MACCFG1_FLOW_RX;
> +	if (tx_flow_control_enable)
> +		value |= MACCFG1_FLOW_TX;
> +	out_be32(maccfg1_register, value);
> +
> +	return 0;
> +}
> +
> +static int init_hw_statistics_gathering_mode(int
> enable_hardware_statistics,
> +					     int
> auto_zero_hardware_statistics,
> +					     volatile u32
> *upsmr_register,
> +					     volatile u16
> *uescr_register)
> +{
> +	u32 upsmr_value = 0;
> +	u16 uescr_value = 0;
> +	/* Enable hardware statistics gathering if requested */
> +	if (enable_hardware_statistics) {
> +		upsmr_value = in_be32(upsmr_register);
> +		upsmr_value |= UPSMR_HSE;
> +		out_be32(upsmr_register, upsmr_value);
> +	}
> +
> +	/* Clear hardware statistics counters */
> +	uescr_value = in_be16(uescr_register);
> +	uescr_value |= UESCR_CLRCNT;
> +	/* Automatically zero hardware statistics counters on read,
> +	if requested */
> +	if (auto_zero_hardware_statistics)
> +		uescr_value |= UESCR_AUTOZ;
> +	out_be16(uescr_register, uescr_value);
> +
> +	return 0;
> +}
> +
> +static int init_firmware_statistics_gathering_mode(int
> +		enable_tx_firmware_statistics,
> +		int enable_rx_firmware_statistics,
> +		volatile u32 *tx_rmon_base_ptr,
> +		u32 tx_firmware_statistics_structure_address,
> +		volatile u32 *rx_rmon_base_ptr,
> +		u32 rx_firmware_statistics_structure_address,
> +		volatile u16 *temoder_register,
> +		volatile u32 *remoder_register)
> +{
> +	/* Note: this function does not check if */
> +	/* the parameters it receives are NULL   */
> +	u16 temoder_value;
> +	u32 remoder_value;
> +
> +	if (enable_tx_firmware_statistics) {
> +		out_be32(tx_rmon_base_ptr,
> +			 tx_firmware_statistics_structure_address);
> +		temoder_value = in_be16(temoder_register);
> +		temoder_value |= TEMODER_TX_RMON_STATISTICS_ENABLE;
> +		out_be16(temoder_register, temoder_value);
> +	}
> +
> +	if (enable_rx_firmware_statistics) {
> +		out_be32(rx_rmon_base_ptr,
> +			 rx_firmware_statistics_structure_address);
> +		remoder_value = in_be32(remoder_register);
> +		remoder_value |= REMODER_RX_RMON_STATISTICS_ENABLE;
> +		out_be32(remoder_register, remoder_value);
> +	}
> +
> +	return 0;
> +}
> +
> +static int init_mac_station_addr_regs(u8 address_byte_0,
> +				      u8 address_byte_1,
> +				      u8 address_byte_2,
> +				      u8 address_byte_3,
> +				      u8 address_byte_4,
> +				      u8 address_byte_5,
> +				      volatile u32
> *macstnaddr1_register,
> +				      volatile u32
> *macstnaddr2_register)
> +{
> +	u32 value = 0;
> +
> +	/* Example: for a station address of 0x12345678ABCD, */
> +	/* 0x12 is byte 0, 0x34 is byte 1 and so on and 0xCD is byte 5
> */
> +
> +	/* MACSTNADDR1 Register: */
> +
> +	/* 0                      7   8                      15  */
> +	/* station address byte 5     station address byte 4     */
> +	/* 16                     23  24                     31  */
> +	/* station address byte 3     station address byte 2     */
> +	value |= (u32) ((address_byte_2 << 0) & 0x000000FF);
> +	value |= (u32) ((address_byte_3 << 8) & 0x0000FF00);
> +	value |= (u32) ((address_byte_4 << 16) & 0x00FF0000);
> +	value |= (u32) ((address_byte_5 << 24) & 0xFF000000);
> +
> +	out_be32(macstnaddr1_register, value);
> +
> +	/* MACSTNADDR2 Register: */
> +
> +	/* 0                      7   8                      15  */
> +	/* station address byte 1     station address byte 0     */
> +	/* 16                     23  24                     31  */
> +	/*         reserved                   reserved           */
> +	value = 0;
> +	value |= (u32) ((address_byte_0 << 16) & 0x00FF0000);
> +	value |= (u32) ((address_byte_1 << 24) & 0xFF000000);
> +
> +	out_be32(macstnaddr2_register, value);
> +
> +	return 0;
> +}
> +
> +static int init_mac_duplex_mode(int full_duplex,
> +				int limited_to_full_duplex,
> +				volatile u32 *maccfg2_register)
> +{
> +	u32 value = 0;
> +
> +	/* some interfaces must work in full duplex mode */
> +	if ((full_duplex == 0) && (limited_to_full_duplex == 1))
> +		return -EINVAL;
> +
> +	value = in_be32(maccfg2_register);
> +
> +	if (full_duplex)
> +		value |= MACCFG2_FDX;
> +	else
> +		value &= ~MACCFG2_FDX;
> +
> +	out_be32(maccfg2_register, value);
> +	return 0;
> +}
> +
> +static int init_check_frame_length_mode(int length_check,
> +					volatile u32 *maccfg2_register)
> +{
> +	u32 value = 0;
> +
> +	value = in_be32(maccfg2_register);
> +
> +	if (length_check)
> +		value |= MACCFG2_LC;
> +	else
> +		value &= ~MACCFG2_LC;
> +
> +	out_be32(maccfg2_register, value);
> +	return 0;
> +}
> +
> +static int init_preamble_length(u8 preamble_length,
> +				volatile u32 *maccfg2_register)
> +{
> +	u32 value = 0;
> +
> +	if ((preamble_length < 3) || (preamble_length > 7))
> +		return -EINVAL;
> +
> +	value = in_be32(maccfg2_register);
> +	value &= ~MACCFG2_PREL_MASK;
> +	value |= (preamble_length << MACCFG2_PREL_SHIFT);
> +	out_be32(maccfg2_register, value);
> +	return 0;
> +}
> +
> +static int init_mii_management_configuration(int reset_mgmt,
> +					     int preamble_supress,
> +					     volatile u32
> *miimcfg_register,
> +					     volatile u32
> *miimind_register)
> +{
> +	unsigned int timeout = PHY_INIT_TIMEOUT;
> +	u32 value = 0;
> +
> +	value = in_be32(miimcfg_register);
> +	if (reset_mgmt) {
> +		value |= MIIMCFG_RESET_MANAGEMENT;
> +		out_be32(miimcfg_register, value);
> +	}
> +
> +	value = 0;
> +
> +	if (preamble_supress)
> +		value |= MIIMCFG_NO_PREAMBLE;
> +
> +	value |= UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT;
> +	out_be32(miimcfg_register, value);
> +
> +	/* Wait until the bus is free */
> +	while ((in_be32(miimind_register) & MIIMIND_BUSY) && timeout--)
> +		cpu_relax();
> +
> +	if (timeout <= 0) {
> +		ugeth_err("%s: The MII Bus is stuck!", __FUNCTION__);
> +		return -ETIMEDOUT;
> +	}
> +
> +	return 0;
> +}
> +
> +static int init_rx_parameters(int reject_broadcast,
> +			      int receive_short_frames,
> +			      int promiscuous, volatile u32
> *upsmr_register)
> +{
> +	u32 value = 0;
> +
> +	value = in_be32(upsmr_register);
> +
> +	if (reject_broadcast)
> +		value |= UPSMR_BRO;
> +	else
> +		value &= ~UPSMR_BRO;
> +
> +	if (receive_short_frames)
> +		value |= UPSMR_RSH;
> +	else
> +		value &= ~UPSMR_RSH;
> +
> +	if (promiscuous)
> +		value |= UPSMR_PRO;
> +	else
> +		value &= ~UPSMR_PRO;
> +
> +	out_be32(upsmr_register, value);
> +
> +	return 0;
> +}
> +
> +static int init_max_rx_buff_len(u16 max_rx_buf_len,
> +				volatile u16 *mrblr_register)
> +{
> +	/* max_rx_buf_len value must be a multiple of 128 */
> +	if ((max_rx_buf_len == 0)
> +	    || (max_rx_buf_len % UCC_GETH_MRBLR_ALIGNMENT))
> +		return -EINVAL;
> +
> +	out_be16(mrblr_register, max_rx_buf_len);
> +	return 0;
> +}
> +
> +static int init_min_frame_len(u16 min_frame_length,
> +			      volatile u16 *minflr_register,
> +			      volatile u16 *mrblr_register)
> +{
> +	u16 mrblr_value = 0;
> +
> +	mrblr_value = in_be16(mrblr_register);
> +	if (min_frame_length >= (mrblr_value - 4))
> +		return -EINVAL;
> +
> +	out_be16(minflr_register, min_frame_length);
> +	return 0;
> +}
> +
> +static int adjust_enet_interface(ucc_geth_private_t *ugeth)
> +{
> +	ucc_geth_info_t *ug_info;
> +	ucc_geth_t *ug_regs;
> +	ucc_fast_t *uf_regs;
> +	enet_speed_e speed;
> +	int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm =
> +	    0, limited_to_full_duplex = 0;
> +	u32 upsmr, maccfg2, utbipar, tbiBaseAddress;
> +	u16 value;
> +
> +	ugeth_vdbg("%s: IN", __FUNCTION__);
> +
> +	ug_info = ugeth->ug_info;
> +	ug_regs = ugeth->ug_regs;
> +	uf_regs = ugeth->uccf->uf_regs;
> +
> +	/* Analyze enet_interface according to Interface Mode
> Configuration
> +	table */
> +	ret_val =
> +	    get_interface_details(ug_info->enet_interface, &speed,
> &r10m, &rmm,
> +				  &rpm, &tbi, &limited_to_full_duplex);
> +	if (ret_val != 0) {
> +		ugeth_err
> +		  ("%s: half duplex not supported in requested
> configuration.",
> +		     __FUNCTION__);
> +		return ret_val;
> +	}
> +
> +	/*                    Set MACCFG2                    */
> +	maccfg2 = in_be32(&ug_regs->maccfg2);
> +	maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK;
> +	if ((speed == ENET_SPEED_10BT) || (speed == ENET_SPEED_100BT))
> +		maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
> +	else if (speed == ENET_SPEED_1000BT)
> +		maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE;
> +	maccfg2 |= ug_info->padAndCrc;
> +	out_be32(&ug_regs->maccfg2, maccfg2);
> +
> +	/*                    Set UPSMR                      */
> +	upsmr = in_be32(&uf_regs->upsmr);
> +	upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM);
> +	if (rpm)
> +		upsmr |= UPSMR_RPM;
> +	if (r10m)
> +		upsmr |= UPSMR_R10M;
> +	if (tbi)
> +		upsmr |= UPSMR_TBIM;
> +	if (rmm)
> +		upsmr |= UPSMR_RMM;
> +	out_be32(&uf_regs->upsmr, upsmr);
> +
> +	/*                    Set UTBIPAR                    */
> +	utbipar = in_be32(&ug_regs->utbipar);
> +	utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK;
> +	if (tbi)
> +		utbipar |=
> +		    (ug_info->phy_address +
> +		     ugeth->ug_info->uf_info.
> +		     ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
> +	else
> +		utbipar |=
> +		    (0x10 +
> +		     ugeth->ug_info->uf_info.
> +		     ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
> +	out_be32(&ug_regs->utbipar, utbipar);
> +
> +	/* Disable autonegotiation in tbi mode, because by default it
> +	comes up in autonegotiation mode. */
> +	/* Note that this depends on proper setting in utbipar register.
> */
> +	if (tbi) {
> +		tbiBaseAddress = in_be32(&ug_regs->utbipar);
> +		tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK;
> +		tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT;
> +		value =
> +		    ugeth->mii_info->mdio_read(ugeth->dev, (u8)
> tbiBaseAddress,
> +					       ENET_TBI_MII_CR);
> +		value &= ~0x1000;	/* Turn off autonegotiation */
> +		ugeth->mii_info->mdio_write(ugeth->dev, (u8)
> tbiBaseAddress,
> +					    ENET_TBI_MII_CR, value);
> +	}
> +
> +	ret_val = init_mac_duplex_mode(1,
> +				       limited_to_full_duplex,
> +				       &ug_regs->maccfg2);
> +	if (ret_val != 0) {
> +		ugeth_err
> +		("%s: half duplex not supported in requested
> configuration.",
> +		     __FUNCTION__);
> +		return ret_val;
> +	}
> +
> +	init_check_frame_length_mode(ug_info->lengthCheckRx,
> &ug_regs->maccfg2);
> +
> +	ret_val = init_preamble_length(ug_info->prel,
> &ug_regs->maccfg2);
> +	if (ret_val != 0) {
> +		ugeth_err
> +		    ("%s: Preamble length must be between 3 and 7
> inclusive.",
> +		     __FUNCTION__);
> +		return ret_val;
> +	}
> +
> +	return 0;
> +}
> +
> +/* Called every time the controller might need to be made
> + * aware of new link state.  The PHY code conveys this
> + * information through variables in the ugeth structure, and this
> + * function converts those variables into the appropriate
> + * register values, and can bring down the device if needed.
> + */
> +static void adjust_link(struct net_device *dev)
> +{
> +	ucc_geth_private_t *ugeth = netdev_priv(dev);
> +	ucc_geth_t *ug_regs;
> +	u32 tempval;
> +	struct ugeth_mii_info *mii_info = ugeth->mii_info;
> +
> +	ug_regs = ugeth->ug_regs;
> +
> +	if (mii_info->link) {
> +		/* Now we make sure that we can be in full duplex mode.
> +		 * If not, we operate in half-duplex mode. */
> +		if (mii_info->duplex != ugeth->oldduplex) {
> +			if (!(mii_info->duplex)) {
> +				tempval = in_be32(&ug_regs->maccfg2);
> +				tempval &= ~(MACCFG2_FDX);
> +				out_be32(&ug_regs->maccfg2, tempval);
> +
> +				ugeth_info("%s: Half Duplex",
> dev->name);
> +			} else {
> +				tempval = in_be32(&ug_regs->maccfg2);
> +				tempval |= MACCFG2_FDX;
> +				out_be32(&ug_regs->maccfg2, tempval);
> +
> +				ugeth_info("%s: Full Duplex",
> dev->name);
> +			}
> +
> +			ugeth->oldduplex = mii_info->duplex;
> +		}
> +
> +		if (mii_info->speed != ugeth->oldspeed) {
> +			switch (mii_info->speed) {
> +			case 1000:
> +#ifdef CONFIG_MPC836x
> +/* FIXME: This code is for 100Mbs BUG fixing,
> +remove this when it is fixed!!! */
> +				if (ugeth->ug_info->enet_interface ==
> +				    ENET_1000_GMII)
> +				/* Run the commands which initialize the
> PHY */
> +				{
> +					tempval =
> +					    (u32)
> mii_info->mdio_read(ugeth->
> +						dev, mii_info->mii_id,
> 0x1b);
> +					tempval |= 0x000f;
> +					mii_info->mdio_write(ugeth->dev,
> +						mii_info->mii_id, 0x1b,
> +						(u16) tempval);
> +					tempval =
> +					    (u32)
> mii_info->mdio_read(ugeth->
> +						dev, mii_info->mii_id,
> +						MII_BMCR);
> +					mii_info->mdio_write(ugeth->dev,
> +						mii_info->mii_id,
> MII_BMCR,
> +						(u16) (tempval |
> BMCR_RESET));
> +				} else if
> (ugeth->ug_info->enet_interface ==
> +					   ENET_1000_RGMII)
> +				/* Run the commands which initialize the
> PHY */
> +				{
> +					tempval =
> +					    (u32)
> mii_info->mdio_read(ugeth->
> +						dev, mii_info->mii_id,
> 0x1b);
> +					tempval = (tempval & ~0x000f) |
> 0x000b;
> +					mii_info->mdio_write(ugeth->dev,
> +						mii_info->mii_id, 0x1b,
> +						(u16) tempval);
> +					tempval =
> +					    (u32)
> mii_info->mdio_read(ugeth->
> +						dev, mii_info->mii_id,
> +						MII_BMCR);
> +					mii_info->mdio_write(ugeth->dev,
> +						mii_info->mii_id,
> MII_BMCR,
> +						(u16) (tempval |
> BMCR_RESET));
> +				}
> +				msleep(4000);
> +#endif				/* CONFIG_MPC8360 */
> +				adjust_enet_interface(ugeth);
> +				break;
> +			case 100:
> +			case 10:
> +#ifdef CONFIG_MPC836x
> +/* FIXME: This code is for 100Mbs BUG fixing,
> +remove this lines when it will be fixed!!! */
> +				ugeth->ug_info->enet_interface =
> ENET_100_RGMII;
> +				tempval =
> +				    (u32)
> mii_info->mdio_read(ugeth->dev,
> +
> mii_info->mii_id,
> +							      0x1b);
> +				tempval = (tempval & ~0x000f) | 0x000b;
> +				mii_info->mdio_write(ugeth->dev,
> +						     mii_info->mii_id,
> 0x1b,
> +						     (u16) tempval);
> +				tempval =
> +				    (u32)
> mii_info->mdio_read(ugeth->dev,
> +
> mii_info->mii_id,
> +							      MII_BMCR);
> +				mii_info->mdio_write(ugeth->dev,
> +						     mii_info->mii_id,
> MII_BMCR,
> +						     (u16) (tempval |
> +
> BMCR_RESET));
> +				msleep(4000);
> +#endif				/* CONFIG_MPC8360 */
> +				adjust_enet_interface(ugeth);
> +				break;
> +			default:
> +				ugeth_warn
> +				    ("%s: Ack!  Speed (%d) is not
> 10/100/1000!",
> +				     dev->name, mii_info->speed);
> +				break;
> +			}
> +
> +			ugeth_info("%s: Speed %dBT", dev->name,
> +				   mii_info->speed);
> +
> +			ugeth->oldspeed = mii_info->speed;
> +		}
> +
> +		if (!ugeth->oldlink) {
> +			ugeth_info("%s: Link is up", dev->name);
> +			ugeth->oldlink = 1;
> +			netif_carrier_on(dev);
> +			netif_schedule(dev);
> +		}
> +	} else {
> +		if (ugeth->oldlink) {
> +			ugeth_info("%s: Link is down", dev->name);
> +			ugeth->oldlink = 0;
> +			ugeth->oldspeed = 0;
> +			ugeth->oldduplex = -1;
> +			netif_carrier_off(dev);
> +		}
> +	}
> +}
> +
> +/* Configure the PHY for dev.
> + * returns 0 if success.  -1 if failure
> + */
> +static int init_phy(struct net_device *dev)
> +{
> +	ucc_geth_private_t *ugeth = netdev_priv(dev);
> +	struct phy_info *curphy;
> +	ucc_mii_mng_t *mii_regs;
> +	struct ugeth_mii_info *mii_info;
> +	int err;
> +
> +	mii_regs = &ugeth->ug_regs->miimng;
> +
> +	ugeth->oldlink = 0;
> +	ugeth->oldspeed = 0;
> +	ugeth->oldduplex = -1;
> +
> +	mii_info = kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL);
> +
> +	if (NULL == mii_info) {
> +		ugeth_err("%s: Could not allocate mii_info", dev->name);
> +		return -ENOMEM;
> +	}
> +
> +	mii_info->mii_regs = mii_regs;
> +	mii_info->speed = SPEED_1000;
> +	mii_info->duplex = DUPLEX_FULL;
> +	mii_info->pause = 0;
> +	mii_info->link = 0;
> +
> +	mii_info->advertising = (ADVERTISED_10baseT_Half |
> +				 ADVERTISED_10baseT_Full |
> +				 ADVERTISED_100baseT_Half |
> +				 ADVERTISED_100baseT_Full |
> +				 ADVERTISED_1000baseT_Full);
> +	mii_info->autoneg = 1;
> +
> +	mii_info->mii_id = ugeth->ug_info->phy_address;
> +
> +	mii_info->dev = dev;
> +
> +	mii_info->mdio_read = &read_phy_reg;
> +	mii_info->mdio_write = &write_phy_reg;
> +
> +	ugeth->mii_info = mii_info;
> +
> +	spin_lock_irq(&ugeth->lock);
> +
> +	/* Set this UCC to be the master of the MII managment */
> +	ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num);
> +
> +	if (init_mii_management_configuration(1,
> +					      ugeth->ug_info->
> +					      miiPreambleSupress,
> +					      &mii_regs->miimcfg,
> +					      &mii_regs->miimind)) {
> +		ugeth_err("%s: The MII Bus is stuck!", dev->name);
> +		err = -1;
> +		goto bus_fail;
> +	}
> +
> +	spin_unlock_irq(&ugeth->lock);
> +
> +	/* get info for this PHY */
> +	curphy = get_phy_info(ugeth->mii_info);
> +
> +	if (curphy == NULL) {
> +		ugeth_err("%s: No PHY found", dev->name);
> +		err = -1;
> +		goto no_phy;
> +	}
> +
> +	mii_info->phyinfo = curphy;
> +
> +	/* Run the commands which initialize the PHY */
> +	if (curphy->init) {
> +		err = curphy->init(ugeth->mii_info);
> +		if (err)
> +			goto phy_init_fail;
> +	}
> +
> +	return 0;
> +
> +      phy_init_fail:
> +      no_phy:
> +      bus_fail:
> +	kfree(mii_info);
> +
> +	return err;
> +}
> +
> +#ifdef CONFIG_UGETH_TX_ON_DEMOND
> +static int ugeth_transmit_on_demand(ucc_geth_private_t *ugeth)
> +{
> +	ucc_fast_transmit_on_demand(ugeth->uccf);
> +
> +	return 0;
> +}
> +#endif
> +
> +static int ugeth_graceful_stop_tx(ucc_geth_private_t *ugeth)
> +{
> +	ucc_fast_private_t *uccf;
> +	u32 cecr_subblock;
> +	u32 temp;
> +
> +	uccf = ugeth->uccf;
> +
> +	/* Mask GRACEFUL STOP TX interrupt bit and clear it */
> +	temp = in_be32(uccf->p_uccm);
> +	temp &= ~UCCE_GRA;
> +	out_be32(uccf->p_uccm, temp);
> +	out_be32(uccf->p_ucce, UCCE_GRA);	/* clear by writing 1 */
> +
> +	/* Issue host command */
> +	cecr_subblock =
> +
> ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
> +	qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock,
> +		     (u8) QE_CR_PROTOCOL_ETHERNET, 0);
> +
> +	/* Wait for command to complete */
> +	do {
> +		temp = in_be32(uccf->p_ucce);
> +	} while (!(temp & UCCE_GRA));
> +
> +	uccf->stopped_tx = 1;
> +
> +	return 0;
> +}
> +
> +static int ugeth_graceful_stop_rx(ucc_geth_private_t * ugeth)
> +{
> +	ucc_fast_private_t *uccf;
> +	u32 cecr_subblock;
> +	u8 temp;
> +
> +	uccf = ugeth->uccf;
> +
> +	/* Clear acknowledge bit */
> +	temp = ugeth->p_rx_glbl_pram->rxgstpack;
> +	temp &= ~GRACEFUL_STOP_ACKNOWLEDGE_RX;
> +	ugeth->p_rx_glbl_pram->rxgstpack = temp;
> +
> +	/* Keep issuing command and checking acknowledge bit until
> +	it is asserted, according to spec */
> +	do {
> +		/* Issue host command */
> +		cecr_subblock =
> +		    ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.
> +						ucc_num);
> +		qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock,
> +			     (u8) QE_CR_PROTOCOL_ETHERNET, 0);
> +
> +		temp = ugeth->p_rx_glbl_pram->rxgstpack;
> +	} while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX));
> +
> +	uccf->stopped_rx = 1;
> +
> +	return 0;
> +}
> +
> +static int ugeth_restart_tx(ucc_geth_private_t *ugeth)
> +{
> +	ucc_fast_private_t *uccf;
> +	u32 cecr_subblock;
> +
> +	uccf = ugeth->uccf;
> +
> +	cecr_subblock =
> +
> ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
> +	qe_issue_cmd(QE_RESTART_TX, cecr_subblock, (u8)
> QE_CR_PROTOCOL_ETHERNET,
> +		     0);
> +	uccf->stopped_tx = 0;
> +
> +	return 0;
> +}
> +
> +static int ugeth_restart_rx(ucc_geth_private_t *ugeth)
> +{
> +	ucc_fast_private_t *uccf;
> +	u32 cecr_subblock;
> +
> +	uccf = ugeth->uccf;
> +
> +	cecr_subblock =
> +
> ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
> +	qe_issue_cmd(QE_RESTART_RX, cecr_subblock, (u8)
> QE_CR_PROTOCOL_ETHERNET,
> +		     0);
> +	uccf->stopped_rx = 0;
> +
> +	return 0;
> +}
> +
> +static int ugeth_enable(ucc_geth_private_t *ugeth, comm_dir_e mode)
> +{
> +	ucc_fast_private_t *uccf;
> +	int enabled_tx, enabled_rx;
> +
> +	uccf = ugeth->uccf;
> +
> +	/* check if the UCC number is in range. */
> +	if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) {
> +		ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
> +		return -EINVAL;
> +	}
> +
> +	enabled_tx = uccf->enabled_tx;
> +	enabled_rx = uccf->enabled_rx;
> +
> +	/* Get Tx and Rx going again, in case this channel was actively
> +	disabled. */
> +	if ((mode & COMM_DIR_TX) && (!enabled_tx) && uccf->stopped_tx)
> +		ugeth_restart_tx(ugeth);
> +	if ((mode & COMM_DIR_RX) && (!enabled_rx) && uccf->stopped_rx)
> +		ugeth_restart_rx(ugeth);
> +
> +	ucc_fast_enable(uccf, mode);	/* OK to do even if not disabled
> */
> +
> +	return 0;
> +
> +}
> +
> +static int ugeth_disable(ucc_geth_private_t * ugeth, comm_dir_e mode)
> +{
> +	ucc_fast_private_t *uccf;
> +
> +	uccf = ugeth->uccf;
> +
> +	/* check if the UCC number is in range. */
> +	if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) {
> +		ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
> +		return -EINVAL;
> +	}
> +
> +	/* Stop any transmissions */
> +	if ((mode & COMM_DIR_TX) && uccf->enabled_tx &&
> !uccf->stopped_tx)
> +		ugeth_graceful_stop_tx(ugeth);
> +
> +	/* Stop any receptions */
> +	if ((mode & COMM_DIR_RX) && uccf->enabled_rx &&
> !uccf->stopped_rx)
> +		ugeth_graceful_stop_rx(ugeth);
> +
> +	ucc_fast_disable(ugeth->uccf, mode); /* OK to do even if not
> enabled */
> +
> +	return 0;
> +}
> +
> +static void ugeth_dump_regs(ucc_geth_private_t *ugeth)
> +{
> +#ifdef DEBUG
> +	ucc_fast_dump_regs(ugeth->uccf);
> +	dump_regs(ugeth);
> +	dump_bds(ugeth);
> +#endif
> +}
> +
> +#ifdef CONFIG_UGETH_FILTERING
> +static int ugeth_ext_filtering_serialize_tad(ucc_geth_tad_params_t *
> +					     p_UccGethTadParams,
> +					     qe_fltr_tad_t *qe_fltr_tad)
> +{
> +	u16 temp;
> +
> +	/* Zero serialized TAD */
> +	memset(qe_fltr_tad, 0, QE_FLTR_TAD_SIZE);
> +
> +	qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_V;	/* Must have
> this */
> +	if (p_UccGethTadParams->rx_non_dynamic_extended_features_mode ||
> +	    (p_UccGethTadParams->vtag_op !=
> UCC_GETH_VLAN_OPERATION_TAGGED_NOP)
> +	    || (p_UccGethTadParams->vnontag_op !=
> +		UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP)
> +	    )
> +		qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_EF;
> +	if (p_UccGethTadParams->reject_frame)
> +		qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_REJ;
> +	temp =
> +	    (u16) (((u16) p_UccGethTadParams->
> +		    vtag_op) << UCC_GETH_TAD_VTAG_OP_SHIFT);
> +	qe_fltr_tad->serialized[0] |= (u8) (temp >> 8);	/* upper bits */
> +
> +	qe_fltr_tad->serialized[1] |= (u8) (temp & 0x00ff);	/* lower
> bits */
> +	if (p_UccGethTadParams->vnontag_op ==
> +	    UCC_GETH_VLAN_OPERATION_NON_TAGGED_Q_TAG_INSERT)
> +		qe_fltr_tad->serialized[1] |=
> UCC_GETH_TAD_V_NON_VTAG_OP;
> +	qe_fltr_tad->serialized[1] |=
> +	    p_UccGethTadParams->rqos << UCC_GETH_TAD_RQOS_SHIFT;
> +
> +	qe_fltr_tad->serialized[2] |=
> +	    p_UccGethTadParams->vpri << UCC_GETH_TAD_V_PRIORITY_SHIFT;
> +	/* upper bits */
> +	qe_fltr_tad->serialized[2] |= (u8) (p_UccGethTadParams->vid >>
> 8);
> +	/* lower bits */
> +	qe_fltr_tad->serialized[3] |= (u8) (p_UccGethTadParams->vid &
> 0x00ff);
> +
> +	return 0;
> +}
> +
> +static enet_addr_container_t
> +    *ugeth_82xx_filtering_get_match_addr_in_hash(ucc_geth_private_t
> *ugeth,
> +						 enet_addr_t
> *p_enet_addr)
> +{
> +	enet_addr_container_t *enet_addr_cont;
> +	struct list_head *p_lh;
> +	u16 i, num;
> +	int32_t j;
> +	u8 *p_counter;
> +
> +	if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) {
> +		p_lh = &ugeth->group_hash_q;
> +		p_counter = &(ugeth->numGroupAddrInHash);
> +	} else {
> +		p_lh = &ugeth->ind_hash_q;
> +		p_counter = &(ugeth->numIndAddrInHash);
> +	}
> +
> +	if (!p_lh)
> +		return NULL;
> +
> +	num = *p_counter;
> +
> +	for (i = 0; i < num; i++) {
> +		enet_addr_cont =
> +		    (enet_addr_container_t *)
> +		    ENET_ADDR_CONT_ENTRY(dequeue(p_lh));
> +		for (j = ENET_NUM_OCTETS_PER_ADDRESS - 1; j >= 0; j--) {
> +			if ((*p_enet_addr)[j] !=
> (enet_addr_cont->address)[j])
> +				break;
> +			if (j == 0)
> +				return enet_addr_cont;	/* Found */
> +		}
> +		enqueue(p_lh, &enet_addr_cont->node);	/* Put it back
> */
> +	}
> +	return NULL;
> +}
> +
> +static int ugeth_82xx_filtering_add_addr_in_hash(ucc_geth_private_t
> *ugeth,
> +						 enet_addr_t
> *p_enet_addr)
> +{
> +	ucc_geth_enet_address_recognition_location_e location;
> +	enet_addr_container_t *enet_addr_cont;
> +	struct list_head *p_lh;
> +	u8 i;
> +	u32 limit;
> +	u8 *p_counter;
> +
> +	if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) {
> +		p_lh = &ugeth->group_hash_q;
> +		limit = ugeth->ug_info->maxGroupAddrInHash;
> +		location =
> +
> UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_GROUP_HASH;
> +		p_counter = &(ugeth->numGroupAddrInHash);
> +	} else {
> +		p_lh = &ugeth->ind_hash_q;
> +		limit = ugeth->ug_info->maxIndAddrInHash;
> +		location =
> +
> UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_INDIVIDUAL_HASH;
> +		p_counter = &(ugeth->numIndAddrInHash);
> +	}
> +
> +	if ((enet_addr_cont =
> +	     ugeth_82xx_filtering_get_match_addr_in_hash(ugeth,
> p_enet_addr))) {
> +		list_add(p_lh, &enet_addr_cont->node);	/* Put it back
> */
> +		return 0;
> +	}
> +	if ((!p_lh) || (!(*p_counter < limit)))
> +		return -EBUSY;
> +	if (!(enet_addr_cont = get_enet_addr_container()))
> +		return -ENOMEM;
> +	for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++)
> +		(enet_addr_cont->address)[i] = (*p_enet_addr)[i];
> +	enet_addr_cont->location = location;
> +	enqueue(p_lh, &enet_addr_cont->node);	/* Put it back */
> +	++(*p_counter);
> +
> +	hw_add_addr_in_hash(ugeth, &(enet_addr_cont->address));
> +
> +	return 0;
> +}
> +
> +static int ugeth_82xx_filtering_clear_addr_in_hash(ucc_geth_private_t
> *ugeth,
> +						   enet_addr_t
> *p_enet_addr)
> +{
> +	ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
> +	enet_addr_container_t *enet_addr_cont;
> +	ucc_fast_private_t *uccf;
> +	comm_dir_e comm_dir;
> +	u16 i, num;
> +	struct list_head *p_lh;
> +	u32 *addr_h, *addr_l;
> +	u8 *p_counter;
> +
> +	uccf = ugeth->uccf;
> +
> +	p_82xx_addr_filt =
> +	    (ucc_geth_82xx_address_filtering_pram_t *)
> ugeth->p_rx_glbl_pram->
> +	    addressfiltering;
> +
> +	if (!
> +	    (enet_addr_cont =
> +	     ugeth_82xx_filtering_get_match_addr_in_hash(ugeth,
> p_enet_addr)))
> +		return -ENOENT;
> +
> +	/* It's been found and removed from the CQ. */
> +	/* Now destroy its container */
> +	put_enet_addr_container(enet_addr_cont);
> +
> +	if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) {
> +		addr_h = &(p_82xx_addr_filt->gaddr_h);
> +		addr_l = &(p_82xx_addr_filt->gaddr_l);
> +		p_lh = &ugeth->group_hash_q;
> +		p_counter = &(ugeth->numGroupAddrInHash);
> +	} else {
> +		addr_h = &(p_82xx_addr_filt->iaddr_h);
> +		addr_l = &(p_82xx_addr_filt->iaddr_l);
> +		p_lh = &ugeth->ind_hash_q;
> +		p_counter = &(ugeth->numIndAddrInHash);
> +	}
> +
> +	comm_dir = 0;
> +	if (uccf->enabled_tx)
> +		comm_dir |= COMM_DIR_TX;
> +	if (uccf->enabled_rx)
> +		comm_dir |= COMM_DIR_RX;
> +	if (comm_dir)
> +		ugeth_disable(ugeth, comm_dir);
> +
> +	/* Clear the hash table. */
> +	out_be32(addr_h, 0x00000000);
> +	out_be32(addr_l, 0x00000000);
> +
> +	/* Add all remaining CQ elements back into hash */
> +	num = --(*p_counter);
> +	for (i = 0; i < num; i++) {
> +		enet_addr_cont =
> +		    (enet_addr_container_t *)
> +		    ENET_ADDR_CONT_ENTRY(dequeue(p_lh));
> +		hw_add_addr_in_hash(ugeth, &(enet_addr_cont->address));
> +		enqueue(p_lh, &enet_addr_cont->node);	/* Put it back
> */
> +	}
> +
> +	if (comm_dir)
> +		ugeth_enable(ugeth, comm_dir);
> +
> +	return 0;
> +}
> +#endif /* CONFIG_UGETH_FILTERING */
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: Xilinx BSP for linux 2.6
From: Ming Liu @ 2006-07-06 14:04 UTC (permalink / raw)
  To: ammubhai; +Cc: linuxppc-embedded
In-Reply-To: <44AD108A.8050802@gmail.com>

Dear Ameet,

>   I DONOT have a ML403 with me. But does Xilinx EDK generate
>xparameters_ml300.h in the BSP instead of xparameters_ml403.h for the
>ML403 board?

Yes. EKD only generates ml300.h instead of ml403.h, although you specify 
the platform is ML403.


>You need to just copy the xparameters_ml300.h file (if that is what
>xilinx EDK generates) as xparameters_ml403.h in
>arch/ppc/platforms/4xx/xparameters/ folder. Configure the kernel as ML403.

I don't think so. I have looked into these two files. I found that there 
are many differences between them. Not only the addresses for each 
peripheral are different, but also the parameters' names. So If we just 
simply copy ml300.h file as ml403.h, many parameters will be undefined. 

>Like I said to you before, if you want to get started quickly and
>without much headache.. then please go step-by-step. Try the things I
>mention in the article PART I without applying any patches.

Thanks for your suggestion. I will start from the beginning. 

>Please DONOT hesitate to ask further clarifications!

It is really like a big family in the Linux world because of the help among 
the persons. Thanks for all the help from the friends in Linux world!

Regards
Ming

_________________________________________________________________
免费下载 MSN Explorer:   http://explorer.msn.com/lccn/  

^ permalink raw reply

* Re: Xilinx BSP for linux 2.6
From: Ameet Patil @ 2006-07-06 14:40 UTC (permalink / raw)
  To: Ming Liu; +Cc: linuxppc-embedded
In-Reply-To: <BAY110-F14AAB7BEB55C4563A4598AB2770@phx.gbl>

Hi Ming,
   If your Xilinx EDK generates the xparameters_ml300.h file for the
ML403 board then it has been configured with the right parameters and
address required by Linux. Don't look at the existing
xparameters_ml403.h file in the kernel source. It has got too many
parameters with address initializations that might not suit you at all.
I think its safe to copy the ml300.h onto ml403.h. I tried it... the
kernel compiles without any problems.

-Ameet

Ming Liu wrote:
> Dear Ameet,
> 
>>   I DONOT have a ML403 with me. But does Xilinx EDK generate
>> xparameters_ml300.h in the BSP instead of xparameters_ml403.h for the
>> ML403 board?
> 
> Yes. EKD only generates ml300.h instead of ml403.h, although you specify 
> the platform is ML403.
> 
> 
>> You need to just copy the xparameters_ml300.h file (if that is what
>> xilinx EDK generates) as xparameters_ml403.h in
>> arch/ppc/platforms/4xx/xparameters/ folder. Configure the kernel as 
>> ML403.
> 
> I don't think so. I have looked into these two files. I found that there 
> are many differences between them. Not only the addresses for each 
> peripheral are different, but also the parameters' names. So If we just 
> simply copy ml300.h file as ml403.h, many parameters will be undefined.
>> Like I said to you before, if you want to get started quickly and
>> without much headache.. then please go step-by-step. Try the things I
>> mention in the article PART I without applying any patches.
> 
> Thanks for your suggestion. I will start from the beginning.
>> Please DONOT hesitate to ask further clarifications!
> 
> It is really like a big family in the Linux world because of the help 
> among the persons. Thanks for all the help from the friends in Linux world!
> 
> Regards
> Ming
> 
> _________________________________________________________________
> 免费下载 MSN Explorer:   http://explorer.msn.com/lccn/ 
> 

^ permalink raw reply

* G5 troubles booting powerpc-git (July 6)
From: Will Schmidt @ 2006-07-06 14:53 UTC (permalink / raw)
  To: linuxppc-dev


        Any other G5's having troubles booting with the powerpc-git
        tree? 
        
        Mine fails..   The last text to the console is "MacIO PCI driver
        attached to Shasta chipset",  then the fans ramp up.  
        
        Booted earlier this week OK, so seems like a change in the last
        couple
        days did something bad.
        
        -Will
        

^ permalink raw reply

* RE: rs232 endianness on PPC
From: Walter L. Wimer III @ 2006-07-06 15:31 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <200607021210.19130.antonio.dibacco@aruba.it>

On Sun, 2006-07-02 at 12:10 +0200, Antonio Di Bacco wrote:
> PowerPC is neither byte swapped nor bit swapped.
> When transmitting on a network card the most significant byte is transmitted 
> first, and, inside the byte, the most significant bit is sent first.

FYI, the *bit*-order on a network actually depends on the layer 2
network standard that you happen to be communicating over.  Ethernet /
IEEE 802.3 is *least significant* bit first on the wire.  SLIP and
asynchronous PPP (since they go over RS232) are also least-significant
bit first.  IBM Token-Ring / IEEE 802.5 was most-significant bit first
on the wire.

IETF protocols such as IP, TCP, UDP, etc., etc., etc., only specify the
*byte* order, which is most-significant *byte* first.

Generally speaking, a network device driver programmer need only worry
about getting the *byte* order correct.  The network interface hardware
generally takes care of the *bit* order.  (An exception to this can be
drivers and interface hardware for some low-speed "networks" such as I2C
or Dallas 1-Wire.  These may be very primitive and require software
"bit-banging" where the driver software must explicitly shift bits out
of a byte and transmit them one bit at a time.  Clearly in these cases,
the driver must transmit the bits in the correct order based on the
appropriate standard (e.g. I2C, Dallas 1-Wire, etc.).)



Cheers,

Walt Wimer
TimeSys Corporation

^ permalink raw reply

* Re: snd-aoa issues & fixes
From: Johannes Berg @ 2006-07-06 16:51 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list
In-Reply-To: <1151481678.4044.11.camel@localhost.localdomain>

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

On Wed, 2006-06-28 at 18:01 +1000, Benjamin Herrenschmidt wrote:

> - Redefinition of various FCR related bits in i2s-control. I've fixed
> that in the patch and used existing definitions. However, we still have
> a problem that we don't properly lock with pmac_feature for access to
> these. We need to either expose new feature calls now that we are
> upstream or expose the pmac_feature spinlock

Oh, good point. I'd say we add feature calls for that.

> - I noticed you don't call pmac_feature and don't set bits in FCR3
> etc... (enabling the 18Mhz clock for example). Is that normal ? You
> don't use that clock ? That's the only difference in FCR content that
> I've been able to spot between snd-powermac and snd-aoa but hacking it
> doesn't seem to make much difference.

Nah, I simply forgot that. Apparently all the clocks are on anyway? All
rates seem to work here... We want clock refcounting so we can actually
turn them off again, turning them all on is easy enough.

> - The fabric stuff needs a bit of cleanup... You seem to be fond of
> defining lotsa struct's :) Even when they don't contain much :) Triggers
> another problem below

Awww :)

> - I've had a crash with built-in snd-aoa at boot... The problem is that
> when built-in, there is no enforced ordering between module_init() calls
> except for link order... What happens here is that soundbus is last in
> the Makefile, thus we try to register soundbus devices before we
> register the bus type. I fixes that in the patch both by putting
> soundbus first in the Make

Good point. I think someone else noticed that too.

> - If i2sbus is loaded after the codec and fabric, the codec fails to
> initialize. I haven't tried to debug that one

Uhh. I thought the codec couldn't be loaded before i2sbus. I'll have to
see what causes this, probably some reference missing.

> - The dmesg output could use some cleanup :)

:)

> I think we need to change the codec probe phase dramatically: 

It's not as dramatic as you think.

>   1 - codec drivers register the i2c thingy as normal
>   2 - i2c kicks in, they do the current device-node and/or i2c bus name
> check and register
>       themselves with the core. They do not try to touch the hardware at
> this point
>   3 - fabric kicks in (or was already there). It checks the list of
> codecs registered when
>       loaded and gets notified of new ones added. If codec matches the
> layout, then codec
>       init is called
>   4 - codec init called by fabric. That is where we try to tap the
> hardware. Might fail in
>       which case the fabric doesn't try to use the codec

> (That is, there is a global list of registered codecs at the core, and a
> list of "active" codecs in the fabric or bus, whatever...)

Nah. All we need to do is change the onyx codec driver to not try
probing the onyx. The tas already does it this way iirc. The toonie is a
bit different again, the module will fail loading when the fabric
doesn't want it. But that's fine.

johannes

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

^ permalink raw reply

* Re: G5 troubles booting powerpc-git (July 6)
From: Benjamin Herrenschmidt @ 2006-07-06 22:53 UTC (permalink / raw)
  To: will_schmidt; +Cc: linuxppc-dev
In-Reply-To: <1152197602.14547.10.camel@farscape.rchland.ibm.com>

On Thu, 2006-07-06 at 09:53 -0500, Will Schmidt wrote:
>         Any other G5's having troubles booting with the powerpc-git
>         tree? 
>         
>         Mine fails..   The last text to the console is "MacIO PCI driver
>         attached to Shasta chipset",  then the fans ramp up.  
>         
>         Booted earlier this week OK, so seems like a change in the last
>         couple
>         days did something bad

I suspect there's still something wrong with mpic map callback, I'm
working on it

Ben.

^ permalink raw reply

* Re: G5 troubles booting powerpc-git (July 6)
From: Benjamin Herrenschmidt @ 2006-07-06 22:56 UTC (permalink / raw)
  To: will_schmidt; +Cc: Andrew Morton, linuxppc-dev
In-Reply-To: <1152197602.14547.10.camel@farscape.rchland.ibm.com>

If you look at arch/powerpc/kernel/irq.c from line 479:

	/* Check if mapping already exist, if it does, call
	 * host->ops->map() to update the flags
	 */
	virq = irq_find_mapping(host, hwirq);
	if (virq != IRQ_NONE) {
		pr_debug("irq: -> existing mapping on virq %d\n", virq);
		host->ops->map(host, virq, hwirq, flags);
		return virq;
	}

What if you comment out the host->ops->map(...) call in there ? Does it
help ?

I think I have a little misdesign in my new powerpc irq handling
regarding the mixing up of mapping and setting of triggers. I'm working
on a solution, hopefully patches early next week.

Ben.

^ permalink raw reply

* Re: [PATCH 4/20] Mark platform device data as const
From: Paul Mackerras @ 2006-07-06 23:41 UTC (permalink / raw)
  To: Jeremy Kerr; +Cc: linuxppc-dev, greg
In-Reply-To: <45499930@toto.iv>

Jeremy Kerr writes:

> platform_device_add_data()'s data argument can be qualified as const -
> the function just copies it to another buffer.

Ummm, you change the actual function definition here, but you put the
change to the declaration in include/linux/platform_device.h in your
[5/20] patch.  Please redo this patch with the change to the
declaration included.

Paul.

^ permalink raw reply

* Re: [Alsa-devel] [RFC 01/12] snd-powermac: no longer handle anything with a layout-id property
From: Benjamin Herrenschmidt @ 2006-07-07  5:38 UTC (permalink / raw)
  To: Andreas Schwab
  Cc: alsa-devel, Takashi Iwai, netstar, linuxppc-dev, Lee Revell,
	Johannes Berg
In-Reply-To: <jehd231rjx.fsf@sykes.suse.de>

On Fri, 2006-06-30 at 01:16 +0200, Andreas Schwab wrote:
> Lee Revell <rlrevell@joe-job.com> writes:
> 
> > What is the content of /proc/asound/cards?  The patches must have
> > changed the card name and failed to create a matching config file
> > in /usr/share/alsa/cards.
> 
> Thanks for the hint.  I have added 'AppleOnbdAudio cards.PMac' to
> /usr/share/alsa/cards/aliases.conf, and it works again.

There is still an issue... wether to enable softvol or not... With
snd-aoa, the card name is always the same but wether it has hardware
volume control or not (Toonie doesn't) is not known... Alsa should have
ways to add softvol automatically if no master volume control exist.

Ben.

^ permalink raw reply

* [PATCH] dtc: fix endian issue when reading blobs
From: Michael Neuling @ 2006-07-07  5:53 UTC (permalink / raw)
  To: linuxppc-dev, Jon Loeliger

The reserve mem regions are screwy if you read a blob on x86.  I'm
guessing there may be a few more of these lurking in the code. 

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

---
This now gives clean diffs between running on big and little endian machines.

 flattree.c |    2 ++
 1 file changed, 2 insertions(+)

Index: dtc/flattree.c
===================================================================
--- dtc.orig/flattree.c
+++ dtc/flattree.c
@@ -619,6 +619,8 @@ static struct reserve_info *flat_read_me
 	p = inb->ptr;
 	while (1) {
 		flat_read_chunk(inb, &re, sizeof(re));
+		re.address  = cpu_to_be64(re.address);
+		re.size = cpu_to_be64(re.size);
 		if (re.size == 0)
 			break;
 

^ permalink raw reply

* snd-aoa: g5 tas codec problems
From: Benjamin Herrenschmidt @ 2006-07-07  7:47 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linuxppc-dev list, alsa-devel

Ok, so now I have it working on the G5 :)

(Patch below)

There are several issues (I would say in addition to what I listed
earlier):

 - Maybe it's me or maybe it's just too complicated, but I haven't quite
grasped the whole interaction between the soundbus,i2sbus,fabric and
codecs... especially initialisation ordering. It would be nice if we
could spend some time going through that and simplifying :) It leads to
at least one of the problems

 - The patch fixes a couple of nits related to having the modules
built-in: soundbus must really be a subsys_initcall() so it's
initialized before anybody else, and I've put the soundbus/ dir before
the codecs in the link order because the TAS is unhappy if loaded before
i2s (see below)

 - The TAS is a nasty beast. It needs the i2s clocks enabled or it goes
bunk... That's the problem with the G5. I've added a clock notifier and
reset it completely when the clocks come back, that's what fixes the G5
sound (looks like it loses state somewhat when not clocked). It would be
nice to streamline/cleanup some of the TAS handling, maybe with register
shadows like darwin or just with proper state variables to re-consitute
the whole thing and have a "fast mode" load since we need to do it so
often

 - Because of the above, starting to play a sound 1- takes some time to
init things and 2- clacks (setting the mutes on TAS before losing clocks
isn't enough, I think the fact that it goes bonk makes it parasite the
analog outputs). We need to also mute the amps around that. I haven't
quite figured how to do that from i2sbus though :) Also, we should try
(if not already the case) to cache our clock/i2s state so that
subsequent prepare() don't try to change things that are already ok.
That way we avoid having to blast the codec each time. But right now,
the important thing is to add mutes. People with external amplifiers
will really not like those clacs...

Note that the patch applies on top of Andreas latest one fixing the irq
on latest git.

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

Index: linux-irq-work/sound/aoa/soundbus/core.c
===================================================================
--- linux-irq-work.orig/sound/aoa/soundbus/core.c	2006-06-23 13:22:14.000000000 +1000
+++ linux-irq-work/sound/aoa/soundbus/core.c	2006-07-07 15:58:25.000000000 +1000
@@ -246,5 +246,5 @@
 }
 EXPORT_SYMBOL_GPL(soundbus_unregister_driver);
 
-module_init(soundbus_init);
+subsys_initcall(soundbus_init);
 module_exit(soundbus_exit);
Index: linux-irq-work/arch/powerpc/platforms/powermac/feature.c
===================================================================
--- linux-irq-work.orig/arch/powerpc/platforms/powermac/feature.c	2006-07-01 13:51:11.000000000 +1000
+++ linux-irq-work/arch/powerpc/platforms/powermac/feature.c	2006-07-07 16:13:20.000000000 +1000
@@ -2394,6 +2394,7 @@
 
 	return func(node, param, value);
 }
+EXPORT_SYMBOL_GPL(pmac_do_feature_call);
 
 static int __init probe_motherboard(void)
 {
Index: linux-irq-work/sound/aoa/Makefile
===================================================================
--- linux-irq-work.orig/sound/aoa/Makefile	2006-06-23 13:22:14.000000000 +1000
+++ linux-irq-work/sound/aoa/Makefile	2006-07-07 16:11:35.000000000 +1000
@@ -1,4 +1,4 @@
 obj-$(CONFIG_SND_AOA) += core/
-obj-$(CONFIG_SND_AOA) += codecs/
-obj-$(CONFIG_SND_AOA) += fabrics/
 obj-$(CONFIG_SND_AOA_SOUNDBUS) += soundbus/
+obj-$(CONFIG_SND_AOA) += fabrics/
+obj-$(CONFIG_SND_AOA) += codecs/
Index: linux-irq-work/sound/aoa/codecs/snd-aoa-codec-tas.c
===================================================================
--- linux-irq-work.orig/sound/aoa/codecs/snd-aoa-codec-tas.c	2006-07-07 15:46:30.000000000 +1000
+++ linux-irq-work/sound/aoa/codecs/snd-aoa-codec-tas.c	2006-07-07 17:45:06.000000000 +1000
@@ -75,19 +75,25 @@
 #include "../aoa.h"
 #include "../soundbus/soundbus.h"
 
-
 #define PFX "snd-aoa-codec-tas: "
 
+
 struct tas {
 	struct aoa_codec	codec;
 	struct i2c_client	i2c;
-	u32			muted_l:1, muted_r:1,
-				controls_created:1;
+	u32			mute_l:1, mute_r:1 ,
+				controls_created:1 ,
+				drc_enabled:1,
+				save_mute_l:1, save_mute_r:1,
+				hw_enabled:1;
 	u8			cached_volume_l, cached_volume_r;
 	u8			mixer_l[3], mixer_r[3];
 	u8			acr;
+	int			drc_range;
 };
 
+static int tas_reset_init(struct tas *tas);
+
 static struct tas *codec_to_tas(struct aoa_codec *codec)
 {
 	return container_of(codec, struct tas, codec);
@@ -101,6 +107,28 @@
 		return i2c_smbus_write_i2c_block_data(&tas->i2c, reg, len, data);
 }
 
+static void tas3004_set_drc(struct tas *tas)
+{
+	unsigned char val[6];
+
+	if (tas->drc_enabled)
+		val[0] = 0x50; /* 3:1 above threshold */
+	else
+		val[0] = 0x51; /* disabled */
+	val[1] = 0x02; /* 1:1 below threshold */
+	if (tas->drc_range > 0xef)
+		val[2] = 0xef;
+	else if (tas->drc_range < 0)
+		val[2] = 0x00;
+	else
+		val[2] = tas->drc_range;
+	val[3] = 0xb0;
+	val[4] = 0x60;
+	val[5] = 0xa0;
+
+	tas_write_reg(tas, TAS_REG_DRC, 6, val);
+}
+
 static void tas_set_volume(struct tas *tas)
 {
 	u8 block[6];
@@ -113,8 +141,8 @@
 	if (left > 177) left = 177;
 	if (right > 177) right = 177;
 
-	if (tas->muted_l) left = 0;
-	if (tas->muted_r) right = 0;
+	if (tas->mute_l) left = 0;
+	if (tas->mute_r) right = 0;
 
 	/* analysing the volume and mixer tables shows
 	 * that they are similar enough when we shift
@@ -202,7 +230,8 @@
 
 	tas->cached_volume_l = ucontrol->value.integer.value[0];
 	tas->cached_volume_r = ucontrol->value.integer.value[1];
-	tas_set_volume(tas);
+	if (tas->hw_enabled)
+		tas_set_volume(tas);
 	return 1;
 }
 
@@ -230,8 +259,8 @@
 {
 	struct tas *tas = snd_kcontrol_chip(kcontrol);
 
-	ucontrol->value.integer.value[0] = !tas->muted_l;
-	ucontrol->value.integer.value[1] = !tas->muted_r;
+	ucontrol->value.integer.value[0] = !tas->mute_l;
+	ucontrol->value.integer.value[1] = !tas->mute_r;
 	return 0;
 }
 
@@ -240,13 +269,14 @@
 {
 	struct tas *tas = snd_kcontrol_chip(kcontrol);
 
-	if (tas->muted_l == !ucontrol->value.integer.value[0]
-	 && tas->muted_r == !ucontrol->value.integer.value[1])
+	if (tas->mute_l == !ucontrol->value.integer.value[0]
+	 && tas->mute_r == !ucontrol->value.integer.value[1])
 		return 0;
 
-	tas->muted_l = !ucontrol->value.integer.value[0];
-	tas->muted_r = !ucontrol->value.integer.value[1];
-	tas_set_volume(tas);
+	tas->mute_l = !ucontrol->value.integer.value[0];
+	tas->mute_r = !ucontrol->value.integer.value[1];
+	if (tas->hw_enabled)
+		tas_set_volume(tas);
 	return 1;
 }
 
@@ -294,7 +324,8 @@
 	tas->mixer_l[idx] = ucontrol->value.integer.value[0];
 	tas->mixer_r[idx] = ucontrol->value.integer.value[1];
 
-	tas_set_mixer(tas);
+	if (tas->hw_enabled)
+		tas_set_mixer(tas);
 	return 1;
 }
 
@@ -310,7 +341,6 @@
 }
 
 MIXER_CONTROL(pcm1, "PCM1", 0);
-MIXER_CONTROL(pcm2, "PCM2", 1);
 MIXER_CONTROL(monitor, "Monitor", 2);
 
 static int tas_snd_capture_source_info(struct snd_kcontrol *kcontrol,
@@ -347,7 +377,8 @@
 		tas->acr |= TAS_ACR_INPUT_B;
 	if (oldacr == tas->acr)
 		return 0;
-	tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
+	if (tas->hw_enabled)
+		tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
 	return 1;
 }
 
@@ -400,26 +431,68 @@
 static int tas_reset_init(struct tas *tas)
 {
 	u8 tmp;
+
+	msleep(5);
 	tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0);
-	msleep(1);
+	msleep(5);
 	tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 1);
-	msleep(1);
+	msleep(20);
 	tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0);
-	msleep(1);
-
-	tas->acr &= ~TAS_ACR_ANALOG_PDOWN;
-	tas->acr |= TAS_ACR_B_MONAUREAL | TAS_ACR_B_MON_SEL_RIGHT;
-	if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
-		return -ENODEV;
+	msleep(10);
 
 	tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT;
 	if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp))
 		return -ENODEV;
 
+	tas->acr |= TAS_ACR_ANALOG_PDOWN | TAS_ACR_B_MONAUREAL |
+		TAS_ACR_B_MON_SEL_RIGHT;
+	if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
+		return -ENODEV;
+
 	tmp = 0;
 	if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp))
 		return -ENODEV;
 
+	tas3004_set_drc(tas);
+
+	/* Set treble & bass to 0dB */
+	tmp = 114;
+	tas_write_reg(tas, TAS_REG_TREBLE, 1, &tmp);
+	tas_write_reg(tas, TAS_REG_BASS, 1, &tmp);
+
+	tas->acr &= ~TAS_ACR_ANALOG_PDOWN;
+	if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
+		return -ENODEV;
+
+	return 0;
+}
+
+static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock)
+{
+	struct tas *tas = cii->codec_data;
+
+	switch(clock) {
+	case CLOCK_SWITCH_PREPARE_SLAVE:
+		/* Clocks are going away, mute mute mute */
+		tas->save_mute_l = tas->mute_l;
+		tas->save_mute_r = tas->mute_r;
+		tas->mute_l = tas->mute_l = 1;
+		tas_set_volume(tas);
+		tas->hw_enabled = 0;
+		break;
+	case CLOCK_SWITCH_SLAVE:
+		/* Clocks are back, re-init the codec */
+		tas->mute_l = tas->save_mute_l;
+		tas->mute_r = tas->save_mute_r;
+		tas_reset_init(tas);
+		tas_set_volume(tas);
+		tas_set_mixer(tas);
+		tas->hw_enabled = 1;
+		break;
+	default:
+		/* Do we want to return an error here ? */
+		return 0;
+	}
 	return 0;
 }
 
@@ -428,6 +501,7 @@
  * our i2c device is suspended, and then take note of that! */
 static int tas_suspend(struct tas *tas)
 {
+	tas->hw_enabled = 0;
 	tas->acr |= TAS_ACR_ANALOG_PDOWN;
 	tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
 	return 0;
@@ -439,6 +513,7 @@
 	tas_reset_init(tas);
 	tas_set_volume(tas);
 	tas_set_mixer(tas);
+	tas->hw_enabled = 1;
 	return 0;
 }
 
@@ -464,6 +539,7 @@
 	.bus_factor = 64,
 	.owner = THIS_MODULE,
 	.usable = tas_usable,
+	.switch_clock = tas_switch_clock,
 #ifdef CONFIG_PM
 	.suspend = _tas_suspend,
 	.resume = _tas_resume,
@@ -480,11 +556,6 @@
 		return -EINVAL;
 	}
 
-	if (tas_reset_init(tas)) {
-		printk(KERN_ERR PFX "tas failed to initialise\n");
-		return -ENXIO;
-	}
-
 	if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev,
 						   aoa_get_card(),
 						   &tas_codec_info, tas)) {
@@ -508,10 +579,6 @@
 	if (err)
 		goto error;
 
-	err = aoa_snd_ctl_add(snd_ctl_new1(&pcm2_control, tas));
-	if (err)
-		goto error;
-
 	err = aoa_snd_ctl_add(snd_ctl_new1(&monitor_control, tas));
 	if (err)
 		goto error;
@@ -553,6 +620,7 @@
 	tas->i2c.driver = &tas_driver;
 	tas->i2c.adapter = adapter;
 	tas->i2c.addr = addr;
+	tas->drc_range = TAS3004_DRC_MAX;
 	strlcpy(tas->i2c.name, "tas audio codec", I2C_NAME_SIZE-1);
 
 	if (i2c_attach_client(&tas->i2c)) {
@@ -569,7 +637,9 @@
 	if (aoa_codec_register(&tas->codec)) {
 		goto detach;
 	}
-	printk(KERN_DEBUG "snd-aoa-codec-tas: created and attached tas instance\n");
+	printk(KERN_DEBUG
+	       "snd-aoa-codec-tas: tas found, addr 0x%02x on %s\n",
+	       addr, node->full_name);
 	return 0;
  detach:
 	i2c_detach_client(&tas->i2c);
@@ -657,3 +727,5 @@
 
 module_init(tas_init);
 module_exit(tas_exit);
+
+
Index: linux-irq-work/sound/aoa/codecs/snd-aoa-codec-tas.h
===================================================================
--- linux-irq-work.orig/sound/aoa/codecs/snd-aoa-codec-tas.h	2006-06-23 13:22:14.000000000 +1000
+++ linux-irq-work/sound/aoa/codecs/snd-aoa-codec-tas.h	2006-07-07 16:58:17.000000000 +1000
@@ -44,4 +44,12 @@
 #define TAS_REG_LEFT_BIQUAD6	0x10
 #define TAS_REG_RIGHT_BIQUAD6	0x19
 
+#define TAS_REG_LEFT_LOUDNESS		0x21
+#define TAS_REG_RIGHT_LOUDNESS		0x22
+#define TAS_REG_LEFT_LOUDNESS_GAIN	0x23
+#define TAS_REG_RIGHT_LOUDNESS_GAIN	0x24
+
+#define TAS3001_DRC_MAX		0x5f
+#define TAS3004_DRC_MAX		0xef
+
 #endif /* __SND_AOA_CODECTASH */
Index: linux-irq-work/sound/aoa/core/snd-aoa-gpio-pmf.c
===================================================================
--- linux-irq-work.orig/sound/aoa/core/snd-aoa-gpio-pmf.c	2006-06-23 13:22:14.000000000 +1000
+++ linux-irq-work/sound/aoa/core/snd-aoa-gpio-pmf.c	2006-07-07 16:10:25.000000000 +1000
@@ -14,9 +14,13 @@
 static void pmf_gpio_set_##name(struct gpio_runtime *rt, int on)\
 {								\
 	struct pmf_args args = { .count = 1, .u[0].v = !on };	\
-								\
+	int rc;							\
+							\
 	if (unlikely(!rt)) return;				\
-	pmf_call_function(rt->node, #name "-mute", &args);	\
+	rc = pmf_call_function(rt->node, #name "-mute", &args);	\
+	if (rc)							\
+		printk(KERN_WARNING "pmf_gpio_set_" #name	\
+		" failed, rc: %d\n", rc);			\
 	rt->implementation_private &= ~(1<<bit);		\
 	rt->implementation_private |= (!!on << bit);		\
 }								\
@@ -33,9 +37,13 @@
 static void pmf_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
 {
 	struct pmf_args args = { .count = 1, .u[0].v = !!on };
+	int rc;
 
 	if (unlikely(!rt)) return;
-	pmf_call_function(rt->node, "hw-reset", &args);
+	rc = pmf_call_function(rt->node, "hw-reset", &args);
+	if (rc)
+		printk(KERN_WARNING "pmf_gpio_set_hw_reset"
+		       " failed, rc: %d\n", rc);
 }
 
 static void pmf_gpio_all_amps_off(struct gpio_runtime *rt)
Index: linux-irq-work/sound/aoa/fabrics/snd-aoa-fabric-layout.c
===================================================================
--- linux-irq-work.orig/sound/aoa/fabrics/snd-aoa-fabric-layout.c	2006-07-01 13:51:30.000000000 +1000
+++ linux-irq-work/sound/aoa/fabrics/snd-aoa-fabric-layout.c	2006-07-07 16:17:43.000000000 +1000
@@ -950,11 +950,12 @@
 	layout_id = (unsigned int *) get_property(sound, "layout-id", NULL);
 	if (!layout_id)
 		goto outnodev;
-	printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d ", *layout_id);
+	printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d\n",
+	       *layout_id);
 
 	layout = find_layout_by_id(*layout_id);
 	if (!layout) {
-		printk("(no idea how to handle)\n");
+		printk(KERN_ERR "snd-aoa-fabric-layout: unknown layout\n");
 		goto outnodev;
 	}
 
@@ -972,15 +973,17 @@
 	case 51: /* PowerBook5,4 */
 	case 58: /* Mac Mini */
 		ldev->gpio.methods = ftr_gpio_methods;
+		printk(KERN_DEBUG
+		       "snd-aoa-fabric-layout: Using PMF GPIOs\n");
 		break;
 	default:
 		ldev->gpio.methods = pmf_gpio_methods;
+		printk(KERN_DEBUG
+		       "snd-aoa-fabric-layout: Using direct GPIOs\n");
 	}
 	ldev->selfptr_headphone.ptr = ldev;
 	ldev->selfptr_lineout.ptr = ldev;
 	sdev->ofdev.dev.driver_data = ldev;
-
-	printk("(using)\n");
 	list_add(&ldev->list, &layouts_list);
 	layouts_list_items++;
 

^ permalink raw reply

* Re: snd-aoa: g5 tas codec problems
From: Benjamin Herrenschmidt @ 2006-07-07  7:50 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linuxppc-dev list, alsa-devel
In-Reply-To: <1152258426.9862.44.camel@localhost.localdomain>

On Fri, 2006-07-07 at 17:47 +1000, Benjamin Herrenschmidt wrote:

> Note that the patch applies on top of Andreas latest one fixing the irq
> on latest git.

Actually, it applies on top of Andres patch, plus my patch fixing the
resources on g5, updated to apply on top of latest git:

I'll do a combo patch later (or you can do one if you want)

Ben.

Index: linux-irq-work/sound/aoa/soundbus/i2sbus/i2sbus-core.c
===================================================================
--- linux-irq-work.orig/sound/aoa/soundbus/i2sbus/i2sbus-core.c	2006-07-07 15:40:53.000000000 +1000
+++ linux-irq-work/sound/aoa/soundbus/i2sbus/i2sbus-core.c	2006-07-07 15:45:06.000000000 +1000
@@ -7,13 +7,16 @@
  */
 
 #include <linux/module.h>
-#include <asm/macio.h>
-#include <asm/dbdma.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+
 #include <sound/driver.h>
 #include <sound/core.h>
-#include <linux/dma-mapping.h>
+
+#include <asm/macio.h>
+#include <asm/dbdma.h>
+
 #include "../soundbus.h"
 #include "i2sbus.h"
 
@@ -24,6 +27,12 @@
  * string that macio puts into the relevant device */
 MODULE_ALIAS("of:Ni2sTi2sC");
 
+static int force;
+module_param(force, int, 0444);
+MODULE_PARM_DESC(force, "Force loading i2sbus even when"
+		 " no layout-id property is present");
+
+
 static struct of_device_id i2sbus_match[] = {
 	{ .name = "i2s" },
 	{ }
@@ -73,7 +82,7 @@
  	if (i2sdev->intfregs) iounmap(i2sdev->intfregs);
  	if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma);
  	if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma);
-	for (i=0;i<3;i++)
+	for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
 		if (i2sdev->allocated_resource[i])
 			release_and_free_resource(i2sdev->allocated_resource[i]);
 	free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring);
@@ -101,10 +110,47 @@
 	return IRQ_HANDLED;
 }
 
-static int force;
-module_param(force, int, 0444);
-MODULE_PARM_DESC(force, "Force loading i2sbus even when"
-			" no layout-id property is present");
+/*
+ * XXX FIXME: We have to test the layout_id's here to get the proper way
+ * of mapping in various registers, thanks to bugs in Apple device-trees.
+ * Ideally, that should be handled by the layout fabric but doing so would
+ * require a little bit of shuffling around
+ */
+static int i2sbus_get_and_fixup_rsrc(struct device_node *np, int index,
+				     int layout, struct resource *res)
+{
+	struct device_node *parent;
+	int pindex, rc = -ENXIO;
+	u32 *reg;
+
+	/* Machines with layout 76 and 36 (K2 based) have a weird device
+	 * tree what we need to special case.
+	 * Normal machines just fetch the resource from the i2s-X node.
+	 * Darwin further divides normal machines into old and new layouts
+	 * with a subtely different code path but that doesn't seem necessary
+	 * in practice, they just bloated it. In addition, even on our K2
+	 * case the i2s-modem node, if we ever want to handle it, uses the
+	 * normal layout
+	 */
+	if (layout != 76 && layout != 36)
+		return of_address_to_resource(np, index, res);
+
+	parent = of_get_parent(np);
+	pindex = (index == aoa_resource_i2smmio) ? 0 : 1;
+	rc = of_address_to_resource(parent, pindex, res);
+	if (rc)
+		goto bail;
+	reg = (u32 *)get_property(np, "reg", NULL);
+	if (reg == NULL) {
+		rc = -ENXIO;
+		goto bail;
+	}
+	res->start += reg[index * 2];
+	res->end = res->start + reg[index * 2 + 1] - 1;
+ bail:
+	of_node_put(parent);
+	return rc;
+}
 
 /* FIXME: look at device node refcounting */
 static int i2sbus_add_dev(struct macio_dev *macio,
@@ -113,7 +159,8 @@
 {
 	struct i2sbus_dev *dev;
 	struct device_node *child = NULL, *sound = NULL;
-	int i;
+	struct resource *r;
+	int i, layout = 0;
 	static const char *rnames[] = { "i2sbus: %s (control)",
 					"i2sbus: %s (tx)",
 					"i2sbus: %s (rx)" };
@@ -144,8 +191,9 @@
 		u32 *layout_id;
 		layout_id = (u32*) get_property(sound, "layout-id", NULL);
 		if (layout_id) {
+			layout = *layout_id;
 			snprintf(dev->sound.modalias, 32,
-				 "sound-layout-%d", *layout_id);
+				 "sound-layout-%d", layout);
 			force = 1;
 		}
 	}
@@ -175,23 +223,32 @@
 	dev->bus_number = np->name[4] - 'a';
 	INIT_LIST_HEAD(&dev->sound.codec_list);
 
-	for (i=0;i<3;i++) {
+	for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
 		dev->interrupts[i] = -1;
-		snprintf(dev->rnames[i], sizeof(dev->rnames[i]), rnames[i], np->name);
+		snprintf(dev->rnames[i], sizeof(dev->rnames[i]), rnames[i],
+			 np->name);
 	}
-	for (i=0;i<3;i++) {
+	for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
 		int irq = irq_of_parse_and_map(np, i);
 		if (request_irq(irq, ints[i], 0, dev->rnames[i], dev))
 			goto err;
 		dev->interrupts[i] = irq;
 	}
 
-	for (i=0;i<3;i++) {
-		if (of_address_to_resource(np, i, &dev->resources[i]))
+	/* Resource handling is problematic as some device-trees contain
+	 * useless crap (ugh ugh ugh). We work around that here by calling
+	 * specific functions for calculating the appropriate resources.
+	 *
+	 * This will all be moved to macio_asic.c at one point
+	 */
+	for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
+		if (i2sbus_get_and_fixup_rsrc(np,i,layout,&dev->resources[i]))
 			goto err;
-		/* if only we could use our resource dev->resources[i]...
+
+		/* If only we could use our resource dev->resources[i]...
 		 * but request_resource doesn't know about parents and
-		 * contained resources... */
+		 * contained resources...
+		 */
 		dev->allocated_resource[i] = 
 			request_mem_region(dev->resources[i].start,
 					   dev->resources[i].end -
@@ -203,12 +260,12 @@
 		}
 	}
 	/* should do sanity checking here about length of them */
-	dev->intfregs = ioremap(dev->resources[0].start,
-				dev->resources[0].end-dev->resources[0].start+1);
-	dev->out.dbdma = ioremap(dev->resources[1].start,
-			 	 dev->resources[1].end-dev->resources[1].start+1);
-	dev->in.dbdma = ioremap(dev->resources[2].start,
-				dev->resources[2].end-dev->resources[2].start+1);
+	r = &dev->resources[aoa_resource_i2smmio];
+	dev->intfregs = ioremap(r->start, r->end - r->start + 1);
+	r = &dev->resources[aoa_resource_txdbdma];
+	dev->out.dbdma = ioremap(r->start, r->end - r->start + 1);
+	r = &dev->resources[aoa_resource_rxdbdma];
+	dev->in.dbdma = ioremap(r->start, r->end - r->start + 1);
 	if (!dev->intfregs || !dev->out.dbdma || !dev->in.dbdma)
 		goto err;
 
Index: linux-irq-work/sound/aoa/soundbus/i2sbus/i2sbus.h
===================================================================
--- linux-irq-work.orig/sound/aoa/soundbus/i2sbus/i2sbus.h	2006-06-23 13:22:14.000000000 +1000
+++ linux-irq-work/sound/aoa/soundbus/i2sbus/i2sbus.h	2006-07-07 15:41:40.000000000 +1000
@@ -7,20 +7,22 @@
  */
 #ifndef __I2SBUS_H
 #define __I2SBUS_H
-#include <asm/dbdma.h>
 #include <linux/interrupt.h>
-#include <sound/pcm.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
+
+#include <sound/pcm.h>
+
 #include <asm/prom.h>
+#include <asm/pmac_feature.h>
+#include <asm/dbdma.h>
+
 #include "i2sbus-interface.h"
-#include "i2sbus-control.h"
 #include "../soundbus.h"
 
 struct i2sbus_control {
-	volatile struct i2s_control_regs __iomem *controlregs;
-	struct resource rsrc;
 	struct list_head list;
+	struct macio_chip *macio;
 };
 
 #define MAX_DBDMA_COMMANDS	32
@@ -45,6 +47,12 @@
 	volatile struct dbdma_regs __iomem *dbdma;
 };
 
+enum {
+	aoa_resource_i2smmio = 0,
+	aoa_resource_txdbdma,
+	aoa_resource_rxdbdma,
+};
+
 struct i2sbus_dev {
 	struct soundbus_dev sound;
 	struct macio_dev *macio;
Index: linux-irq-work/sound/aoa/soundbus/i2sbus/i2sbus-control.c
===================================================================
--- linux-irq-work.orig/sound/aoa/soundbus/i2sbus/i2sbus-control.c	2006-06-23 13:22:14.000000000 +1000
+++ linux-irq-work/sound/aoa/soundbus/i2sbus/i2sbus-control.c	2006-07-07 15:41:40.000000000 +1000
@@ -6,12 +6,16 @@
  * GPL v2, can be found in COPYING.
  */
 
-#include <asm/io.h>
+#include <linux/kernel.h>
 #include <linux/delay.h>
+
+#include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/macio.h>
 #include <asm/pmac_feature.h>
 #include <asm/pmac_pfunc.h>
+#include <asm/keylargo.h>
+
 #include "i2sbus.h"
 
 int i2sbus_control_init(struct macio_dev* dev, struct i2sbus_control **c)
@@ -22,26 +26,12 @@
 
 	INIT_LIST_HEAD(&(*c)->list);
 
-	if (of_address_to_resource(dev->ofdev.node, 0, &(*c)->rsrc))
-		goto err;
-	/* we really should be using feature calls instead of mapping
-	 * these registers. It's safe for now since no one else is
-	 * touching them... */
-	(*c)->controlregs = ioremap((*c)->rsrc.start,
-				    sizeof(struct i2s_control_regs));
-	if (!(*c)->controlregs)
-		goto err;
-
+	(*c)->macio = dev->bus->chip;
 	return 0;
- err:
-	kfree(*c);
-	*c = NULL;
-	return -ENODEV;
 }
 
 void i2sbus_control_destroy(struct i2sbus_control *c)
 {
-	iounmap(c->controlregs);
 	kfree(c);
 }
 
@@ -93,19 +83,19 @@
 			  struct i2sbus_dev *i2sdev)
 {
 	struct pmf_args args = { .count = 0 };
-	int cc;
+	struct macio_chip *macio = c->macio;
 
 	if (i2sdev->enable)
 		return pmf_call_one(i2sdev->enable, &args);
 
+	if (macio == NULL || macio->base == NULL)
+		return -ENODEV;
 	switch (i2sdev->bus_number) {
 	case 0:
-		cc = in_le32(&c->controlregs->cell_control);
-		out_le32(&c->controlregs->cell_control, cc | CTRL_CLOCK_INTF_0_ENABLE);
+		MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_ENABLE);
 		break;
 	case 1:
-		cc = in_le32(&c->controlregs->cell_control);
-		out_le32(&c->controlregs->cell_control, cc | CTRL_CLOCK_INTF_1_ENABLE);
+		MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_ENABLE);
 		break;
 	default:
 		return -ENODEV;
@@ -118,7 +108,7 @@
 			int enable)
 {
 	struct pmf_args args = { .count = 0 };
-	int cc;
+	struct macio_chip *macio = c->macio;
 
 	switch (enable) {
 	case 0:
@@ -133,18 +123,21 @@
 		printk(KERN_ERR "i2sbus: INVALID CELL ENABLE VALUE\n");
 		return -ENODEV;
 	}
+
+	if (macio == NULL || macio->base == NULL)
+		return -ENODEV;
 	switch (i2sdev->bus_number) {
 	case 0:
-		cc = in_le32(&c->controlregs->cell_control);
-		cc &= ~CTRL_CLOCK_CELL_0_ENABLE;
-		cc |= enable * CTRL_CLOCK_CELL_0_ENABLE;
-		out_le32(&c->controlregs->cell_control, cc);
+		if (enable)
+			MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE);
+		else
+			MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE);
 		break;
 	case 1:
-		cc = in_le32(&c->controlregs->cell_control);
-		cc &= ~CTRL_CLOCK_CELL_1_ENABLE;
-		cc |= enable * CTRL_CLOCK_CELL_1_ENABLE;
-		out_le32(&c->controlregs->cell_control, cc);
+		if (enable)
+			MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_CELL_ENABLE);
+		else
+			MACIO_BIC(KEYLARGO_FCR1, KL1_I2S1_CELL_ENABLE);
 		break;
 	default:
 		return -ENODEV;
@@ -157,7 +150,7 @@
 			 int enable)
 {
 	struct pmf_args args = { .count = 0 };
-	int cc;
+	struct macio_chip *macio = c->macio;
 
 	switch (enable) {
 	case 0:
@@ -172,18 +165,20 @@
 		printk(KERN_ERR "i2sbus: INVALID CLOCK ENABLE VALUE\n");
 		return -ENODEV;
 	}
+	if (macio == NULL || macio->base == NULL)
+		return -ENODEV;
 	switch (i2sdev->bus_number) {
 	case 0:
-		cc = in_le32(&c->controlregs->cell_control);
-		cc &= ~CTRL_CLOCK_CLOCK_0_ENABLE;
-		cc |= enable * CTRL_CLOCK_CLOCK_0_ENABLE;
-		out_le32(&c->controlregs->cell_control, cc);
+		if (enable)
+			MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT);
+		else
+			MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT);
 		break;
 	case 1:
-		cc = in_le32(&c->controlregs->cell_control);
-		cc &= ~CTRL_CLOCK_CLOCK_1_ENABLE;
-		cc |= enable * CTRL_CLOCK_CLOCK_1_ENABLE;
-		out_le32(&c->controlregs->cell_control, cc);
+		if (enable)
+			MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_CLK_ENABLE_BIT);
+		else
+			MACIO_BIC(KEYLARGO_FCR1, KL1_I2S1_CLK_ENABLE_BIT);
 		break;
 	default:
 		return -ENODEV;
Index: linux-irq-work/sound/aoa/soundbus/i2sbus/i2sbus-control.h
===================================================================
--- linux-irq-work.orig/sound/aoa/soundbus/i2sbus/i2sbus-control.h	2006-06-23 13:22:14.000000000 +1000
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,37 +0,0 @@
-/*
- * i2sbus driver -- bus register definitions
- *
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
- *
- * GPL v2, can be found in COPYING.
- */
-#ifndef __I2SBUS_CONTROLREGS_H
-#define __I2SBUS_CONTROLREGS_H
-
-/* i2s control registers, at least what we know about them */
-
-#define __PAD(m,n) u8 __pad##m[n]
-#define _PAD(line, n) __PAD(line, n)
-#define PAD(n) _PAD(__LINE__, (n))
-struct i2s_control_regs {
-	PAD(0x38);
-	__le32 fcr0;		/* 0x38 (unknown) */
-	__le32 cell_control;	/* 0x3c (fcr1) */
-	__le32 fcr2;		/* 0x40 (unknown) */
-	__le32 fcr3;		/* 0x44 (fcr3) */
-	__le32 clock_control;	/* 0x48 (unknown) */
-	PAD(4);
-	/* total size: 0x50 bytes */
-}  __attribute__((__packed__));
-
-#define CTRL_CLOCK_CELL_0_ENABLE	(1<<10)
-#define CTRL_CLOCK_CLOCK_0_ENABLE	(1<<12)
-#define CTRL_CLOCK_SWRESET_0		(1<<11)
-#define CTRL_CLOCK_INTF_0_ENABLE	(1<<13)
-
-#define CTRL_CLOCK_CELL_1_ENABLE	(1<<17)
-#define CTRL_CLOCK_CLOCK_1_ENABLE	(1<<18)
-#define CTRL_CLOCK_SWRESET_1		(1<<19)
-#define CTRL_CLOCK_INTF_1_ENABLE	(1<<20)
-
-#endif /* __I2SBUS_CONTROLREGS_H */
Index: linux-irq-work/sound/aoa/codecs/snd-aoa-codec-tas.c
===================================================================
--- linux-irq-work.orig/sound/aoa/codecs/snd-aoa-codec-tas.c	2006-06-23 13:22:14.000000000 +1000
+++ linux-irq-work/sound/aoa/codecs/snd-aoa-codec-tas.c	2006-07-07 17:49:19.000000000 +1000
@@ -310,6 +310,7 @@
 }
 
 MIXER_CONTROL(pcm1, "PCM1", 0);
+MIXER_CONTROL(pcm2, "PCM2", 1);
 MIXER_CONTROL(monitor, "Monitor", 2);
 
 static int tas_snd_capture_source_info(struct snd_kcontrol *kcontrol,
@@ -507,6 +508,10 @@
 	if (err)
 		goto error;
 
+	err = aoa_snd_ctl_add(snd_ctl_new1(&pcm2_control, tas));
+	if (err)
+		goto error;
+
 	err = aoa_snd_ctl_add(snd_ctl_new1(&monitor_control, tas));
 	if (err)
 		goto error;

^ permalink raw reply

* Re: snd-aoa: g5 tas codec problems
From: Johannes Berg @ 2006-07-07  8:03 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list, alsa-devel
In-Reply-To: <1152258426.9862.44.camel@localhost.localdomain>

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

On Fri, 2006-07-07 at 17:47 +1000, Benjamin Herrenschmidt wrote:
> Ok, so now I have it working on the G5 :)

Great :)
Powerbook woke itself an hour ago, no idea why, sorry for confusing you
on irc.

>  - Maybe it's me or maybe it's just too complicated, but I haven't quite
> grasped the whole interaction between the soundbus,i2sbus,fabric and
> codecs... especially initialisation ordering. It would be nice if we
> could spend some time going through that and simplifying :) It leads to
> at least one of the problems

Yeah, well... I sorta know.

>  - The patch fixes a couple of nits related to having the modules
> built-in: soundbus must really be a subsys_initcall() so it's
> initialized before anybody else, and I've put the soundbus/ dir before
> the codecs in the link order because the TAS is unhappy if loaded before
> i2s (see below)

Right.

>  - The TAS is a nasty beast. It needs the i2s clocks enabled or it goes
> bunk... That's the problem with the G5. I've added a clock notifier and
> reset it completely when the clocks come back, that's what fixes the G5
> sound (looks like it loses state somewhat when not clocked). It would be
> nice to streamline/cleanup some of the TAS handling, maybe with register
> shadows like darwin or just with proper state variables to re-consitute
> the whole thing and have a "fast mode" load since we need to do it so
> often

Ahrg

>  - Because of the above, starting to play a sound 1- takes some time to
> init things and 2- clacks (setting the mutes on TAS before losing clocks
> isn't enough, I think the fact that it goes bonk makes it parasite the
> analog outputs). We need to also mute the amps around that. I haven't
> quite figured how to do that from i2sbus though :) Also, we should try
> (if not already the case) to cache our clock/i2s state so that
> subsequent prepare() don't try to change things that are already ok.
> That way we avoid having to blast the codec each time. But right now,
> the important thing is to add mutes. People with external amplifiers
> will really not like those clacs...

Right. The way I did that with the onyx is that I told the GPIOs to mute
all amps from the clock switch callback.

I see you added DRC too, thanks :) I'll take a closer look after
breakfast ;)

johannes

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

^ permalink raw reply

* Re: [Alsa-devel] [RFC 01/12] snd-powermac: no longer handle anything with a layout-id property
From: Johannes Berg @ 2006-07-07  8:04 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: alsa-devel, Takashi Iwai, netstar, linuxppc-dev, Lee Revell
In-Reply-To: <1152250720.9862.32.camel@localhost.localdomain>

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

On Fri, 2006-07-07 at 15:38 +1000, Benjamin Herrenschmidt wrote:

> There is still an issue... wether to enable softvol or not... With
> snd-aoa, the card name is always the same but wether it has hardware
> volume control or not (Toonie doesn't) is not known... Alsa should have
> ways to add softvol automatically if no master volume control exist.

Hm, good point. I probably need to completely revamp the card handling
and not create a card object before the codecs are registered. That way,
I could influence the naming through the codecs.

johannes

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

^ permalink raw reply

* Re: snd-aoa: g5 tas codec problems
From: Benjamin Herrenschmidt @ 2006-07-07  8:12 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linuxppc-dev list, alsa-devel
In-Reply-To: <1152259414.15068.12.camel@localhost>


> I see you added DRC too, thanks :) I'll take a closer look after
> breakfast ;)

Hehe :) Oh I just added a routine to program it in hardware, not any
control to actually change it.

Ben.

^ permalink raw reply

* Re: [Alsa-devel] [RFC 01/12] snd-powermac: no longer handle anything with a layout-id property
From: Benjamin Herrenschmidt @ 2006-07-07  8:13 UTC (permalink / raw)
  To: Johannes Berg; +Cc: alsa-devel, Takashi Iwai, netstar, linuxppc-dev, Lee Revell
In-Reply-To: <1152259477.15068.15.camel@localhost>

On Fri, 2006-07-07 at 10:04 +0200, Johannes Berg wrote:
> On Fri, 2006-07-07 at 15:38 +1000, Benjamin Herrenschmidt wrote:
> 
> > There is still an issue... wether to enable softvol or not... With
> > snd-aoa, the card name is always the same but wether it has hardware
> > volume control or not (Toonie doesn't) is not known... Alsa should have
> > ways to add softvol automatically if no master volume control exist.
> 
> Hm, good point. I probably need to completely revamp the card handling
> and not create a card object before the codecs are registered. That way,
> I could influence the naming through the codecs.

Maybe ... or not... I'd rather not bother. I think Alsa should be able
to create softvol if there is no Master volume...

Ben.

^ permalink raw reply

* Re: [Alsa-devel] [RFC 01/12] snd-powermac: no longer handle anything with a layout-id property
From: Johannes Berg @ 2006-07-07  8:22 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: alsa-devel, Takashi Iwai, netstar, linuxppc-dev, Lee Revell
In-Reply-To: <1152260005.9862.53.camel@localhost.localdomain>

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

On Fri, 2006-07-07 at 18:13 +1000, Benjamin Herrenschmidt wrote:

> Maybe ... or not... I'd rather not bother. I think Alsa should be able
> to create softvol if there is no Master volume...

But how long should it wait for the master volume to become available?
Thing is, as far as I understand this, the mixer is dynamic and you can
add and remove things at any time essentially. No one does, but that's
another story.

johannes

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

^ permalink raw reply

* Re: G5 troubles booting powerpc-git (July 6)
From: Andrew Morton @ 2006-07-07  8:23 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1152226587.9862.19.camel@localhost.localdomain>

On Fri, 07 Jul 2006 08:56:27 +1000
Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:

> If you look at arch/powerpc/kernel/irq.c from line 479:
> 
> 	/* Check if mapping already exist, if it does, call
> 	 * host->ops->map() to update the flags
> 	 */
> 	virq = irq_find_mapping(host, hwirq);
> 	if (virq != IRQ_NONE) {
> 		pr_debug("irq: -> existing mapping on virq %d\n", virq);
> 		host->ops->map(host, virq, hwirq, flags);
> 		return virq;
> 	}
> 
> What if you comment out the host->ops->map(...) call in there ? Does it
> help ?

No, there's no change in behaviour.

^ permalink raw reply

* Re: G5 troubles booting powerpc-git (July 6)
From: Benjamin Herrenschmidt @ 2006-07-07  8:27 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linuxppc-dev
In-Reply-To: <20060707012330.f1dea5ac.akpm@osdl.org>

On Fri, 2006-07-07 at 01:23 -0700, Andrew Morton wrote:
> On Fri, 07 Jul 2006 08:56:27 +1000
> Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
> 
> > If you look at arch/powerpc/kernel/irq.c from line 479:
> > 
> > 	/* Check if mapping already exist, if it does, call
> > 	 * host->ops->map() to update the flags
> > 	 */
> > 	virq = irq_find_mapping(host, hwirq);
> > 	if (virq != IRQ_NONE) {
> > 		pr_debug("irq: -> existing mapping on virq %d\n", virq);
> > 		host->ops->map(host, virq, hwirq, flags);
> > 		return virq;
> > 	}
> > 
> > What if you comment out the host->ops->map(...) call in there ? Does it
> > help ?
> 
> No, there's no change in behaviour.

Doh ! Ok, looks like a different issue. Can you try this patch ? Please,
do _not_ apply it to your tree as, as it is it will break non-powermac.
It's some work I'm doing to clean up a couple of rough edges in my irq
rework and fix a little misdesign.

If it doesn't fix it, then it's indeed a completely different issue that I'll have to track down tomorrow
hopefully.

Index: linux-irq-work/arch/powerpc/kernel/irq.c
===================================================================
--- linux-irq-work.orig/arch/powerpc/kernel/irq.c	2006-07-07 15:40:27.000000000 +1000
+++ linux-irq-work/arch/powerpc/kernel/irq.c	2006-07-07 15:47:23.000000000 +1000
@@ -391,15 +391,14 @@
 			irq_map[i].host = host;
 			smp_wmb();
 
-			/* Clear some flags */
-			get_irq_desc(i)->status
-				&= ~(IRQ_NOREQUEST | IRQ_LEVEL);
+			/* Clear norequest flags */
+			get_irq_desc(i)->status &= ~IRQ_NOREQUEST;
 
 			/* Legacy flags are left to default at this point,
 			 * one can then use irq_create_mapping() to
 			 * explicitely change them
 			 */
-			ops->map(host, i, i, 0);
+			ops->map(host, i, i);
 		}
 		break;
 	case IRQ_HOST_MAP_LINEAR:
@@ -457,13 +456,11 @@
 }
 
 unsigned int irq_create_mapping(struct irq_host *host,
-				irq_hw_number_t hwirq,
-				unsigned int flags)
+				irq_hw_number_t hwirq)
 {
 	unsigned int virq, hint;
 
-	pr_debug("irq: irq_create_mapping(0x%p, 0x%lx, 0x%x)\n",
-		 host, hwirq, flags);
+	pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq);
 
 	/* Look for default host if nececssary */
 	if (host == NULL)
@@ -482,7 +479,6 @@
 	virq = irq_find_mapping(host, hwirq);
 	if (virq != IRQ_NONE) {
 		pr_debug("irq: -> existing mapping on virq %d\n", virq);
-		host->ops->map(host, virq, hwirq, flags);
 		return virq;
 	}
 
@@ -504,18 +500,18 @@
 	}
 	pr_debug("irq: -> obtained virq %d\n", virq);
 
-	/* Clear some flags */
-	get_irq_desc(virq)->status &= ~(IRQ_NOREQUEST | IRQ_LEVEL);
+	/* Clear IRQ_NOREQUEST flag */
+	get_irq_desc(virq)->status &= ~IRQ_NOREQUEST;
 
 	/* map it */
-	if (host->ops->map(host, virq, hwirq, flags)) {
+	smp_wmb();
+	irq_map[virq].hwirq = hwirq;
+	smp_mb();
+	if (host->ops->map(host, virq, hwirq)) {
 		pr_debug("irq: -> mapping failed, freeing\n");
 		irq_free_virt(virq, 1);
 		return NO_IRQ;
 	}
-	smp_wmb();
-	irq_map[virq].hwirq = hwirq;
-	smp_mb();
 	return virq;
 }
 EXPORT_SYMBOL_GPL(irq_create_mapping);
@@ -525,7 +521,8 @@
 {
 	struct irq_host *host;
 	irq_hw_number_t hwirq;
-	unsigned int flags = IRQ_TYPE_NONE;
+	unsigned int type = IRQ_TYPE_NONE;
+	unsigned int virq;
 
 	if (controller == NULL)
 		host = irq_default_host;
@@ -539,11 +536,20 @@
 		hwirq = intspec[0];
 	else {
 		if (host->ops->xlate(host, controller, intspec, intsize,
-				     &hwirq, &flags))
+				     &hwirq, &type))
 			return NO_IRQ;
 	}
 
-	return irq_create_mapping(host, hwirq, flags);
+	/* Create mapping */
+	virq = irq_create_mapping(host, hwirq);
+	if (virq == NO_IRQ)
+		return virq;
+
+	/* Set type if specified and different than the current one */
+	if (type != IRQ_TYPE_NONE &&
+	    type != (get_irq_desc(virq)->status & IRQF_TRIGGER_MASK))
+		set_irq_type(virq, type);
+	return virq;
 }
 EXPORT_SYMBOL_GPL(irq_create_of_mapping);
 
Index: linux-irq-work/arch/powerpc/platforms/powermac/pci.c
===================================================================
--- linux-irq-work.orig/arch/powerpc/platforms/powermac/pci.c	2006-07-07 15:40:27.000000000 +1000
+++ linux-irq-work/arch/powerpc/platforms/powermac/pci.c	2006-07-07 15:47:23.000000000 +1000
@@ -46,7 +46,6 @@
 static struct pci_controller *u3_agp;
 static struct pci_controller *u4_pcie;
 static struct pci_controller *u3_ht;
-#define has_second_ohare 0
 #else
 static int has_second_ohare;
 #endif /* CONFIG_PPC64 */
@@ -993,6 +992,7 @@
 		/* Read interrupt from the device-tree */
 		pci_read_irq_line(dev);
 
+#ifdef CONFIG_PPC32
 		/* Fixup interrupt for the modem/ethernet combo controller.
 		 * on machines with a second ohare chip.
 		 * The number in the device tree (27) is bogus (correct for
@@ -1002,8 +1002,11 @@
 		 */
 		if (has_second_ohare &&
 		    dev->vendor == PCI_VENDOR_ID_DEC &&
-		    dev->device == PCI_DEVICE_ID_DEC_TULIP_PLUS)
-			dev->irq = irq_create_mapping(NULL, 60, 0);
+		    dev->device == PCI_DEVICE_ID_DEC_TULIP_PLUS) {
+			dev->irq = irq_create_mapping(NULL, 60);
+			set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW);
+		}
+#endif /* CONFIG_PPC32 */
 	}
 }
 
Index: linux-irq-work/arch/powerpc/platforms/powermac/pic.c
===================================================================
--- linux-irq-work.orig/arch/powerpc/platforms/powermac/pic.c	2006-07-07 15:40:27.000000000 +1000
+++ linux-irq-work/arch/powerpc/platforms/powermac/pic.c	2006-07-07 15:47:23.000000000 +1000
@@ -579,9 +579,10 @@
 		flags |= OF_IMAP_OLDWORLD_MAC;
 	if (get_property(of_chosen, "linux,bootx", NULL) != NULL)
 		flags |= OF_IMAP_NO_PHANDLE;
-	of_irq_map_init(flags);
 #endif /* CONFIG_PPC_32 */
 
+	of_irq_map_init(flags);
+
 	/* We first try to detect Apple's new Core99 chipset, since mac-io
 	 * is quite different on those machines and contains an IBM MPIC2.
 	 */
Index: linux-irq-work/arch/powerpc/sysdev/mpic.c
===================================================================
--- linux-irq-work.orig/arch/powerpc/sysdev/mpic.c	2006-07-07 15:40:27.000000000 +1000
+++ linux-irq-work/arch/powerpc/sysdev/mpic.c	2006-07-07 15:47:23.000000000 +1000
@@ -337,6 +337,17 @@
 	}
 }
 
+#else /* CONFIG_MPIC_BROKEN_U3 */
+
+static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source)
+{
+	return 0;
+}
+
+static void __init mpic_scan_ht_pics(struct mpic *mpic)
+{
+}
+
 #endif /* CONFIG_MPIC_BROKEN_U3 */
 
 
@@ -405,11 +416,9 @@
 	unsigned int loops = 100000;
 	struct mpic *mpic = mpic_from_irq(irq);
 	unsigned int src = mpic_irq_to_hw(irq);
-	unsigned long flags;
 
 	DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);
 
-	spin_lock_irqsave(&mpic_lock, flags);
 	mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
 		       mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
 		       ~MPIC_VECPRI_MASK);
@@ -420,7 +429,6 @@
 			break;
 		}
 	} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
-	spin_unlock_irqrestore(&mpic_lock, flags);
 }
 
 static void mpic_mask_irq(unsigned int irq)
@@ -428,11 +436,9 @@
 	unsigned int loops = 100000;
 	struct mpic *mpic = mpic_from_irq(irq);
 	unsigned int src = mpic_irq_to_hw(irq);
-	unsigned long flags;
 
 	DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
 
-	spin_lock_irqsave(&mpic_lock, flags);
 	mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
 		       mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
 		       MPIC_VECPRI_MASK);
@@ -444,7 +450,6 @@
 			break;
 		}
 	} while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
-	spin_unlock_irqrestore(&mpic_lock, flags);
 }
 
 static void mpic_end_irq(unsigned int irq)
@@ -512,8 +517,7 @@
 		mpic_ht_end_irq(mpic, src);
 	mpic_eoi(mpic);
 }
-
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* !CONFIG_MPIC_BROKEN_U3 */
 
 #ifdef CONFIG_SMP
 
@@ -560,47 +564,74 @@
 		       mpic_physmask(cpus_addr(tmp)[0]));	
 }
 
-static unsigned int mpic_flags_to_vecpri(unsigned int flags, int *level)
+static unsigned int mpic_type_to_vecpri(unsigned int type)
 {
-	unsigned int vecpri;
-
 	/* Now convert sense value */
-	switch(flags & IRQ_TYPE_SENSE_MASK) {
+	switch(type & IRQ_TYPE_SENSE_MASK) {
 	case IRQ_TYPE_EDGE_RISING:
-		vecpri = MPIC_VECPRI_SENSE_EDGE |
-			MPIC_VECPRI_POLARITY_POSITIVE;
-		*level = 0;
-		break;
+		return MPIC_VECPRI_SENSE_EDGE | MPIC_VECPRI_POLARITY_POSITIVE;
 	case IRQ_TYPE_EDGE_FALLING:
-		vecpri = MPIC_VECPRI_SENSE_EDGE |
-			MPIC_VECPRI_POLARITY_NEGATIVE;
-		*level = 0;
-		break;
+	case IRQ_TYPE_EDGE_BOTH:
+		return MPIC_VECPRI_SENSE_EDGE | MPIC_VECPRI_POLARITY_NEGATIVE;
 	case IRQ_TYPE_LEVEL_HIGH:
-		vecpri = MPIC_VECPRI_SENSE_LEVEL |
-			MPIC_VECPRI_POLARITY_POSITIVE;
-		*level = 1;
-		break;
+		return MPIC_VECPRI_SENSE_LEVEL | MPIC_VECPRI_POLARITY_POSITIVE;
 	case IRQ_TYPE_LEVEL_LOW:
 	default:
-		vecpri = MPIC_VECPRI_SENSE_LEVEL |
-			MPIC_VECPRI_POLARITY_NEGATIVE;
-		*level = 1;
+		return MPIC_VECPRI_SENSE_LEVEL | MPIC_VECPRI_POLARITY_NEGATIVE;
 	}
-	return vecpri;
+}
+
+static int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
+{
+	struct mpic *mpic = mpic_from_irq(virq);
+	unsigned int src = mpic_irq_to_hw(virq);
+	struct irq_desc *desc = get_irq_desc(virq);
+	unsigned int vecpri, vold, vnew;
+
+	pr_debug("mpic: set_irq_type(mpic:@%p,virq:%d,src:%d,type:0x%x)\n",
+		 mpic, virq, src, flow_type);
+
+	if (src >= mpic->irq_count)
+		return -EINVAL;
+
+	if (flow_type == IRQ_TYPE_NONE)
+		if (mpic->senses && src < mpic->senses_count)
+			flow_type = mpic->senses[src];
+	if (flow_type == IRQ_TYPE_NONE)
+		flow_type = IRQ_TYPE_LEVEL_LOW;
+
+	desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
+	desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
+	if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
+		desc->status |= IRQ_LEVEL;
+
+	if (mpic_is_ht_interrupt(mpic, src))
+		vecpri = MPIC_VECPRI_POLARITY_POSITIVE |
+			MPIC_VECPRI_SENSE_EDGE;
+	else
+		vecpri = mpic_type_to_vecpri(flow_type);
+
+	vold = mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI);
+	vnew = vold & ~(MPIC_VECPRI_POLARITY_MASK | MPIC_VECPRI_SENSE_MASK);
+	vnew |= vecpri;
+	if (vold != vnew)
+		mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, vnew);
+
+	return 0;
 }
 
 static struct irq_chip mpic_irq_chip = {
-	.mask	= mpic_mask_irq,
-	.unmask	= mpic_unmask_irq,
-	.eoi	= mpic_end_irq,
+	.mask		= mpic_mask_irq,
+	.unmask		= mpic_unmask_irq,
+	.eoi		= mpic_end_irq,
+	.set_type	= mpic_set_irq_type,
 };
 
 #ifdef CONFIG_SMP
 static struct irq_chip mpic_ipi_chip = {
-	.mask	= mpic_mask_ipi,
-	.unmask	= mpic_unmask_ipi,
-	.eoi	= mpic_end_ipi,
+	.mask		= mpic_mask_ipi,
+	.unmask		= mpic_unmask_ipi,
+	.eoi		= mpic_end_ipi,
 };
 #endif /* CONFIG_SMP */
 
@@ -611,6 +642,7 @@
 	.mask		= mpic_mask_irq,
 	.unmask		= mpic_unmask_ht_irq,
 	.eoi		= mpic_end_ht_irq,
+	.set_type	= mpic_set_irq_type,
 };
 #endif /* CONFIG_MPIC_BROKEN_U3 */
 
@@ -624,18 +656,12 @@
 }
 
 static int mpic_host_map(struct irq_host *h, unsigned int virq,
-			 irq_hw_number_t hw, unsigned int flags)
+			 irq_hw_number_t hw)
 {
-	struct irq_desc *desc = get_irq_desc(virq);
-	struct irq_chip *chip;
 	struct mpic *mpic = h->host_data;
-	u32 v, vecpri = MPIC_VECPRI_SENSE_LEVEL |
-		MPIC_VECPRI_POLARITY_NEGATIVE;
-	int level;
-	unsigned long iflags;
+	struct irq_chip *chip;
 
-	pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n",
-		 virq, hw, flags);
+	pr_debug("mpic: map virq %d, hwirq 0x%lx\n", virq, hw);
 
 	if (hw == MPIC_VEC_SPURRIOUS)
 		return -EINVAL;
@@ -654,44 +680,23 @@
 	if (hw >= mpic->irq_count)
 		return -EINVAL;
 
-	/* If no sense provided, check default sense array */
-	if (((flags & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_NONE) &&
-	    mpic->senses && hw < mpic->senses_count)
-		flags |= mpic->senses[hw];
-
-	vecpri = mpic_flags_to_vecpri(flags, &level);
-	if (level)
-		desc->status |= IRQ_LEVEL;
+	/* Default chip */
 	chip = &mpic->hc_irq;
 
 #ifdef CONFIG_MPIC_BROKEN_U3
 	/* Check for HT interrupts, override vecpri */
-	if (mpic_is_ht_interrupt(mpic, hw)) {
-		vecpri &= ~(MPIC_VECPRI_SENSE_MASK |
-			    MPIC_VECPRI_POLARITY_MASK);
-		vecpri |= MPIC_VECPRI_POLARITY_POSITIVE;
+	if (mpic_is_ht_interrupt(mpic, hw))
 		chip = &mpic->hc_ht_irq;
-	}
-#endif
-
-	/* Reconfigure irq. We must preserve the mask bit as we can be called
-	 * while the interrupt is still active (This may change in the future
-	 * but for now, it is the case).
-	 */
-	spin_lock_irqsave(&mpic_lock, iflags);
-	v = mpic_irq_read(hw, MPIC_IRQ_VECTOR_PRI);
-	vecpri = (v &
-		~(MPIC_VECPRI_POLARITY_MASK | MPIC_VECPRI_SENSE_MASK)) |
-		vecpri;
-	if (vecpri != v)
-		mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri);
-	spin_unlock_irqrestore(&mpic_lock, iflags);
+#endif /* CONFIG_MPIC_BROKEN_U3 */
 
-	pr_debug("mpic: mapping as IRQ, vecpri = 0x%08x (was 0x%08x)\n",
-		 vecpri, v);
+	pr_debug("mpic: mapping to irq chip @%p\n", chip);
 
 	set_irq_chip_data(virq, mpic);
 	set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq);
+
+	/* Set default irq type */
+	set_irq_type(virq, IRQ_TYPE_NONE);
+
 	return 0;
 }
 
@@ -906,41 +911,16 @@
 	if (mpic->irq_count == 0)
 		mpic->irq_count = mpic->num_sources;
 
-#ifdef CONFIG_MPIC_BROKEN_U3
 	/* Do the HT PIC fixups on U3 broken mpic */
 	DBG("MPIC flags: %x\n", mpic->flags);
 	if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
  		mpic_scan_ht_pics(mpic);
-#endif /* CONFIG_MPIC_BROKEN_U3 */
 
 	for (i = 0; i < mpic->num_sources; i++) {
 		/* start with vector = source number, and masked */
-		u32 vecpri = MPIC_VECPRI_MASK | i | (8 << MPIC_VECPRI_PRIORITY_SHIFT);
-		int level = 1;
+		u32 vecpri = MPIC_VECPRI_MASK | i |
+			(8 << MPIC_VECPRI_PRIORITY_SHIFT);
 		
-		/* do senses munging */
-		if (mpic->senses && i < mpic->senses_count)
-			vecpri |= mpic_flags_to_vecpri(mpic->senses[i],
-						       &level);
-		else
-			vecpri |= MPIC_VECPRI_SENSE_LEVEL;
-
-		/* deal with broken U3 */
-		if (mpic->flags & MPIC_BROKEN_U3) {
-#ifdef CONFIG_MPIC_BROKEN_U3
-			if (mpic_is_ht_interrupt(mpic, i)) {
-				vecpri &= ~(MPIC_VECPRI_SENSE_MASK |
-					    MPIC_VECPRI_POLARITY_MASK);
-				vecpri |= MPIC_VECPRI_POLARITY_POSITIVE;
-			}
-#else
-			printk(KERN_ERR "mpic: BROKEN_U3 set, but CONFIG doesn't match\n");
-#endif
-		}
-
-		DBG("setup source %d, vecpri: %08x, level: %d\n", i, vecpri,
-		    (level != 0));
-
 		/* init hw */
 		mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri);
 		mpic_irq_write(i, MPIC_IRQ_DESTINATION,
@@ -1154,7 +1134,7 @@
 
 	for (i = 0; i < 4; i++) {
 		unsigned int vipi = irq_create_mapping(mpic->irqhost,
-						       MPIC_VEC_IPI_0 + i, 0);
+						       MPIC_VEC_IPI_0 + i);
 		if (vipi == NO_IRQ) {
 			printk(KERN_ERR "Failed to map IPI %d\n", i);
 			break;
Index: linux-irq-work/drivers/macintosh/macio_asic.c
===================================================================
--- linux-irq-work.orig/drivers/macintosh/macio_asic.c	2006-07-07 15:40:27.000000000 +1000
+++ linux-irq-work/drivers/macintosh/macio_asic.c	2006-07-07 15:47:23.000000000 +1000
@@ -330,7 +330,7 @@
 {
 	unsigned int irq;
 
-	irq = irq_create_mapping(NULL, line, 0);
+	irq = irq_create_mapping(NULL, line);
 	if (irq != NO_IRQ) {
 		dev->interrupt[index].start = irq;
 		dev->interrupt[index].flags = IORESOURCE_IRQ;
Index: linux-irq-work/include/asm-powerpc/irq.h
===================================================================
--- linux-irq-work.orig/include/asm-powerpc/irq.h	2006-07-07 15:40:27.000000000 +1000
+++ linux-irq-work/include/asm-powerpc/irq.h	2006-07-07 15:47:23.000000000 +1000
@@ -83,25 +83,24 @@
 	int (*match)(struct irq_host *h, struct device_node *node);
 
 	/* Create or update a mapping between a virtual irq number and a hw
-	 * irq number. This can be called several times for the same mapping
-	 * but with different flags, though unmap shall always be called
-	 * before the virq->hw mapping is changed.
+	 * irq number. This is called only once for a given mapping.
 	 */
-	int (*map)(struct irq_host *h, unsigned int virq,
-		   irq_hw_number_t hw, unsigned int flags);
+	int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw);
 
 	/* Dispose of such a mapping */
 	void (*unmap)(struct irq_host *h, unsigned int virq);
 
 	/* Translate device-tree interrupt specifier from raw format coming
 	 * from the firmware to a irq_hw_number_t (interrupt line number) and
-	 * trigger flags that can be passed to irq_create_mapping().
-	 * If no translation is provided, raw format is assumed to be one cell
-	 * for interrupt line and default sense.
+	 * type (sense) that can be passed to set_irq_type(). In the absence
+	 * of this callback, irq_create_of_mapping() and irq_of_parse_and_map()
+	 * will return the hw number in the first cell and IRQ_TYPE_NONE for
+	 * the type (which amount to keeping whatever default value the
+	 * interrupt controller has for that line)
 	 */
 	int (*xlate)(struct irq_host *h, struct device_node *ctrler,
 		     u32 *intspec, unsigned int intsize,
-		     irq_hw_number_t *out_hwirq, unsigned int *out_flags);
+		     irq_hw_number_t *out_hwirq, unsigned int *out_type);
 };
 
 struct irq_host {
@@ -193,25 +192,14 @@
  * irq_create_mapping - Map a hardware interrupt into linux virq space
  * @host: host owning this hardware interrupt or NULL for default host
  * @hwirq: hardware irq number in that host space
- * @flags: flags passed to the controller. contains the trigger type among
- *         others. Use IRQ_TYPE_* defined in include/linux/irq.h
  *
  * Only one mapping per hardware interrupt is permitted. Returns a linux
- * virq number. The flags can be used to provide sense information to the
- * controller (typically extracted from the device-tree). If no information
- * is passed, the controller defaults will apply (for example, xics can only
- * do edge so flags are irrelevant for some pseries specific irqs).
- *
- * The device-tree generally contains the trigger info in an encoding that is
- * specific to a given type of controller. In that case, you can directly use
- * host->ops->trigger_xlate() to translate that.
- *
- * It is recommended that new PICs that don't have existing OF bindings chose
- * to use a representation of triggers identical to linux.
+ * virq number.
+ * If the sense/trigger is to be specified, set_irq_type() should be called
+ * on the number returned from that call.
  */
 extern unsigned int irq_create_mapping(struct irq_host *host,
-				       irq_hw_number_t hwirq,
-				       unsigned int flags);
+				       irq_hw_number_t hwirq);
 
 
 /***
@@ -295,7 +283,7 @@
  *
  * This function is identical to irq_create_mapping except that it takes
  * as input informations straight from the device-tree (typically the results
- * of the of_irq_map_*() functions
+ * of the of_irq_map_*() functions.
  */
 extern unsigned int irq_create_of_mapping(struct device_node *controller,
 					  u32 *intspec, unsigned int intsize);

^ permalink raw reply

* Re: [Alsa-devel] [RFC 01/12] snd-powermac: no longer handle anything with a layout-id property
From: Benjamin Herrenschmidt @ 2006-07-07  8:27 UTC (permalink / raw)
  To: Johannes Berg; +Cc: alsa-devel, Takashi Iwai, netstar, linuxppc-dev, Lee Revell
In-Reply-To: <1152260564.15068.20.camel@localhost>

On Fri, 2006-07-07 at 10:22 +0200, Johannes Berg wrote:
> On Fri, 2006-07-07 at 18:13 +1000, Benjamin Herrenschmidt wrote:
> 
> > Maybe ... or not... I'd rather not bother. I think Alsa should be able
> > to create softvol if there is no Master volume...
> 
> But how long should it wait for the master volume to become available?
> Thing is, as far as I understand this, the mixer is dynamic and you can
> add and remove things at any time essentially. No one does, but that's
> another story.

Well, when the master volume shows up, softvol can "unplug" itself :)

Ben.

^ permalink raw reply

* Re: [Alsa-devel] [RFC 01/12] snd-powermac: no longer handle anything with a layout-id property
From: Johannes Berg @ 2006-07-07  8:40 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: alsa-devel, Takashi Iwai, netstar, linuxppc-dev, Lee Revell
In-Reply-To: <1152260861.9862.59.camel@localhost.localdomain>

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

On Fri, 2006-07-07 at 18:27 +1000, Benjamin Herrenschmidt wrote:

> Well, when the master volume shows up, softvol can "unplug" itself :)

Hmm, not a bad idea, that way there's always a master volume. And when
some cards have an unusable master volume then softvol could be forced
to superimpose via the config file.

johannes

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

^ 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