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

* [PATCH 3/3] Freescale QE UCC gigabit ethernet driver
From: Li Yang-r58472 @ 2006-07-06 12:02 UTC (permalink / raw)
  To: Andrew Morton, jgarzik; +Cc: netdev, linuxppc-dev

Continues [PATCH 2/3] Freescale QE UCC gigabit ethernet driver

---
+
+static int ucc_geth_remove(struct device *device)
+{
+	struct net_device *dev =3D dev_get_drvdata(device);
+	struct ucc_geth_private *ugeth =3D netdev_priv(dev);
+
+	dev_set_drvdata(device, NULL);
+	ucc_geth_memclean(ugeth);
+	free_netdev(dev);
+
+	return 0;
+}
+
+/* Structure for a device driver */
+static struct device_driver ucc_geth_driver =3D {
+	.name =3D DRV_NAME,
+	.bus =3D &platform_bus_type,
+	.probe =3D ucc_geth_probe,
+	.remove =3D ucc_geth_remove,
+};
+
+static int __init ucc_geth_init(void)
+{
+	int i;
+	printk(KERN_INFO "ucc_geth: " DRV_DESC "\n");
+	for (i =3D 0; i < 8; i++)
+		memcpy(&(ugeth_info[i]), &ugeth_primary_info,
+		       sizeof(ugeth_primary_info));
+
+	return driver_register(&ucc_geth_driver);
+}
+
+static void __exit ucc_geth_exit(void)
+{
+	driver_unregister(&ucc_geth_driver);
+}
+
+module_init(ucc_geth_init);
+module_exit(ucc_geth_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc");
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
new file mode 100644
index 0000000..6eafd95
--- /dev/null
+++ b/drivers/net/ucc_geth.h
@@ -0,0 +1,1334 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights
reserved.
+ *
+ * Author: Shlomi Gridish <gridish@freescale.com>
+ *
+ * Description:
+ * Internal header file for UCC Gigabit Ethernet unit routines.
+ *
+ * Changelog:
+ * Jun 28, 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.
+ */
+#ifndef __UCC_GETH_H__
+#define __UCC_GETH_H__
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+
+#include <asm/ucc.h>
+#include <asm/ucc_fast.h>
+
+#define NUM_TX_QUEUES                   8
+#define NUM_RX_QUEUES                   8
+#define NUM_BDS_IN_PREFETCHED_BDS       4
+#define TX_IP_OFFSET_ENTRY_MAX          8
+#define NUM_OF_PADDRS                   4
+#define ENET_INIT_PARAM_MAX_ENTRIES_RX  9
+#define ENET_INIT_PARAM_MAX_ENTRIES_TX  8
+
+typedef struct ucc_mii_mng {
+	u32 miimcfg;		/* MII management configuration reg */
+	u32 miimcom;		/* MII management command reg */
+	u32 miimadd;		/* MII management address reg */
+	u32 miimcon;		/* MII management control reg */
+	u32 miimstat;		/* MII management status reg */
+	u32 miimind;		/* MII management indication reg */
+} __attribute__ ((packed)) ucc_mii_mng_t;
+
+typedef struct ucc_geth {
+	ucc_fast_t uccf;
+
+	u32 maccfg1;		/* mac configuration reg. 1 */
+	u32 maccfg2;		/* mac configuration reg. 2 */
+	u32 ipgifg;		/* interframe gap reg.  */
+	u32 hafdup;		/* half-duplex reg.  */
+	u8 res1[0x10];
+	ucc_mii_mng_t miimng;	/* MII management structure */
+	u32 ifctl;		/* interface control reg */
+	u32 ifstat;		/* interface statux reg */
+	u32 macstnaddr1;	/* mac station address part 1 reg */
+	u32 macstnaddr2;	/* mac station address part 2 reg */
+	u8 res2[0x8];
+	u32 uempr;		/* UCC Ethernet Mac parameter reg */
+	u32 utbipar;		/* UCC tbi address reg */
+	u16 uescr;		/* UCC Ethernet statistics control reg
*/
+	u8 res3[0x180 - 0x15A];
+	u32 tx64;		/* Total number of frames (including bad
+				   frames) transmitted that were exactly
of the=20
+				   minimal length (64 for un tagged, 68
for
+				   tagged, or with length exactly equal
to the
+				   parameter MINLength */
+	u32 tx127;		/* Total number of frames (including bad
+				   frames) transmitted that were between
+				   MINLength (Including FCS length=3D=3D4)
and 127
+				   octets */
+	u32 tx255;		/* Total number of frames (including bad
+				   frames) transmitted that were between
128
+				   (Including FCS length=3D=3D4) and 255
octets */
+	u32 rx64;		/* Total number of frames received
including
+				   bad frames that were exactly of the
mninimal=20
+				   length (64 bytes) */
+	u32 rx127;		/* Total number of frames (including bad
+				   frames) received that were between
MINLength=20
+				   (Including FCS length=3D=3D4) and 127
octets */
+	u32 rx255;		/* Total number of frames (including bad
+				   frames) received that were between
128
+				   (Including FCS length=3D=3D4) and 255
octets */
+	u32 txok;		/* Total number of octets residing in
frames
+				   that where involved in succesfull
+				   transmission */
+	u16 txcf;		/* Total number of PAUSE control frames
+				   transmitted by this MAC */
+	u8 res4[0x2];
+	u32 tmca;		/* Total number of frames that were
transmitted=20
+				   succesfully with the group address
bit set
+				   that are not broadcast frames */
+	u32 tbca;		/* Total number of frames transmitted
+				   succesfully that had destination
address
+				   field equal to the broadcast address
*/
+	u32 rxfok;		/* Total number of frames received OK */
+	u32 rxbok;		/* Total number of octets received OK */
+	u32 rbyt;		/* Total number of octets received
including
+				   octets in bad frames. Must be
implemented in=20
+				   HW because it includes octets in
frames that=20
+				   never even reach the UCC */
+	u32 rmca;		/* Total number of frames that were
received
+				   succesfully with the group address
bit set
+				   that are not broadcast frames */
+	u32 rbca;		/* Total number of frames received
succesfully
+				   that had destination address equal to
the
+				   broadcast address */
+	u32 scar;		/* Statistics carry register */
+	u32 scam;		/* Statistics caryy mask register */
+	u8 res5[0x200 - 0x1c4];
+} __attribute__ ((packed)) ucc_geth_t;
+
+/* UCC GETH TEMODR Register */
+#define TEMODER_TX_RMON_STATISTICS_ENABLE       0x0100	/* enable Tx
statistics=20
+							 */
+#define TEMODER_SCHEDULER_ENABLE                0x2000	/* enable
scheduler */
+#define TEMODER_IP_CHECKSUM_GENERATE            0x0400	/* generate IPv4
+							   checksums */
+#define TEMODER_PERFORMANCE_OPTIMIZATION_MODE1  0x0200	/* enable
performance
+							   optimization
+							   enhancement
(mode1) */
+#define TEMODER_RMON_STATISTICS                 0x0100	/* enable tx
statistics=20
+							 */
+#define TEMODER_NUM_OF_QUEUES_SHIFT             (15-15)	/*
Number of queues <<
+							   shift */
+
+/* UCC GETH TEMODR Register */
+#define REMODER_RX_RMON_STATISTICS_ENABLE       0x00001000	/*
enable Rx
+
statistics */
+#define REMODER_RX_EXTENDED_FEATURES            0x80000000	/*
enable
+
extended
+
features */
+#define REMODER_VLAN_OPERATION_TAGGED_SHIFT     (31-9 )	/* vlan
operation
+							   tagged <<
shift */
+#define REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT (31-10)	/* vlan
operation non
+							   tagged <<
shift */
+#define REMODER_RX_QOS_MODE_SHIFT               (31-15)	/* rx
QoS mode << shift=20
+							 */
+#define REMODER_RMON_STATISTICS                 0x00001000	/*
enable rx
+
statistics */
+#define REMODER_RX_EXTENDED_FILTERING           0x00000800	/*
extended
+
filtering
+								   vs.
+
mpc82xx-like=20
+
filtering */
+#define REMODER_NUM_OF_QUEUES_SHIFT             (31-23)	/*
Number of queues <<
+							   shift */
+#define REMODER_DYNAMIC_MAX_FRAME_LENGTH        0x00000008	/*
enable
+
dynamic max
+								   frame
length=20
+								 */
+#define REMODER_DYNAMIC_MIN_FRAME_LENGTH        0x00000004	/*
enable
+
dynamic min
+								   frame
length=20
+								 */
+#define REMODER_IP_CHECKSUM_CHECK               0x00000002	/* check
IPv4
+
checksums */
+#define REMODER_IP_ADDRESS_ALIGNMENT            0x00000001	/* align
ip
+
address to
+
4-byte
+
boundary */
+
+/* UCC GETH Event Register */
+#define UCCE_MPD                                0x80000000	/* Magic
packet=20
+
detection */
+#define UCCE_SCAR                               0x40000000
+#define UCCE_GRA                                0x20000000	/* Tx
graceful
+								   stop
+
complete */
+#define UCCE_CBPR                               0x10000000
+#define UCCE_BSY                                0x08000000
+#define UCCE_RXC                                0x04000000
+#define UCCE_TXC                                0x02000000
+#define UCCE_TXE                                0x01000000
+#define UCCE_TXB7                               0x00800000
+#define UCCE_TXB6                               0x00400000
+#define UCCE_TXB5                               0x00200000
+#define UCCE_TXB4                               0x00100000
+#define UCCE_TXB3                               0x00080000
+#define UCCE_TXB2                               0x00040000
+#define UCCE_TXB1                               0x00020000
+#define UCCE_TXB0                               0x00010000
+#define UCCE_RXB7                               0x00008000
+#define UCCE_RXB6                               0x00004000
+#define UCCE_RXB5                               0x00002000
+#define UCCE_RXB4                               0x00001000
+#define UCCE_RXB3                               0x00000800
+#define UCCE_RXB2                               0x00000400
+#define UCCE_RXB1                               0x00000200
+#define UCCE_RXB0                               0x00000100
+#define UCCE_RXF7                               0x00000080
+#define UCCE_RXF6                               0x00000040
+#define UCCE_RXF5                               0x00000020
+#define UCCE_RXF4                               0x00000010
+#define UCCE_RXF3                               0x00000008
+#define UCCE_RXF2                               0x00000004
+#define UCCE_RXF1                               0x00000002
+#define UCCE_RXF0                               0x00000001
+
+#define UCCE_RXBF_SINGLE_MASK                   (UCCE_RXF0)
+#define UCCE_TXBF_SINGLE_MASK                   (UCCE_TXB0)
+
+#define UCCE_TXB         (UCCE_TXB7 | UCCE_TXB6 | UCCE_TXB5 | UCCE_TXB4
| UCCE_TXB3 | UCCE_TXB2 | UCCE_TXB1 | UCCE_TXB0)
+#define UCCE_RXB         (UCCE_RXB7 | UCCE_RXB6 | UCCE_RXB5 | UCCE_RXB4
| UCCE_RXB3 | UCCE_RXB2 | UCCE_RXB1 | UCCE_RXB0)
+#define UCCE_RXF         (UCCE_RXF7 | UCCE_RXF6 | UCCE_RXF5 | UCCE_RXF4
| UCCE_RXF3 | UCCE_RXF2 | UCCE_RXF1 | UCCE_RXF0)
+#define UCCE_OTHER       (UCCE_SCAR | UCCE_GRA  | UCCE_CBPR | UCCE_BSY
| UCCE_RXC  | UCCE_TXC  | UCCE_TXE)
+
+/* UCC GETH UPSMR (Protocol Specific Mode Register) */
+#define UPSMR_ECM                               0x04000000	/*
Enable CAM
+								   Miss
or
+
Enable
+
Filtering
+								   Miss
*/
+#define UPSMR_HSE                               0x02000000	/*
Hardware
+
Statistics
+
Enable */
+#define UPSMR_PRO                               0x00400000	/*
Promiscuous */
+#define UPSMR_CAP                               0x00200000	/* CAM
polarity=20
+								 */
+#define UPSMR_RSH                               0x00100000	/*
Receive
+								   Short
Frames=20
+								 */
+#define UPSMR_RPM                               0x00080000	/*
Reduced Pin
+								   Mode
+
interfaces */
+#define UPSMR_R10M                              0x00040000	/*
RGMII/RMII
+								   10
Mode */
+#define UPSMR_RLPB                              0x00020000	/* RMII
+
Loopback
+								   Mode
*/
+#define UPSMR_TBIM                              0x00010000	/*
Ten-bit
+
Interface
+								   Mode
*/
+#define UPSMR_RMM                               0x00001000	/*
RMII/RGMII
+								   Mode
*/
+#define UPSMR_CAM                               0x00000400	/* CAM
Address
+
Matching */
+#define UPSMR_BRO                               0x00000200	/*
Broadcast
+
Address */
+#define UPSMR_RES1                              0x00002000	/*
Reserved
+								   feild
- must=20
+								   be 1
*/
+
+/* UCC GETH MACCFG1 (MAC Configuration 1 Register) */
+#define MACCFG1_FLOW_RX                         0x00000020	/* Flow
Control=20
+								   Rx */
+#define MACCFG1_FLOW_TX                         0x00000010	/* Flow
Control=20
+								   Tx */
+#define MACCFG1_ENABLE_SYNCHED_RX               0x00000008	/* Rx
Enable
+
synchronized=20
+								   to Rx
stream=20
+								 */
+#define MACCFG1_ENABLE_RX                       0x00000004	/*
Enable Rx */
+#define MACCFG1_ENABLE_SYNCHED_TX               0x00000002	/* Tx
Enable
+
synchronized=20
+								   to Tx
stream=20
+								 */
+#define MACCFG1_ENABLE_TX                       0x00000001	/*
Enable Tx */
+
+/* UCC GETH MACCFG2 (MAC Configuration 2 Register) */
+#define MACCFG2_PREL_SHIFT                      (31 - 19)	/*
Preamble
+
Length <<
+								   shift
*/
+#define MACCFG2_PREL_MASK                       0x0000f000	/*
Preamble
+
Length mask */
+#define MACCFG2_SRP                             0x00000080	/* Soft
Receive=20
+
Preamble */
+#define MACCFG2_STP                             0x00000040	/* Soft
+
Transmit
+
Preamble */
+#define MACCFG2_RESERVED_1                      0x00000020	/*
Reserved -
+								   must
be set
+								   to 1
*/
+#define MACCFG2_LC                              0x00000010	/*
Length Check=20
+								 */
+#define MACCFG2_MPE                             0x00000008	/* Magic
packet=20
+
detect */
+#define MACCFG2_FDX                             0x00000001	/* Full
Duplex */
+#define MACCFG2_FDX_MASK                        0x00000001	/* Full
Duplex
+								   mask
*/
+#define MACCFG2_PAD_CRC                         0x00000004
+#define MACCFG2_CRC_EN                          0x00000002
+#define MACCFG2_PAD_AND_CRC_MODE_NONE           0x00000000	/*
Neither
+
Padding
+								   short
frames=20
+								   nor
CRC */
+#define MACCFG2_PAD_AND_CRC_MODE_CRC_ONLY       0x00000002	/*
Append CRC
+								   only
*/
+#define MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC    0x00000004
+#define MACCFG2_INTERFACE_MODE_NIBBLE           0x00000100	/*
nibble mode
+
(MII/RMII/RGMII=20
+
10/100bps) */
+#define MACCFG2_INTERFACE_MODE_BYTE             0x00000200	/* byte
mode
+
(GMII/TBI/RTB/RGMII=20
+
1000bps ) */
+#define MACCFG2_INTERFACE_MODE_MASK             0x00000300	/* mask
+
covering all=20
+
relevant
+								   bits
*/
+
+/* UCC GETH IPGIFG (Inter-frame Gap / Inter-Frame Gap Register) */
+#define IPGIFG_NON_BACK_TO_BACK_IFG_PART1_SHIFT (31 -  7)	/* Non
+
back-to-back=20
+								   inter
frame
+								   gap
part 1.
+								   <<
shift */
+#define IPGIFG_NON_BACK_TO_BACK_IFG_PART2_SHIFT (31 - 15)	/* Non
+
back-to-back=20
+								   inter
frame
+								   gap
part 2.
+								   <<
shift */
+#define IPGIFG_MINIMUM_IFG_ENFORCEMENT_SHIFT    (31 - 23)	/*
Mimimum IFG
+
Enforcement
+								   <<
shift */
+#define IPGIFG_BACK_TO_BACK_IFG_SHIFT           (31 - 31)	/*
back-to-back=20
+								   inter
frame
+								   gap
<< shift=20
+								 */
+#define IPGIFG_NON_BACK_TO_BACK_IFG_PART1_MAX   127	/* Non
back-to-back
+							   inter frame
gap part=20
+							   1. max val */
+#define IPGIFG_NON_BACK_TO_BACK_IFG_PART2_MAX   127	/* Non
back-to-back
+							   inter frame
gap part=20
+							   2. max val */
+#define IPGIFG_MINIMUM_IFG_ENFORCEMENT_MAX      255	/* Mimimum IFG
+							   Enforcement
max val */
+#define IPGIFG_BACK_TO_BACK_IFG_MAX             127	/* back-to-back
inter
+							   frame gap max
val */
+#define IPGIFG_NBTB_CS_IPG_MASK                 0x7F000000
+#define IPGIFG_NBTB_IPG_MASK                    0x007F0000
+#define IPGIFG_MIN_IFG_MASK                     0x0000FF00
+#define IPGIFG_BTB_IPG_MASK                     0x0000007F
+
+/* UCC GETH HAFDUP (Half Duplex Register) */
+#define HALFDUP_ALT_BEB_TRUNCATION_SHIFT        (31 - 11)	/*
Alternate
+
Binary
+
Exponential
+
Backoff
+
Truncation
+								   <<
shift */
+#define HALFDUP_ALT_BEB_TRUNCATION_MAX          0xf	/* Alternate
Binary
+							   Exponential
Backoff
+							   Truncation
max val */
+#define HALFDUP_ALT_BEB                         0x00080000	/*
Alternate
+
Binary
+
Exponential
+
Backoff */
+#define HALFDUP_BACK_PRESSURE_NO_BACKOFF        0x00040000	/* Back
+
pressure no
+
backoff */
+#define HALFDUP_NO_BACKOFF                      0x00020000	/* No
Backoff */
+#define HALFDUP_EXCESSIVE_DEFER                 0x00010000	/*
Excessive
+								   Defer
*/
+#define HALFDUP_MAX_RETRANSMISSION_SHIFT        (31 - 19)	/*
Maximum
+
Retransmission=20
+								   <<
shift */
+#define HALFDUP_MAX_RETRANSMISSION_MAX          0xf	/* Maximum
+
Retransmission max
+							   val */
+#define HALFDUP_COLLISION_WINDOW_SHIFT          (31 - 31)	/*
Collision
+
Window <<
+								   shift
*/
+#define HALFDUP_COLLISION_WINDOW_MAX            0x3f	/* Collision
Window max=20
+							   val */
+#define HALFDUP_ALT_BEB_TR_MASK                 0x00F00000
+#define HALFDUP_RETRANS_MASK                    0x0000F000
+#define HALFDUP_COL_WINDOW_MASK                 0x0000003F
+
+/* UCC GETH UCCS (Ethernet Status Register) */
+#define UCCS_BPR                                0x02	/* Back pressure
(in
+							   half duplex
mode) */
+#define UCCS_PAU                                0x02	/* Pause state
(in full=20
+							   duplex mode)
*/
+#define UCCS_MPD                                0x01	/* Magic Packet
+							   Detected */
+
+/* UCC GETH MIIMCFG (MII Management Configuration Register) */
+#define MIIMCFG_RESET_MANAGEMENT                0x80000000	/* Reset
+
management */
+#define MIIMCFG_NO_PREAMBLE                     0x00000010	/*
Preamble
+
suppress */
+#define MIIMCFG_CLOCK_DIVIDE_SHIFT              (31 - 31)	/* clock
divide=20
+								   <<
shift */
+#define MIIMCFG_CLOCK_DIVIDE_MAX                0xf	/* clock divide
max val=20
+							 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2    0x00000000	/*
divide by 2 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4    0x00000001	/*
divide by 4 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6    0x00000002	/*
divide by 6 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8    0x00000003	/*
divide by 8 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10   0x00000004	/*
divide by 10=20
+								 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14   0x00000005	/*
divide by 14=20
+								 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16   0x00000008	/*
divide by 16=20
+								 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20   0x00000006	/*
divide by 20=20
+								 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28   0x00000007	/*
divide by 28=20
+								 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32   0x00000009	/*
divide by 32=20
+								 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48   0x0000000a	/*
divide by 48=20
+								 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64   0x0000000b	/*
divide by 64=20
+								 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80   0x0000000c	/*
divide by 80=20
+								 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112  0x0000000d	/*
divide by
+								   112
*/
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160  0x0000000e	/*
divide by
+								   160
*/
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224  0x0000000f	/*
divide by
+								   224
*/
+
+/* UCC GETH MIIMCOM (MII Management Command Register) */
+#define MIIMCOM_SCAN_CYCLE                      0x00000002	/* Scan
cycle */
+#define MIIMCOM_READ_CYCLE                      0x00000001	/* Read
cycle */
+
+/* UCC GETH MIIMADD (MII Management Address Register) */
+#define MIIMADD_PHY_ADDRESS_SHIFT               (31 - 23)	/* PHY
Address
+								   <<
shift */
+#define MIIMADD_PHY_REGISTER_SHIFT              (31 - 31)	/* PHY
Register=20
+								   <<
shift */
+
+/* UCC GETH MIIMCON (MII Management Control Register) */
+#define MIIMCON_PHY_CONTROL_SHIFT               (31 - 31)	/* PHY
Control
+								   <<
shift */
+#define MIIMCON_PHY_STATUS_SHIFT                (31 - 31)	/* PHY
Status
+								   <<
shift */
+
+/* UCC GETH MIIMIND (MII Management Indicator Register) */
+#define MIIMIND_NOT_VALID                       0x00000004	/* Not
valid */
+#define MIIMIND_SCAN                            0x00000002	/* Scan
in
+
progress */
+#define MIIMIND_BUSY                            0x00000001
+
+/* UCC GETH IFSTAT (Interface Status Register) */
+#define IFSTAT_EXCESS_DEFER                     0x00000200	/*
Excessive
+
transmission=20
+								   defer
*/
+
+/* UCC GETH MACSTNADDR1 (Station Address Part 1 Register) */
+#define MACSTNADDR1_OCTET_6_SHIFT               (31 -  7)	/*
Station
+
address 6th
+								   octet
<<
+								   shift
*/
+#define MACSTNADDR1_OCTET_5_SHIFT               (31 - 15)	/*
Station
+
address 5th
+								   octet
<<
+								   shift
*/
+#define MACSTNADDR1_OCTET_4_SHIFT               (31 - 23)	/*
Station
+
address 4th
+								   octet
<<
+								   shift
*/
+#define MACSTNADDR1_OCTET_3_SHIFT               (31 - 31)	/*
Station
+
address 3rd
+								   octet
<<
+								   shift
*/
+
+/* UCC GETH MACSTNADDR2 (Station Address Part 2 Register) */
+#define MACSTNADDR2_OCTET_2_SHIFT               (31 -  7)	/*
Station
+
address 2nd
+								   octet
<<
+								   shift
*/
+#define MACSTNADDR2_OCTET_1_SHIFT               (31 - 15)	/*
Station
+
address 1st
+								   octet
<<
+								   shift
*/
+
+/* UCC GETH UEMPR (Ethernet Mac Parameter Register) */
+#define UEMPR_PAUSE_TIME_VALUE_SHIFT            (31 - 15)	/* Pause
time
+								   value
<<
+								   shift
*/
+#define UEMPR_EXTENDED_PAUSE_TIME_VALUE_SHIFT   (31 - 31)	/*
Extended
+								   pause
time
+								   value
<<
+								   shift
*/
+
+/* UCC GETH UTBIPAR (Ten Bit Interface Physical Address Register) */
+#define UTBIPAR_PHY_ADDRESS_SHIFT               (31 - 31)	/* Phy
address
+								   <<
shift */
+#define UTBIPAR_PHY_ADDRESS_MASK                0x0000001f	/* Phy
address
+								   mask
*/
+
+/* UCC GETH UESCR (Ethernet Statistics Control Register) */
+#define UESCR_AUTOZ                             0x8000	/* Automatically
zero
+							   addressed
+							   statistical
counter
+							   values */
+#define UESCR_CLRCNT                            0x4000	/* Clear all
statistics=20
+							   counters */
+#define UESCR_MAXCOV_SHIFT                      (15 -  7)	/* Max
+
Coalescing
+								   Value
<<
+								   shift
*/
+#define UESCR_SCOV_SHIFT                        (15 - 15)	/*
Status
+
Coalescing
+								   Value
<<
+								   shift
*/
+
+/* UCC GETH UDSR (Data Synchronization Register) */
+#define UDSR_MAGIC                              0x067E
+
+typedef struct ucc_geth_thread_data_tx {
+	u8 res0[104];
+} __attribute__ ((packed)) ucc_geth_thread_data_tx_t;
+
+typedef struct ucc_geth_thread_data_rx {
+	u8 res0[40];
+} __attribute__ ((packed)) ucc_geth_thread_data_rx_t;
+
+/* Send Queue Queue-Descriptor */
+typedef struct ucc_geth_send_queue_qd {
+	u32 bd_ring_base;	/* pointer to BD ring base address */
+	u8 res0[0x8];
+	u32 last_bd_completed_address;	/* initialize to last entry in
BD ring */
+	u8 res1[0x30];
+} __attribute__ ((packed)) ucc_geth_send_queue_qd_t;
+
+typedef struct ucc_geth_send_queue_mem_region {
+	ucc_geth_send_queue_qd_t sqqd[NUM_TX_QUEUES];
+} __attribute__ ((packed)) ucc_geth_send_queue_mem_region_t;
+
+typedef struct ucc_geth_thread_tx_pram {
+	u8 res0[64];
+} __attribute__ ((packed)) ucc_geth_thread_tx_pram_t;
+
+typedef struct ucc_geth_thread_rx_pram {
+	u8 res0[128];
+} __attribute__ ((packed)) ucc_geth_thread_rx_pram_t;
+
+#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING        64
+#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8      64
+#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16     96
+
+typedef struct ucc_geth_scheduler {
+	u16 cpucount0;		/* CPU packet counter */
+	u16 cpucount1;		/* CPU packet counter */
+	u16 cecount0;		/* QE packet counter */
+	u16 cecount1;		/* QE packet counter */
+	u16 cpucount2;		/* CPU packet counter */
+	u16 cpucount3;		/* CPU packet counter */
+	u16 cecount2;		/* QE packet counter */
+	u16 cecount3;		/* QE packet counter */
+	u16 cpucount4;		/* CPU packet counter */
+	u16 cpucount5;		/* CPU packet counter */
+	u16 cecount4;		/* QE packet counter */
+	u16 cecount5;		/* QE packet counter */
+	u16 cpucount6;		/* CPU packet counter */
+	u16 cpucount7;		/* CPU packet counter */
+	u16 cecount6;		/* QE packet counter */
+	u16 cecount7;		/* QE packet counter */
+	u32 weightstatus[NUM_TX_QUEUES];	/* accumulated weight
factor */
+	u32 rtsrshadow;		/* temporary variable handled by QE */
+	u32 time;		/* temporary variable handled by QE */
+	u32 ttl;		/* temporary variable handled by QE */
+	u32 mblinterval;	/* max burst length interval */
+	u16 nortsrbytetime;	/* normalized value of byte time in tsr
units */
+	u8 fracsiz;		/* radix 2 log value of denom. of
+				   NorTSRByteTime */
+	u8 res0[1];
+	u8 strictpriorityq;	/* Strict Priority Mask register */
+	u8 txasap;		/* Transmit ASAP register */
+	u8 extrabw;		/* Extra BandWidth register */
+	u8 oldwfqmask;		/* temporary variable handled by QE */
+	u8 weightfactor[NUM_TX_QUEUES];
+				      /**< weight factor for queues   */
+	u32 minw;		/* temporary variable handled by QE */
+	u8 res1[0x70 - 0x64];
+} __attribute__ ((packed)) ucc_geth_scheduler_t;
+
+typedef struct ucc_geth_tx_firmware_statistics_pram {
+	u32 sicoltx;		/* single collision */
+	u32 mulcoltx;		/* multiple collision */
+	u32 latecoltxfr;	/* late collision */
+	u32 frabortduecol;	/* frames aborted due to transmit
collision */
+	u32 frlostinmactxer;	/* frames lost due to internal MAC error
+				   transmission that are not counted on
any
+				   other counter */
+	u32 carriersenseertx;	/* carrier sense error */
+	u32 frtxok;		/* frames transmitted OK */
+	u32 txfrexcessivedefer;	/* frames with defferal time greater
than
+				   specified threshold */
+	u32 txpkts256;		/* total packets (including bad) between
256
+				   and 511 octets */
+	u32 txpkts512;		/* total packets (including bad) between
512
+				   and 1023 octets */
+	u32 txpkts1024;		/* total packets (including bad) between
1024
+				   and 1518 octets */
+	u32 txpktsjumbo;	/* total packets (including bad) between
1024
+				   and MAXLength octets */
+} __attribute__ ((packed)) ucc_geth_tx_firmware_statistics_pram_t;
+
+typedef struct ucc_geth_rx_firmware_statistics_pram {
+	u32 frrxfcser;		/* frames with crc error */
+	u32 fraligner;		/* frames with alignment error */
+	u32 inrangelenrxer;	/* in range length error */
+	u32 outrangelenrxer;	/* out of range length error */
+	u32 frtoolong;		/* frame too long */
+	u32 runt;		/* runt */
+	u32 verylongevent;	/* very long event */
+	u32 symbolerror;	/* symbol error */
+	u32 dropbsy;		/* drop because of BD not ready */
+	u8 res0[0x8];
+	u32 mismatchdrop;	/* drop because of MAC filtering (e.g.
address
+				   or type mismatch) */
+	u32 underpkts;		/* total frames less than 64 octets */
+	u32 pkts256;		/* total frames (including bad) between
256 and=20
+				   511 octets */
+	u32 pkts512;		/* total frames (including bad) between
512 and=20
+				   1023 octets */
+	u32 pkts1024;		/* total frames (including bad) between
1024
+				   and 1518 octets */
+	u32 pktsjumbo;		/* total frames (including bad) between
1024
+				   and MAXLength octets */
+	u32 frlossinmacer;	/* frames lost because of internal MAC
error
+				   that is not counted in any other
counter */
+	u32 pausefr;		/* pause frames */
+	u8 res1[0x4];
+	u32 removevlan;		/* total frames that had their VLAN tag
removed=20
+				 */
+	u32 replacevlan;	/* total frames that had their VLAN tag
+				   replaced */
+	u32 insertvlan;		/* total frames that had their VLAN tag
+				   inserted */
+} __attribute__ ((packed)) ucc_geth_rx_firmware_statistics_pram_t;
+
+typedef struct ucc_geth_rx_interrupt_coalescing_entry {
+	u32 interruptcoalescingmaxvalue;	/* interrupt coalescing
max
+						   value */
+	u32 interruptcoalescingcounter;	/* interrupt coalescing counter,
+					   initialize to
+					   interruptcoalescingmaxvalue
*/
+} __attribute__ ((packed)) ucc_geth_rx_interrupt_coalescing_entry_t;
+
+typedef struct ucc_geth_rx_interrupt_coalescing_table {
+	ucc_geth_rx_interrupt_coalescing_entry_t
coalescingentry[NUM_RX_QUEUES];
+
/**< interrupt coalescing entry */
+} __attribute__ ((packed)) ucc_geth_rx_interrupt_coalescing_table_t;
+
+typedef struct ucc_geth_rx_prefetched_bds {
+	qe_bd_t bd[NUM_BDS_IN_PREFETCHED_BDS];	/* prefetched bd */
+} __attribute__ ((packed)) ucc_geth_rx_prefetched_bds_t;
+
+typedef struct ucc_geth_rx_bd_queues_entry {
+	u32 bdbaseptr;		/* BD base pointer */
+	u32 bdptr;		/* BD pointer */
+	u32 externalbdbaseptr;	/* external BD base pointer */
+	u32 externalbdptr;	/* external BD pointer */
+} __attribute__ ((packed)) ucc_geth_rx_bd_queues_entry_t;
+
+typedef struct ucc_geth_tx_global_pram {
+	u16 temoder;
+	u8 res0[0x38 - 0x02];
+	u32 sqptr;		/* a base pointer to send queue memory
region */
+	u32 schedulerbasepointer;	/* a base pointer to scheduler
memory
+					   region */
+	u32 txrmonbaseptr;	/* base pointer to Tx RMON statistics
counter */
+	u32 tstate;		/* tx internal state. High byte contains
+				   function code */
+	u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX];
+	u32 vtagtable[0x8];	/* 8 4-byte VLAN tags */
+	u32 tqptr;		/* a base pointer to the Tx Queues
Memory
+				   Region */
+	u8 res2[0x80 - 0x74];
+} __attribute__ ((packed)) ucc_geth_tx_global_pram_t;
+
+/* structure representing Extended Filtering Global Parameters in PRAM
*/
+typedef struct ucc_geth_exf_global_pram {
+	u32 l2pcdptr;		/* individual address filter, high */
+	u8 res0[0x10 - 0x04];
+} __attribute__ ((packed)) ucc_geth_exf_global_pram_t;
+
+typedef struct ucc_geth_rx_global_pram {
+	u32 remoder;		/* ethernet mode reg. */
+	u32 rqptr;		/* base pointer to the Rx Queues Memory
Region */
+	u32 res0[0x1];
+	u8 res1[0x20 - 0xC];
+	u16 typeorlen;		/* cutoff point less than which,
type/len field=20
+				   is considered length */
+	u8 res2[0x1];
+	u8 rxgstpack;		/* acknowledgement on GRACEFUL STOP RX
command */
+	u32 rxrmonbaseptr;	/* base pointer to Rx RMON statistics
counter */
+	u8 res3[0x30 - 0x28];
+	u32 intcoalescingptr;	/* Interrupt coalescing table pointer */
+	u8 res4[0x36 - 0x34];
+	u8 rstate;		/* rx internal state. High byte contains
+				   function code */
+	u8 res5[0x46 - 0x37];
+	u16 mrblr;		/* max receive buffer length reg. */
+	u32 rbdqptr;		/* base pointer to RxBD parameter table
+				   description */
+	u16 mflr;		/* max frame length reg. */
+	u16 minflr;		/* min frame length reg. */
+	u16 maxd1;		/* max dma1 length reg. */
+	u16 maxd2;		/* max dma2 length reg. */
+	u32 ecamptr;		/* external CAM address */
+	u32 l2qt;		/* VLAN priority mapping table. */
+	u32 l3qt[0x8];		/* IP priority mapping table. */
+	u16 vlantype;		/* vlan type */
+	u16 vlantci;		/* default vlan tci */
+	u8 addressfiltering[64];	/* address filtering data
structure */
+	u32 exfGlobalParam;	/* base address for extended filtering
global
+				   parameters */
+	u8 res6[0x100 - 0xC4];	/* Initialize to zero */
+} __attribute__ ((packed)) ucc_geth_rx_global_pram_t;
+
+#define GRACEFUL_STOP_ACKNOWLEDGE_RX            0x01
+
+/* structure representing InitEnet command */
+typedef struct ucc_geth_init_pram {
+	u8 resinit1;
+	u8 resinit2;
+	u8 resinit3;
+	u8 resinit4;
+	u16 resinit5;
+	u8 res1[0x1];
+	u8 largestexternallookupkeysize;
+	u32 rgftgfrxglobal;
+	u32 rxthread[ENET_INIT_PARAM_MAX_ENTRIES_RX];	/* rx threads */
+	u8 res2[0x38 - 0x30];
+	u32 txglobal;		/* tx global */
+	u32 txthread[ENET_INIT_PARAM_MAX_ENTRIES_TX];	/* tx threads */
+	u8 res3[0x1];
+} __attribute__ ((packed)) ucc_geth_init_pram_t;
+
+#define ENET_INIT_PARAM_RGF_SHIFT               (32 - 4)
+#define ENET_INIT_PARAM_TGF_SHIFT               (32 - 8)
+
+#define ENET_INIT_PARAM_RISC_MASK               0x0000003f
+#define ENET_INIT_PARAM_PTR_MASK                0x00ffffc0
+#define ENET_INIT_PARAM_SNUM_MASK               0xff000000
+#define ENET_INIT_PARAM_SNUM_SHIFT              24
+
+#define ENET_INIT_PARAM_MAGIC_RES_INIT1         0x06
+#define ENET_INIT_PARAM_MAGIC_RES_INIT2         0x30
+#define ENET_INIT_PARAM_MAGIC_RES_INIT3         0xff
+#define ENET_INIT_PARAM_MAGIC_RES_INIT4         0x00
+#define ENET_INIT_PARAM_MAGIC_RES_INIT5         0x0400
+
+/* structure representing 82xx Address Filtering Enet Address in PRAM
*/
+typedef struct ucc_geth_82xx_enet_address {
+	u8 res1[0x2];
+	u16 h;			/* address (MSB) */
+	u16 m;			/* address */
+	u16 l;			/* address (LSB) */
+} __attribute__ ((packed)) ucc_geth_82xx_enet_address_t;
+
+/* structure representing 82xx Address Filtering PRAM */
+typedef struct ucc_geth_82xx_address_filtering_pram {
+	u32 iaddr_h;		/* individual address filter, high */
+	u32 iaddr_l;		/* individual address filter, low */
+	u32 gaddr_h;		/* group address filter, high */
+	u32 gaddr_l;		/* group address filter, low */
+	ucc_geth_82xx_enet_address_t taddr;
+	ucc_geth_82xx_enet_address_t paddr[NUM_OF_PADDRS];
+	u8 res0[0x40 - 0x38];
+} __attribute__ ((packed)) ucc_geth_82xx_address_filtering_pram_t;
+
+/* GETH Tx firmware statistics structure, used when calling
+   UCC_GETH_GetStatistics. */
+typedef struct ucc_geth_tx_firmware_statistics {
+	u32 sicoltx;		/* single collision */
+	u32 mulcoltx;		/* multiple collision */
+	u32 latecoltxfr;	/* late collision */
+	u32 frabortduecol;	/* frames aborted due to transmit
collision */
+	u32 frlostinmactxer;	/* frames lost due to internal MAC error
+				   transmission that are not counted on
any
+				   other counter */
+	u32 carriersenseertx;	/* carrier sense error */
+	u32 frtxok;		/* frames transmitted OK */
+	u32 txfrexcessivedefer;	/* frames with defferal time greater
than
+				   specified threshold */
+	u32 txpkts256;		/* total packets (including bad) between
256
+				   and 511 octets */
+	u32 txpkts512;		/* total packets (including bad) between
512
+				   and 1023 octets */
+	u32 txpkts1024;		/* total packets (including bad) between
1024
+				   and 1518 octets */
+	u32 txpktsjumbo;	/* total packets (including bad) between
1024
+				   and MAXLength octets */
+} __attribute__ ((packed)) ucc_geth_tx_firmware_statistics_t;
+
+/* GETH Rx firmware statistics structure, used when calling
+   UCC_GETH_GetStatistics. */
+typedef struct ucc_geth_rx_firmware_statistics {
+	u32 frrxfcser;		/* frames with crc error */
+	u32 fraligner;		/* frames with alignment error */
+	u32 inrangelenrxer;	/* in range length error */
+	u32 outrangelenrxer;	/* out of range length error */
+	u32 frtoolong;		/* frame too long */
+	u32 runt;		/* runt */
+	u32 verylongevent;	/* very long event */
+	u32 symbolerror;	/* symbol error */
+	u32 dropbsy;		/* drop because of BD not ready */
+	u8 res0[0x8];
+	u32 mismatchdrop;	/* drop because of MAC filtering (e.g.
address
+				   or type mismatch) */
+	u32 underpkts;		/* total frames less than 64 octets */
+	u32 pkts256;		/* total frames (including bad) between
256 and=20
+				   511 octets */
+	u32 pkts512;		/* total frames (including bad) between
512 and=20
+				   1023 octets */
+	u32 pkts1024;		/* total frames (including bad) between
1024
+				   and 1518 octets */
+	u32 pktsjumbo;		/* total frames (including bad) between
1024
+				   and MAXLength octets */
+	u32 frlossinmacer;	/* frames lost because of internal MAC
error
+				   that is not counted in any other
counter */
+	u32 pausefr;		/* pause frames */
+	u8 res1[0x4];
+	u32 removevlan;		/* total frames that had their VLAN tag
removed=20
+				 */
+	u32 replacevlan;	/* total frames that had their VLAN tag
+				   replaced */
+	u32 insertvlan;		/* total frames that had their VLAN tag
+				   inserted */
+} __attribute__ ((packed)) ucc_geth_rx_firmware_statistics_t;
+
+/* GETH hardware statistics structure, used when calling
+   UCC_GETH_GetStatistics. */
+typedef struct ucc_geth_hardware_statistics {
+	u32 tx64;		/* Total number of frames (including bad
+				   frames) transmitted that were exactly
of the=20
+				   minimal length (64 for un tagged, 68
for
+				   tagged, or with length exactly equal
to the
+				   parameter MINLength */
+	u32 tx127;		/* Total number of frames (including bad
+				   frames) transmitted that were between
+				   MINLength (Including FCS length=3D=3D4)
and 127
+				   octets */
+	u32 tx255;		/* Total number of frames (including bad
+				   frames) transmitted that were between
128
+				   (Including FCS length=3D=3D4) and 255
octets */
+	u32 rx64;		/* Total number of frames received
including
+				   bad frames that were exactly of the
mninimal=20
+				   length (64 bytes) */
+	u32 rx127;		/* Total number of frames (including bad
+				   frames) received that were between
MINLength=20
+				   (Including FCS length=3D=3D4) and 127
octets */
+	u32 rx255;		/* Total number of frames (including bad
+				   frames) received that were between
128
+				   (Including FCS length=3D=3D4) and 255
octets */
+	u32 txok;		/* Total number of octets residing in
frames
+				   that where involved in succesfull
+				   transmission */
+	u16 txcf;		/* Total number of PAUSE control frames
+				   transmitted by this MAC */
+	u32 tmca;		/* Total number of frames that were
transmitted=20
+				   succesfully with the group address
bit set
+				   that are not broadcast frames */
+	u32 tbca;		/* Total number of frames transmitted
+				   succesfully that had destination
address
+				   field equal to the broadcast address
*/
+	u32 rxfok;		/* Total number of frames received OK */
+	u32 rxbok;		/* Total number of octets received OK */
+	u32 rbyt;		/* Total number of octets received
including
+				   octets in bad frames. Must be
implemented in=20
+				   HW because it includes octets in
frames that=20
+				   never even reach the UCC */
+	u32 rmca;		/* Total number of frames that were
received
+				   succesfully with the group address
bit set
+				   that are not broadcast frames */
+	u32 rbca;		/* Total number of frames received
succesfully
+				   that had destination address equal to
the
+				   broadcast address */
+} __attribute__ ((packed)) ucc_geth_hardware_statistics_t;
+
+/* UCC GETH Tx errors returned via TxConf callback */
+#define TX_ERRORS_DEF      0x0200
+#define TX_ERRORS_EXDEF    0x0100
+#define TX_ERRORS_LC       0x0080
+#define TX_ERRORS_RL       0x0040
+#define TX_ERRORS_RC_MASK  0x003C
+#define TX_ERRORS_RC_SHIFT 2
+#define TX_ERRORS_UN       0x0002
+#define TX_ERRORS_CSL      0x0001
+
+/* UCC GETH Rx errors returned via RxStore callback */
+#define RX_ERRORS_CMR      0x0200
+#define RX_ERRORS_M        0x0100
+#define RX_ERRORS_BC       0x0080
+#define RX_ERRORS_MC       0x0040
+
+/* Transmit BD. These are in addition to values defined in uccf. */
+#define T_VID      0x003c0000	/* insert VLAN id index mask. */
+#define T_DEF      (((u32) TX_ERRORS_DEF     ) << 16)
+#define T_EXDEF    (((u32) TX_ERRORS_EXDEF   ) << 16)
+#define T_LC       (((u32) TX_ERRORS_LC      ) << 16)
+#define T_RL       (((u32) TX_ERRORS_RL      ) << 16)
+#define T_RC_MASK  (((u32) TX_ERRORS_RC_MASK ) << 16)
+#define T_UN       (((u32) TX_ERRORS_UN      ) << 16)
+#define T_CSL      (((u32) TX_ERRORS_CSL     ) << 16)
+#define T_ERRORS_REPORT  (T_DEF | T_EXDEF | T_LC | T_RL | T_RC_MASK \
+		| T_UN | T_CSL)	/* transmit errors to report */
+
+/* Receive BD. These are in addition to values defined in uccf. */
+#define R_LG    0x00200000	/* Frame length violation.  */
+#define R_NO    0x00100000	/* Non-octet aligned frame.  */
+#define R_SH    0x00080000	/* Short frame.  */
+#define R_CR    0x00040000	/* CRC error.  */
+#define R_OV    0x00020000	/* Overrun.  */
+#define R_IPCH  0x00010000	/* IP checksum check failed. */
+#define R_CMR   (((u32) RX_ERRORS_CMR  ) << 16)
+#define R_M     (((u32) RX_ERRORS_M    ) << 16)
+#define R_BC    (((u32) RX_ERRORS_BC   ) << 16)
+#define R_MC    (((u32) RX_ERRORS_MC   ) << 16)
+#define R_ERRORS_REPORT (R_CMR | R_M | R_BC | R_MC)	/* receive
errors to
+							   report */
+#define R_ERRORS_FATAL  (R_LG  | R_NO | R_SH | R_CR | \
+		R_OV | R_IPCH)	/* receive errors to discard */
+
+/* Alignments */
+#define UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT	256
+#define UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT       128
+#define UCC_GETH_THREAD_RX_PRAM_ALIGNMENT       128
+#define UCC_GETH_THREAD_TX_PRAM_ALIGNMENT       64
+#define UCC_GETH_THREAD_DATA_ALIGNMENT          256	/* spec gives
values
+							   based on num
of
+							   threads, but
always
+							   using the
maximum is=20
+							   easier */
+#define UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT	32
+#define UCC_GETH_SCHEDULER_ALIGNMENT		4	/* This is a
guess */
+#define UCC_GETH_TX_STATISTICS_ALIGNMENT	4	/* This is a
guess */
+#define UCC_GETH_RX_STATISTICS_ALIGNMENT	4	/* This is a
guess */
+#define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT	4	/* This
is a
+								   guess
*/
+#define UCC_GETH_RX_BD_QUEUES_ALIGNMENT		8	/* This
is a guess */
+#define UCC_GETH_RX_PREFETCHED_BDS_ALIGNMENT	128	/* This is a
guess */
+#define UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT 4
/* This=20
+
is a=20
+
guess
+
*/
+#define UCC_GETH_RX_BD_RING_ALIGNMENT		32
+#define UCC_GETH_TX_BD_RING_ALIGNMENT		32
+#define UCC_GETH_MRBLR_ALIGNMENT		128
+#define UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT	4
+#define UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT	32
+#define UCC_GETH_RX_DATA_BUF_ALIGNMENT		64
+
+#define UCC_GETH_TAD_EF                         0x80
+#define UCC_GETH_TAD_V                          0x40
+#define UCC_GETH_TAD_REJ                        0x20
+#define UCC_GETH_TAD_VTAG_OP_RIGHT_SHIFT        2
+#define UCC_GETH_TAD_VTAG_OP_SHIFT              6
+#define UCC_GETH_TAD_V_NON_VTAG_OP              0x20
+#define UCC_GETH_TAD_RQOS_SHIFT                 0
+#define UCC_GETH_TAD_V_PRIORITY_SHIFT           5
+#define UCC_GETH_TAD_CFI                        0x10
+
+#define UCC_GETH_VLAN_PRIORITY_MAX              8
+#define UCC_GETH_IP_PRIORITY_MAX                64
+#define UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX        8
+#define UCC_GETH_RX_BD_RING_SIZE_MIN            8
+#define UCC_GETH_TX_BD_RING_SIZE_MIN            2
+
+#define UCC_GETH_SIZE_OF_BD                     QE_SIZEOF_BD
+
+/* Driver definitions */
+#define TX_BD_RING_LEN                          0x10
+#define RX_BD_RING_LEN                          0x10
+#define UCC_GETH_DEV_WEIGHT                     TX_BD_RING_LEN
+
+#define TX_RING_MOD_MASK(size)                  (size-1)
+#define RX_RING_MOD_MASK(size)                  (size-1)
+
+#define ENET_NUM_OCTETS_PER_ADDRESS             6
+#define ENET_GROUP_ADDR                         0x01	/* Group address
mask
+							   for ethernet
+							   addresses */
+
+#define TX_TIMEOUT                              (1*HZ)
+#define SKB_ALLOC_TIMEOUT                       100000
+#define PHY_INIT_TIMEOUT                        100000
+#define PHY_CHANGE_TIME                         2
+
+/* Fast Ethernet (10/100 Mbps) */
+#define UCC_GETH_URFS_INIT                      512	/* Rx virtual
FIFO size=20
+							 */
+#define UCC_GETH_URFET_INIT                     256	/* 1/2 urfs */
+#define UCC_GETH_URFSET_INIT                    384	/* 3/4 urfs */
+#define UCC_GETH_UTFS_INIT                      512	/* Tx virtual
FIFO size=20
+							 */
+#define UCC_GETH_UTFET_INIT                     256	/* 1/2 utfs */
+#define UCC_GETH_UTFTT_INIT                     128
+/* Gigabit Ethernet (1000 Mbps) */
+#define UCC_GETH_URFS_GIGA_INIT                 4096/*2048*/	/* Rx
virtual
+								   FIFO
size */
+#define UCC_GETH_URFET_GIGA_INIT                2048/*1024*/	/* 1/2
urfs */
+#define UCC_GETH_URFSET_GIGA_INIT               3072/*1536*/	/* 3/4
urfs */
+#define UCC_GETH_UTFS_GIGA_INIT                 8192/*2048*/	/* Tx
virtual
+								   FIFO
size */
+#define UCC_GETH_UTFET_GIGA_INIT                4096/*1024*/	/* 1/2
utfs */
+#define UCC_GETH_UTFTT_GIGA_INIT                0x400/*0x40*/	/* */
+
+#define UCC_GETH_REMODER_INIT                   0	/* bits that
must be
+							   set */
+#define UCC_GETH_TEMODER_INIT                   0xC000	/* bits that
must */
+#define UCC_GETH_UPSMR_INIT                     (UPSMR_RES1)	/* Start
value
+								   for
this
+
register */
+#define UCC_GETH_MACCFG1_INIT                   0
+#define UCC_GETH_MACCFG2_INIT                   (MACCFG2_RESERVED_1)
+#define UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT
(MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112)
+
+/* Ethernet speed */
+typedef enum enet_speed {
+	ENET_SPEED_10BT,	/* 10 Base T */
+	ENET_SPEED_100BT,	/* 100 Base T */
+	ENET_SPEED_1000BT	/* 1000 Base T */
+} enet_speed_e;
+
+/* Ethernet Address Type. */
+typedef enum enet_addr_type {
+	ENET_ADDR_TYPE_INDIVIDUAL,
+	ENET_ADDR_TYPE_GROUP,
+	ENET_ADDR_TYPE_BROADCAST
+} enet_addr_type_e;
+
+/* TBI / MII Set Register */
+typedef enum enet_tbi_mii_reg {
+	ENET_TBI_MII_CR =3D 0x00,	/* Control (CR ) */
+	ENET_TBI_MII_SR =3D 0x01,	/* Status (SR ) */
+	ENET_TBI_MII_ANA =3D 0x04,	/* AN advertisement (ANA ) */
+	ENET_TBI_MII_ANLPBPA =3D 0x05,	/* AN link partner base page
ability
+					   (ANLPBPA) */
+	ENET_TBI_MII_ANEX =3D 0x06,	/* AN expansion (ANEX ) */
+	ENET_TBI_MII_ANNPT =3D 0x07,	/* AN next page transmit (ANNPT
) */
+	ENET_TBI_MII_ANLPANP =3D 0x08,	/* AN link partner ability next
page
+					   (ANLPANP) */
+	ENET_TBI_MII_EXST =3D 0x0F,	/* Extended status (EXST ) */
+	ENET_TBI_MII_JD =3D 0x10,	/* Jitter diagnostics (JD ) */
+	ENET_TBI_MII_TBICON =3D 0x11	/* TBI control (TBICON ) */
+} enet_tbi_mii_reg_e;
+
+/* UCC GETH 82xx Ethernet Address Recognition Location */
+typedef enum ucc_geth_enet_address_recognition_location {
+	UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/*
station=20
+
address */
+	UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR_FIRST,	/*
additional
+
station
+
address
+
paddr1 */
+	UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR2,	/*
additional
+
station
+
address
+
paddr2 */
+	UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR3,	/*
additional
+
station
+
address
+
paddr3 */
+	UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR_LAST,	/*
additional
+
station
+
address
+
paddr4 */
+	UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_GROUP_HASH,	/* group
hash */
+	UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_INDIVIDUAL_HASH /*
individual
+
hash */
+} ucc_geth_enet_address_recognition_location_e;
+
+/* UCC GETH vlan operation tagged */
+typedef enum ucc_geth_vlan_operation_tagged {
+	UCC_GETH_VLAN_OPERATION_TAGGED_NOP =3D 0x0,	/* Tagged - nop
*/
+	UCC_GETH_VLAN_OPERATION_TAGGED_REPLACE_VID_PORTION_OF_Q_TAG
+		=3D 0x1,	/* Tagged - replace vid portion of q tag */
+
UCC_GETH_VLAN_OPERATION_TAGGED_IF_VID0_REPLACE_VID_WITH_DEFAULT_VALUE
+		=3D 0x2,	/* Tagged - if vid0 replace vid with default
value  */
+	UCC_GETH_VLAN_OPERATION_TAGGED_EXTRACT_Q_TAG_FROM_FRAME=20
+		=3D 0x3	/* Tagged - extract q tag from frame */
+} ucc_geth_vlan_operation_tagged_e;
+
+/* UCC GETH vlan operation non-tagged */
+typedef enum ucc_geth_vlan_operation_non_tagged {
+	UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP =3D 0x0,	/* Non tagged -
nop */
+	UCC_GETH_VLAN_OPERATION_NON_TAGGED_Q_TAG_INSERT =3D 0x1	/* Non
tagged -=20
+								   q tag
insert=20
+								 */
+} ucc_geth_vlan_operation_non_tagged_e;
+
+/* UCC GETH Rx Quality of Service Mode */
+typedef enum ucc_geth_qos_mode {
+	UCC_GETH_QOS_MODE_DEFAULT =3D 0x0,	/* default queue */
+	UCC_GETH_QOS_MODE_QUEUE_NUM_FROM_L2_CRITERIA =3D 0x1,	/* queue
+
determined
+								   by L2
+
criteria */
+	UCC_GETH_QOS_MODE_QUEUE_NUM_FROM_L3_CRITERIA =3D 0x2	/* queue
+
determined
+								   by L3
+
criteria */
+} ucc_geth_qos_mode_e;
+
+/* UCC GETH Statistics Gathering Mode - These are bit flags, 'or' them
together=20
+   for combined functionality */
+typedef enum ucc_geth_statistics_gathering_mode {
+	UCC_GETH_STATISTICS_GATHERING_MODE_NONE =3D 0x00000000,	/* No
+
statistics
+
gathering */
+	UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE =3D 0x00000001,/*
Enable=20
+
hardware=20
+
statistics=20
+
gathering=20
+								  */
+	UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX =3D
0x00000004,/*Enable=20
+
firmware=20
+								      tx
+
statistics
+
gathering=20
+								     */
+	UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX =3D 0x00000008/*
Enable=20
+
firmware=20
+								      rx
+
statistics
+
gathering=20
+								    */
+} ucc_geth_statistics_gathering_mode_e;
+
+/* UCC GETH Pad and CRC Mode - Note, Padding without CRC is not
possible */
+typedef enum ucc_geth_maccfg2_pad_and_crc_mode {
+	UCC_GETH_PAD_AND_CRC_MODE_NONE=20
+		=3D MACCFG2_PAD_AND_CRC_MODE_NONE,	/* Neither
Padding=20
+							   short frames=20
+							   nor CRC */
+	UCC_GETH_PAD_AND_CRC_MODE_CRC_ONLY
+		=3D MACCFG2_PAD_AND_CRC_MODE_CRC_ONLY,	/* Append=20
+							   CRC only */
+	UCC_GETH_PAD_AND_CRC_MODE_PAD_AND_CRC =3D
+	    MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC
+} ucc_geth_maccfg2_pad_and_crc_mode_e;
+
+/* UCC GETH upsmr Flow Control Mode */
+typedef enum ucc_geth_flow_control_mode {
+	UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_NONE =3D 0x00000000,	/* No
automatic=20
+								   flow
control=20
+								 */
+	UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_PAUSE_WHEN_EMERGENCY=20
+		=3D 0x00004000	/* Send pause frame when RxFIFO reaches
its=20
+				   emergency threshold */
+} ucc_geth_flow_control_mode_e;
+
+/* UCC GETH number of threads */
+typedef enum ucc_geth_num_of_threads {
+	UCC_GETH_NUM_OF_THREADS_1 =3D 0x1,	/* 1 */
+	UCC_GETH_NUM_OF_THREADS_2 =3D 0x2,	/* 2 */
+	UCC_GETH_NUM_OF_THREADS_4 =3D 0x0,	/* 4 */
+	UCC_GETH_NUM_OF_THREADS_6 =3D 0x3,	/* 6 */
+	UCC_GETH_NUM_OF_THREADS_8 =3D 0x4	/* 8 */
+} ucc_geth_num_of_threads_e;
+
+/* UCC GETH number of station addresses */
+typedef enum ucc_geth_num_of_station_addresses {
+	UCC_GETH_NUM_OF_STATION_ADDRESSES_1,	/* 1 */
+	UCC_GETH_NUM_OF_STATION_ADDRESSES_5	/* 5 */
+} ucc_geth_num_of_station_addresses_e;
+
+typedef u8 enet_addr_t[ENET_NUM_OCTETS_PER_ADDRESS];
+
+/* UCC GETH 82xx Ethernet Address Container */
+typedef struct enet_addr_container {
+	enet_addr_t address;	/* ethernet address */
+	ucc_geth_enet_address_recognition_location_e location;	/*
location in
+								   82xx
address=20
+
recognition
+
hardware */
+	struct list_head node;
+} enet_addr_container_t;
+
+#define ENET_ADDR_CONT_ENTRY(ptr) list_entry(ptr,
enet_addr_container_t, node)
+
+/* UCC GETH Termination Action Descriptor (TAD) structure. */
+typedef struct ucc_geth_tad_params {
+	int rx_non_dynamic_extended_features_mode;
+	int reject_frame;
+	ucc_geth_vlan_operation_tagged_e vtag_op;
+	ucc_geth_vlan_operation_non_tagged_e vnontag_op;
+	ucc_geth_qos_mode_e rqos;
+	u8 vpri;
+	u16 vid;
+} ucc_geth_tad_params_t;
+
+/* GETH protocol initialization structure */
+typedef struct ucc_geth_info {
+	ucc_fast_info_t uf_info;
+	u8 numQueuesTx;
+	u8 numQueuesRx;
+	int ipCheckSumCheck;
+	int ipCheckSumGenerate;
+	int rxExtendedFiltering;
+	u32 extendedFilteringChainPointer;
+	u16 typeorlen;
+	int dynamicMaxFrameLength;
+	int dynamicMinFrameLength;
+	u8 nonBackToBackIfgPart1;
+	u8 nonBackToBackIfgPart2;
+	u8 miminumInterFrameGapEnforcement;
+	u8 backToBackInterFrameGap;
+	int ipAddressAlignment;
+	int lengthCheckRx;
+	u32 mblinterval;
+	u16 nortsrbytetime;
+	u8 fracsiz;
+	u8 strictpriorityq;
+	u8 txasap;
+	u8 extrabw;
+	int miiPreambleSupress;
+	u8 altBebTruncation;
+	int altBeb;
+	int backPressureNoBackoff;
+	int noBackoff;
+	int excessDefer;
+	u8 maxRetransmission;
+	u8 collisionWindow;
+	int pro;
+	int cap;
+	int rsh;
+	int rlpb;
+	int cam;
+	int bro;
+	int ecm;
+	int receiveFlowControl;
+	u8 maxGroupAddrInHash;
+	u8 maxIndAddrInHash;
+	u8 prel;
+	u16 maxFrameLength;
+	u16 minFrameLength;
+	u16 maxD1Length;
+	u16 maxD2Length;
+	u16 vlantype;
+	u16 vlantci;
+	u32 ecamptr;
+	u32 eventRegMask;
+	u16 pausePeriod;
+	u16 extensionField;
+	u8 phy_address;
+	u32 board_flags;
+	u32 phy_interrupt;
+	u8 weightfactor[NUM_TX_QUEUES];
+	u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES];
+	u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX];
+	u8 l3qt[UCC_GETH_IP_PRIORITY_MAX];
+	u32 vtagtable[UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX];
+	u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX];
+	u16 bdRingLenTx[NUM_TX_QUEUES];
+	u16 bdRingLenRx[NUM_RX_QUEUES];
+	enet_interface_e enet_interface;
+	ucc_geth_num_of_station_addresses_e numStationAddresses;
+	 qe_fltr_largest_external_tbl_lookup_key_size_e
+	    largestexternallookupkeysize;
+	ucc_geth_statistics_gathering_mode_e statisticsMode;
+	ucc_geth_vlan_operation_tagged_e vlanOperationTagged;
+	ucc_geth_vlan_operation_non_tagged_e vlanOperationNonTagged;
+	ucc_geth_qos_mode_e rxQoSMode;
+	ucc_geth_flow_control_mode_e aufc;
+	ucc_geth_maccfg2_pad_and_crc_mode_e padAndCrc;
+	ucc_geth_num_of_threads_e numThreadsTx;
+	ucc_geth_num_of_threads_e numThreadsRx;
+	qe_risc_allocation_e riscTx;
+	qe_risc_allocation_e riscRx;
+} ucc_geth_info_t;
+
+/* structure representing UCC GETH */
+typedef struct ucc_geth_private {
+	ucc_geth_info_t *ug_info;
+	ucc_fast_private_t *uccf;
+	struct net_device *dev;
+	struct net_device_stats stats;	/* linux network statistics */
+	ucc_geth_t *ug_regs;
+	ucc_geth_init_pram_t *p_init_enet_param_shadow;
+	ucc_geth_exf_global_pram_t *p_exf_glbl_param;
+	u32 exf_glbl_param_offset;
+	ucc_geth_rx_global_pram_t *p_rx_glbl_pram;
+	u32 rx_glbl_pram_offset;
+	ucc_geth_tx_global_pram_t *p_tx_glbl_pram;
+	u32 tx_glbl_pram_offset;
+	ucc_geth_send_queue_mem_region_t *p_send_q_mem_reg;
+	u32 send_q_mem_reg_offset;
+	ucc_geth_thread_data_tx_t *p_thread_data_tx;
+	u32 thread_dat_tx_offset;
+	ucc_geth_thread_data_rx_t *p_thread_data_rx;
+	u32 thread_dat_rx_offset;
+	ucc_geth_scheduler_t *p_scheduler;
+	u32 scheduler_offset;
+	ucc_geth_tx_firmware_statistics_pram_t *p_tx_fw_statistics_pram;
+	u32 tx_fw_statistics_pram_offset;
+	ucc_geth_rx_firmware_statistics_pram_t *p_rx_fw_statistics_pram;
+	u32 rx_fw_statistics_pram_offset;
+	ucc_geth_rx_interrupt_coalescing_table_t
*p_rx_irq_coalescing_tbl;
+	u32 rx_irq_coalescing_tbl_offset;
+	ucc_geth_rx_bd_queues_entry_t *p_rx_bd_qs_tbl;
+	u32 rx_bd_qs_tbl_offset;
+	u8 *p_tx_bd_ring[NUM_TX_QUEUES];
+	u32 tx_bd_ring_offset[NUM_TX_QUEUES];
+	u8 *p_rx_bd_ring[NUM_RX_QUEUES];
+	u32 rx_bd_ring_offset[NUM_RX_QUEUES];
+	u8 *confBd[NUM_TX_QUEUES];
+	u8 *txBd[NUM_TX_QUEUES];
+	u8 *rxBd[NUM_RX_QUEUES];
+	int badFrame[NUM_RX_QUEUES];
+	u16 cpucount[NUM_TX_QUEUES];
+	volatile u16 *p_cpucount[NUM_TX_QUEUES];
+	int indAddrRegUsed[NUM_OF_PADDRS];
+	enet_addr_t paddr[NUM_OF_PADDRS];
+	u8 numGroupAddrInHash;
+	u8 numIndAddrInHash;
+	u8 numIndAddrInReg;
+	int rx_extended_features;
+	int rx_non_dynamic_extended_features;
+	struct list_head conf_skbs;
+	struct list_head group_hash_q;
+	struct list_head ind_hash_q;
+	u32 saved_uccm;
+	spinlock_t lock;
+	/* pointers to arrays of skbuffs for tx and rx */
+	struct sk_buff **tx_skbuff[NUM_TX_QUEUES];
+	struct sk_buff **rx_skbuff[NUM_RX_QUEUES];
+	/* indices pointing to the next free sbk in skb arrays */
+	u16 skb_curtx[NUM_TX_QUEUES];
+	u16 skb_currx[NUM_RX_QUEUES];
+	/* index of the first skb which hasn't been transmitted yet. */
+	u16 skb_dirtytx[NUM_TX_QUEUES];
+
+	struct work_struct tq;
+	struct timer_list phy_info_timer;
+	struct ugeth_mii_info *mii_info;
+	int oldspeed;
+	int oldduplex;
+	int oldlink;
+} ucc_geth_private_t;
+
+#endif				/* __UCC_GETH_H__ */
diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c
new file mode 100644
index 0000000..6ea1dbe
--- /dev/null
+++ b/drivers/net/ucc_geth_phy.c
@@ -0,0 +1,801 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights
reserved.
+ *
+ * Author: Shlomi Gridish <gridish@freescale.com>
+ *
+ * Description:
+ * UCC GETH Driver -- PHY handling
+ *
+ * Changelog:
+ * Jun 28, 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/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "ucc_geth.h"
+#include "ucc_geth_phy.h"
+#include <platforms/83xx/mpc8360e_pb.h>
+
+#define ugphy_printk(level, format, arg...)  \
+        printk(level format "\n", ## arg)
+
+#define ugphy_dbg(format, arg...)            \
+        ugphy_printk(KERN_DEBUG, format , ## arg)
+#define ugphy_err(format, arg...)            \
+        ugphy_printk(KERN_ERR, format , ## arg)
+#define ugphy_info(format, arg...)           \
+        ugphy_printk(KERN_INFO, format , ## arg)
+#define ugphy_warn(format, arg...)           \
+        ugphy_printk(KERN_WARNING, format , ## arg)
+
+#ifdef UGETH_VERBOSE_DEBUG
+#define ugphy_vdbg ugphy_dbg
+#else
+#define ugphy_vdbg(fmt, args...) do { } while (0)
+#endif				/* UGETH_VERBOSE_DEBUG */
+
+static void config_genmii_advert(struct ugeth_mii_info *mii_info);
+static void genmii_setup_forced(struct ugeth_mii_info *mii_info);
+static void genmii_restart_aneg(struct ugeth_mii_info *mii_info);
+static int gbit_config_aneg(struct ugeth_mii_info *mii_info);
+static int genmii_config_aneg(struct ugeth_mii_info *mii_info);
+static int genmii_update_link(struct ugeth_mii_info *mii_info);
+static int genmii_read_status(struct ugeth_mii_info *mii_info);
+u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum);
+void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val);
+
+static u8 *bcsr_regs =3D NULL;
+
+/* Write value to the PHY for this device to the register at regnum, */
+/* waiting until the write is done before it returns.  All PHY */
+/* configuration has to be done through the TSEC1 MIIM regs */
+void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int
value)
+{
+	ucc_geth_private_t *ugeth =3D netdev_priv(dev);
+	ucc_mii_mng_t *mii_regs;
+	enet_tbi_mii_reg_e mii_reg =3D (enet_tbi_mii_reg_e) regnum;
+	u32 tmp_reg;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	spin_lock_irq(&ugeth->lock);
+
+	mii_regs =3D ugeth->mii_info->mii_regs;
+
+	/* Set this UCC to be the master of the MII managment */
+	ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num);
+
+	/* Stop the MII management read cycle */
+	out_be32(&mii_regs->miimcom, 0);
+	/* Setting up the MII Mangement Address Register */
+	tmp_reg =3D ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
+	out_be32(&mii_regs->miimadd, tmp_reg);
+
+	/* Setting up the MII Mangement Control Register with the value
*/
+	out_be32(&mii_regs->miimcon, (u32) value);
+
+	/* Wait till MII management write is complete */
+	while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY)
+		cpu_relax();
+
+	spin_unlock_irq(&ugeth->lock);
+
+	udelay(10000);
+}
+
+/* Reads from register regnum in the PHY for device dev, */
+/* returning the value.  Clears miimcom first.  All PHY */
+/* configuration has to be done through the TSEC1 MIIM regs */
+int read_phy_reg(struct net_device *dev, int mii_id, int regnum)
+{
+	ucc_geth_private_t *ugeth =3D netdev_priv(dev);
+	ucc_mii_mng_t *mii_regs;
+	enet_tbi_mii_reg_e mii_reg =3D (enet_tbi_mii_reg_e) regnum;
+	u32 tmp_reg;
+	u16 value;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	spin_lock_irq(&ugeth->lock);
+
+	mii_regs =3D ugeth->mii_info->mii_regs;
+
+	/* Setting up the MII Mangement Address Register */
+	tmp_reg =3D ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
+	out_be32(&mii_regs->miimadd, tmp_reg);
+
+	/* Perform an MII management read cycle */
+	out_be32(&mii_regs->miimcom, MIIMCOM_READ_CYCLE);
+
+	/* Wait till MII management write is complete */
+	while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY)
+		cpu_relax();
+
+	udelay(10000);
+
+	/* Read MII management status  */
+	value =3D (u16) in_be32(&mii_regs->miimstat);
+	out_be32(&mii_regs->miimcom, 0);
+	if (value =3D=3D 0xffff)
+		ugphy_warn("read wrong value : mii_id %d,mii_reg %d,
base %08x",
+			   mii_id, mii_reg, (u32) &
(mii_regs->miimcfg));
+
+	spin_unlock_irq(&ugeth->lock);
+
+	return (value);
+}
+
+void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info)
+{
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	if (mii_info->phyinfo->ack_interrupt)
+		mii_info->phyinfo->ack_interrupt(mii_info);
+}
+
+void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
+				 u32 interrupts)
+{
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	mii_info->interrupts =3D interrupts;
+	if (mii_info->phyinfo->config_intr)
+		mii_info->phyinfo->config_intr(mii_info);
+}
+
+/* Writes MII_ADVERTISE with the appropriate values, after
+ * sanitizing advertise to make sure only supported features
+ * are advertised=20
+ */
+static void config_genmii_advert(struct ugeth_mii_info *mii_info)
+{
+	u32 advertise;
+	u16 adv;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	/* Only allow advertising what this PHY supports */
+	mii_info->advertising &=3D mii_info->phyinfo->features;
+	advertise =3D mii_info->advertising;
+
+	/* Setup standard advertisement */
+	adv =3D phy_read(mii_info, MII_ADVERTISE);
+	adv &=3D ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+	if (advertise & ADVERTISED_10baseT_Half)
+		adv |=3D ADVERTISE_10HALF;
+	if (advertise & ADVERTISED_10baseT_Full)
+		adv |=3D ADVERTISE_10FULL;
+	if (advertise & ADVERTISED_100baseT_Half)
+		adv |=3D ADVERTISE_100HALF;
+	if (advertise & ADVERTISED_100baseT_Full)
+		adv |=3D ADVERTISE_100FULL;
+	phy_write(mii_info, MII_ADVERTISE, adv);
+}
+
+static void genmii_setup_forced(struct ugeth_mii_info *mii_info)
+{
+	u16 ctrl;
+	u32 features =3D mii_info->phyinfo->features;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	ctrl =3D phy_read(mii_info, MII_BMCR);
+
+	ctrl &=3D
+	    ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 |
BMCR_ANENABLE);
+	ctrl |=3D BMCR_RESET;
+
+	switch (mii_info->speed) {
+	case SPEED_1000:
+		if (features & (SUPPORTED_1000baseT_Half
+				| SUPPORTED_1000baseT_Full)) {
+			ctrl |=3D BMCR_SPEED1000;
+			break;
+		}
+		mii_info->speed =3D SPEED_100;
+	case SPEED_100:
+		if (features & (SUPPORTED_100baseT_Half
+				| SUPPORTED_100baseT_Full)) {
+			ctrl |=3D BMCR_SPEED100;
+			break;
+		}
+		mii_info->speed =3D SPEED_10;
+	case SPEED_10:
+		if (features & (SUPPORTED_10baseT_Half
+				| SUPPORTED_10baseT_Full))
+			break;
+	default:		/* Unsupported speed! */
+		ugphy_err("%s: Bad speed!", mii_info->dev->name);
+		break;
+	}
+
+	phy_write(mii_info, MII_BMCR, ctrl);
+}
+
+/* Enable and Restart Autonegotiation */
+static void genmii_restart_aneg(struct ugeth_mii_info *mii_info)
+{
+	u16 ctl;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	ctl =3D phy_read(mii_info, MII_BMCR);
+	ctl |=3D (BMCR_ANENABLE | BMCR_ANRESTART);
+	phy_write(mii_info, MII_BMCR, ctl);
+}
+
+static int gbit_config_aneg(struct ugeth_mii_info *mii_info)
+{
+	u16 adv;
+	u32 advertise;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	if (mii_info->autoneg) {
+		/* Configure the ADVERTISE register */
+		config_genmii_advert(mii_info);
+		advertise =3D mii_info->advertising;
+
+		adv =3D phy_read(mii_info, MII_1000BASETCONTROL);
+		adv &=3D ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
+			 MII_1000BASETCONTROL_HALFDUPLEXCAP);
+		if (advertise & SUPPORTED_1000baseT_Half)
+			adv |=3D MII_1000BASETCONTROL_HALFDUPLEXCAP;
+		if (advertise & SUPPORTED_1000baseT_Full)
+			adv |=3D MII_1000BASETCONTROL_FULLDUPLEXCAP;
+		phy_write(mii_info, MII_1000BASETCONTROL, adv);
+
+		/* Start/Restart aneg */
+		genmii_restart_aneg(mii_info);
+	} else
+		genmii_setup_forced(mii_info);
+
+	return 0;
+}
+
+static int genmii_config_aneg(struct ugeth_mii_info *mii_info)
+{
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	if (mii_info->autoneg) {
+		config_genmii_advert(mii_info);
+		genmii_restart_aneg(mii_info);
+	} else
+		genmii_setup_forced(mii_info);
+
+	return 0;
+}
+
+static int genmii_update_link(struct ugeth_mii_info *mii_info)
+{
+	u16 status;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	/* Do a fake read */
+	phy_read(mii_info, MII_BMSR);
+
+	/* Read link and autonegotiation status */
+	status =3D phy_read(mii_info, MII_BMSR);
+	if ((status & BMSR_LSTATUS) =3D=3D 0)
+		mii_info->link =3D 0;
+	else
+		mii_info->link =3D 1;
+
+	/* If we are autonegotiating, and not done,=20
+	 * return an error */
+	if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE))
+		return -EAGAIN;
+
+	return 0;
+}
+
+static int genmii_read_status(struct ugeth_mii_info *mii_info)
+{
+	u16 status;
+	int err;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	/* Update the link, but return if there
+	 * was an error */
+	err =3D genmii_update_link(mii_info);
+	if (err)
+		return err;
+
+	if (mii_info->autoneg) {
+		status =3D phy_read(mii_info, MII_LPA);
+
+		if (status & (LPA_10FULL | LPA_100FULL))
+			mii_info->duplex =3D DUPLEX_FULL;
+		else
+			mii_info->duplex =3D DUPLEX_HALF;
+		if (status & (LPA_100FULL | LPA_100HALF))
+			mii_info->speed =3D SPEED_100;
+		else
+			mii_info->speed =3D SPEED_10;
+		mii_info->pause =3D 0;
+	}
+	/* On non-aneg, we assume what we put in BMCR is the speed,
+	 * though magic-aneg shouldn't prevent this case from occurring
+	 */
+
+	return 0;
+}
+
+static int marvell_init(struct ugeth_mii_info *mii_info)
+{
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	phy_write(mii_info, 0x14, 0x0cd2);
+	phy_write(mii_info, MII_BMCR,
+		  phy_read(mii_info, MII_BMCR) | BMCR_RESET);
+	msleep(4000);
+
+	return 0;
+}
+
+static int marvell_config_aneg(struct ugeth_mii_info *mii_info)
+{
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	/* The Marvell PHY has an errata which requires
+	 * that certain registers get written in order
+	 * to restart autonegotiation */
+	phy_write(mii_info, MII_BMCR, BMCR_RESET);
+
+	phy_write(mii_info, 0x1d, 0x1f);
+	phy_write(mii_info, 0x1e, 0x200c);
+	phy_write(mii_info, 0x1d, 0x5);
+	phy_write(mii_info, 0x1e, 0);
+	phy_write(mii_info, 0x1e, 0x100);
+
+	gbit_config_aneg(mii_info);
+
+	return 0;
+}
+
+static int marvell_read_status(struct ugeth_mii_info *mii_info)
+{
+	u16 status;
+	int err;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	/* Update the link, but return if there
+	 * was an error */
+	err =3D genmii_update_link(mii_info);
+	if (err)
+		return err;
+
+	/* If the link is up, read the speed and duplex */
+	/* If we aren't autonegotiating, assume speeds=20
+	 * are as set */
+	if (mii_info->autoneg && mii_info->link) {
+		int speed;
+		status =3D phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS);
+
+		/* Get the duplexity */
+		if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
+			mii_info->duplex =3D DUPLEX_FULL;
+		else
+			mii_info->duplex =3D DUPLEX_HALF;
+
+		/* Get the speed */
+		speed =3D status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK;
+		switch (speed) {
+		case MII_M1011_PHY_SPEC_STATUS_1000:
+			mii_info->speed =3D SPEED_1000;
+			break;
+		case MII_M1011_PHY_SPEC_STATUS_100:
+			mii_info->speed =3D SPEED_100;
+			break;
+		default:
+			mii_info->speed =3D SPEED_10;
+			break;
+		}
+		mii_info->pause =3D 0;
+	}
+
+	return 0;
+}
+
+static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info)
+{
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	/* Clear the interrupts by reading the reg */
+	phy_read(mii_info, MII_M1011_IEVENT);
+
+	return 0;
+}
+
+static int marvell_config_intr(struct ugeth_mii_info *mii_info)
+{
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	if (mii_info->interrupts =3D=3D MII_INTERRUPT_ENABLED)
+		phy_write(mii_info, MII_M1011_IMASK,
MII_M1011_IMASK_INIT);
+	else
+		phy_write(mii_info, MII_M1011_IMASK,
MII_M1011_IMASK_CLEAR);
+
+	return 0;
+}
+
+static int cis820x_init(struct ugeth_mii_info *mii_info)
+{
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	phy_write(mii_info, MII_CIS8201_AUX_CONSTAT,
+		  MII_CIS8201_AUXCONSTAT_INIT);
+	phy_write(mii_info, MII_CIS8201_EXT_CON1,
MII_CIS8201_EXTCON1_INIT);
+
+	return 0;
+}
+
+static int cis820x_read_status(struct ugeth_mii_info *mii_info)
+{
+	u16 status;
+	int err;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	/* Update the link, but return if there
+	 * was an error */
+	err =3D genmii_update_link(mii_info);
+	if (err)
+		return err;
+
+	/* If the link is up, read the speed and duplex */
+	/* If we aren't autonegotiating, assume speeds=20
+	 * are as set */
+	if (mii_info->autoneg && mii_info->link) {
+		int speed;
+
+		status =3D phy_read(mii_info, MII_CIS8201_AUX_CONSTAT);
+		if (status & MII_CIS8201_AUXCONSTAT_DUPLEX)
+			mii_info->duplex =3D DUPLEX_FULL;
+		else
+			mii_info->duplex =3D DUPLEX_HALF;
+
+		speed =3D status & MII_CIS8201_AUXCONSTAT_SPEED;
+
+		switch (speed) {
+		case MII_CIS8201_AUXCONSTAT_GBIT:
+			mii_info->speed =3D SPEED_1000;
+			break;
+		case MII_CIS8201_AUXCONSTAT_100:
+			mii_info->speed =3D SPEED_100;
+			break;
+		default:
+			mii_info->speed =3D SPEED_10;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info)
+{
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	phy_read(mii_info, MII_CIS8201_ISTAT);
+
+	return 0;
+}
+
+static int cis820x_config_intr(struct ugeth_mii_info *mii_info)
+{
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	if (mii_info->interrupts =3D=3D MII_INTERRUPT_ENABLED)
+		phy_write(mii_info, MII_CIS8201_IMASK,
MII_CIS8201_IMASK_MASK);
+	else
+		phy_write(mii_info, MII_CIS8201_IMASK, 0);
+
+	return 0;
+}
+
+#define DM9161_DELAY 10
+
+static int dm9161_read_status(struct ugeth_mii_info *mii_info)
+{
+	u16 status;
+	int err;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	/* Update the link, but return if there
+	 * was an error */
+	err =3D genmii_update_link(mii_info);
+	if (err)
+		return err;
+
+	/* If the link is up, read the speed and duplex */
+	/* If we aren't autonegotiating, assume speeds=20
+	 * are as set */
+	if (mii_info->autoneg && mii_info->link) {
+		status =3D phy_read(mii_info, MII_DM9161_SCSR);
+		if (status & (MII_DM9161_SCSR_100F |
MII_DM9161_SCSR_100H))
+			mii_info->speed =3D SPEED_100;
+		else
+			mii_info->speed =3D SPEED_10;
+
+		if (status & (MII_DM9161_SCSR_100F |
MII_DM9161_SCSR_10F))
+			mii_info->duplex =3D DUPLEX_FULL;
+		else
+			mii_info->duplex =3D DUPLEX_HALF;
+	}
+
+	return 0;
+}
+
+static int dm9161_config_aneg(struct ugeth_mii_info *mii_info)
+{
+	struct dm9161_private *priv =3D mii_info->priv;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	if (0 =3D=3D priv->resetdone)
+		return -EAGAIN;
+
+	return 0;
+}
+
+static void dm9161_timer(unsigned long data)
+{
+	struct ugeth_mii_info *mii_info =3D (struct ugeth_mii_info *)data;
+	struct dm9161_private *priv =3D mii_info->priv;
+	u16 status =3D phy_read(mii_info, MII_BMSR);
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	if (status & BMSR_ANEGCOMPLETE) {
+		priv->resetdone =3D 1;
+	} else
+		mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
+}
+
+static int dm9161_init(struct ugeth_mii_info *mii_info)
+{
+	struct dm9161_private *priv;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	/* Allocate the private data structure */
+	priv =3D kmalloc(sizeof(struct dm9161_private), GFP_KERNEL);
+
+	if (NULL =3D=3D priv)
+		return -ENOMEM;
+
+	mii_info->priv =3D priv;
+
+	/* Reset is not done yet */
+	priv->resetdone =3D 0;
+
+	phy_write(mii_info, MII_BMCR,
+		  phy_read(mii_info, MII_BMCR) | BMCR_RESET);
+
+	phy_write(mii_info, MII_BMCR,
+		  phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE);
+
+	config_genmii_advert(mii_info);
+	/* Start/Restart aneg */
+	genmii_config_aneg(mii_info);
+
+	/* Start a timer for DM9161_DELAY seconds to wait
+	 * for the PHY to be ready */
+	init_timer(&priv->timer);
+	priv->timer.function =3D &dm9161_timer;
+	priv->timer.data =3D (unsigned long)mii_info;
+	mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
+
+	return 0;
+}
+
+static void dm9161_close(struct ugeth_mii_info *mii_info)
+{
+	struct dm9161_private *priv =3D mii_info->priv;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	del_timer_sync(&priv->timer);
+	kfree(priv);
+}
+
+static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info)
+{
+/* FIXME: This lines are for BUG fixing in the mpc8325.=20
+Remove this from here when it's fixed */
+	if (bcsr_regs =3D=3D NULL)
+		bcsr_regs =3D (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE);
+	bcsr_regs[14] |=3D 0x40;
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	/* Clear the interrupts by reading the reg */
+	phy_read(mii_info, MII_DM9161_INTR);
+=09
+
+	return 0;
+}
+
+static int dm9161_config_intr(struct ugeth_mii_info *mii_info)
+{
+/* FIXME: This lines are for BUG fixing in the mpc8325.=20
+Remove this from here when it's fixed */
+	if (bcsr_regs =3D=3D NULL) {
+		bcsr_regs =3D (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE);
+		bcsr_regs[14] &=3D ~0x40;
+	}
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	if (mii_info->interrupts =3D=3D MII_INTERRUPT_ENABLED)
+		phy_write(mii_info, MII_DM9161_INTR,
MII_DM9161_INTR_INIT);
+	else
+		phy_write(mii_info, MII_DM9161_INTR,
MII_DM9161_INTR_STOP);
+
+	return 0;
+}
+
+/* Cicada 820x */
+static struct phy_info phy_info_cis820x =3D {
+	.phy_id =3D 0x000fc440,
+	.name =3D "Cicada Cis8204",
+	.phy_id_mask =3D 0x000fffc0,
+	.features =3D MII_GBIT_FEATURES,
+	.init =3D &cis820x_init,
+	.config_aneg =3D &gbit_config_aneg,
+	.read_status =3D &cis820x_read_status,
+	.ack_interrupt =3D &cis820x_ack_interrupt,
+	.config_intr =3D &cis820x_config_intr,
+};
+
+static struct phy_info phy_info_dm9161 =3D {
+	.phy_id =3D 0x0181b880,
+	.phy_id_mask =3D 0x0ffffff0,
+	.name =3D "Davicom DM9161E",
+	.init =3D dm9161_init,
+	.config_aneg =3D dm9161_config_aneg,
+	.read_status =3D dm9161_read_status,
+	.close =3D dm9161_close,
+};
+
+static struct phy_info phy_info_dm9161a =3D {
+	.phy_id =3D 0x0181b8a0,
+	.phy_id_mask =3D 0x0ffffff0,
+	.name =3D "Davicom DM9161A",
+	.features =3D MII_BASIC_FEATURES,
+	.init =3D dm9161_init,
+	.config_aneg =3D dm9161_config_aneg,
+	.read_status =3D dm9161_read_status,
+	.ack_interrupt =3D dm9161_ack_interrupt,
+	.config_intr =3D dm9161_config_intr,
+	.close =3D dm9161_close,
+};
+
+static struct phy_info phy_info_marvell =3D {
+	.phy_id =3D 0x01410c00,
+	.phy_id_mask =3D 0xffffff00,
+	.name =3D "Marvell 88E11x1",
+	.features =3D MII_GBIT_FEATURES,
+	.init =3D &marvell_init,
+	.config_aneg =3D &marvell_config_aneg,
+	.read_status =3D &marvell_read_status,
+	.ack_interrupt =3D &marvell_ack_interrupt,
+	.config_intr =3D &marvell_config_intr,
+};
+
+static struct phy_info phy_info_genmii =3D {
+	.phy_id =3D 0x00000000,
+	.phy_id_mask =3D 0x00000000,
+	.name =3D "Generic MII",
+	.features =3D MII_BASIC_FEATURES,
+	.config_aneg =3D genmii_config_aneg,
+	.read_status =3D genmii_read_status,
+};
+
+static struct phy_info *phy_info[] =3D {
+	&phy_info_cis820x,
+	&phy_info_marvell,
+	&phy_info_dm9161,
+	&phy_info_dm9161a,
+	&phy_info_genmii,
+	NULL
+};
+
+u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum)
+{
+	u16 retval;
+	unsigned long flags;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	spin_lock_irqsave(&mii_info->mdio_lock, flags);
+	retval =3D mii_info->mdio_read(mii_info->dev, mii_info->mii_id,
regnum);
+	spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
+
+	return retval;
+}
+
+void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val)
+{
+	unsigned long flags;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	spin_lock_irqsave(&mii_info->mdio_lock, flags);
+	mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum,
val);
+	spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
+}
+
+/* Use the PHY ID registers to determine what type of PHY is attached
+ * to device dev.  return a struct phy_info structure describing that
PHY
+ */
+struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info)
+{
+	u16 phy_reg;
+	u32 phy_ID;
+	int i;
+	struct phy_info *theInfo =3D NULL;
+	struct net_device *dev =3D mii_info->dev;
+
+	ugphy_vdbg("%s: IN", __FUNCTION__);
+
+	/* Grab the bits from PHYIR1, and put them in the upper half */
+	phy_reg =3D phy_read(mii_info, MII_PHYSID1);
+	phy_ID =3D (phy_reg & 0xffff) << 16;
+
+	/* Grab the bits from PHYIR2, and put them in the lower half */
+	phy_reg =3D phy_read(mii_info, MII_PHYSID2);
+	phy_ID |=3D (phy_reg & 0xffff);
+
+	/* loop through all the known PHY types, and find one that */
+	/* matches the ID we read from the PHY. */
+	for (i =3D 0; phy_info[i]; i++)
+		if (phy_info[i]->phy_id =3D=3D (phy_ID &
phy_info[i]->phy_id_mask)){
+			theInfo =3D phy_info[i];
+			break;
+		}
+
+	/* This shouldn't happen, as we have generic PHY support */
+	if (theInfo =3D=3D NULL) {
+		ugphy_info("%s: PHY id %x is not supported!", dev->name,
+			   phy_ID);
+		return NULL;
+	} else {
+		ugphy_info("%s: PHY is %s (%x)", dev->name,
theInfo->name,
+			   phy_ID);
+	}
+
+	return theInfo;
+}
diff --git a/drivers/net/ucc_geth_phy.h b/drivers/net/ucc_geth_phy.h
new file mode 100644
index 0000000..2f98b8f
--- /dev/null
+++ b/drivers/net/ucc_geth_phy.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights
reserved.
+ *
+ * Author: Shlomi Gridish <gridish@freescale.com>
+ *
+ * Description:
+ * UCC GETH Driver -- PHY handling
+ *
+ * Changelog:
+ * Jun 28, 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.
+ *
+ */
+#ifndef __UCC_GETH_PHY_H__
+#define __UCC_GETH_PHY_H__
+
+#define MII_end ((u32)-2)
+#define MII_read ((u32)-1)
+
+#define MIIMIND_BUSY            0x00000001
+#define MIIMIND_NOTVALID        0x00000004
+
+#define UGETH_AN_TIMEOUT        2000
+
+/* 1000BT control (Marvell & BCM54xx at least) */
+#define MII_1000BASETCONTROL                  0x09
+#define MII_1000BASETCONTROL_FULLDUPLEXCAP    0x0200
+#define MII_1000BASETCONTROL_HALFDUPLEXCAP    0x0100
+
+/* Cicada Extended Control Register 1 */
+#define MII_CIS8201_EXT_CON1        0x17
+#define MII_CIS8201_EXTCON1_INIT    0x0000
+
+/* Cicada Interrupt Mask Register */
+#define MII_CIS8201_IMASK           0x19
+#define MII_CIS8201_IMASK_IEN       0x8000
+#define MII_CIS8201_IMASK_SPEED     0x4000
+#define MII_CIS8201_IMASK_LINK      0x2000
+#define MII_CIS8201_IMASK_DUPLEX    0x1000
+#define MII_CIS8201_IMASK_MASK      0xf000
+
+/* Cicada Interrupt Status Register */
+#define MII_CIS8201_ISTAT           0x1a
+#define MII_CIS8201_ISTAT_STATUS    0x8000
+#define MII_CIS8201_ISTAT_SPEED     0x4000
+#define MII_CIS8201_ISTAT_LINK      0x2000
+#define MII_CIS8201_ISTAT_DUPLEX    0x1000
+
+/* Cicada Auxiliary Control/Status Register */
+#define MII_CIS8201_AUX_CONSTAT        0x1c
+#define MII_CIS8201_AUXCONSTAT_INIT    0x0004
+#define MII_CIS8201_AUXCONSTAT_DUPLEX  0x0020
+#define MII_CIS8201_AUXCONSTAT_SPEED   0x0018
+#define MII_CIS8201_AUXCONSTAT_GBIT    0x0010
+#define MII_CIS8201_AUXCONSTAT_100     0x0008
+
+/* 88E1011 PHY Status Register */
+#define MII_M1011_PHY_SPEC_STATUS               0x11
+#define MII_M1011_PHY_SPEC_STATUS_1000          0x8000
+#define MII_M1011_PHY_SPEC_STATUS_100           0x4000
+#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK      0xc000
+#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX    0x2000
+#define MII_M1011_PHY_SPEC_STATUS_RESOLVED      0x0800
+#define MII_M1011_PHY_SPEC_STATUS_LINK          0x0400
+
+#define MII_M1011_IEVENT                0x13
+#define MII_M1011_IEVENT_CLEAR          0x0000
+
+#define MII_M1011_IMASK                 0x12
+#define MII_M1011_IMASK_INIT            0x6400
+#define MII_M1011_IMASK_CLEAR           0x0000
+
+#define MII_DM9161_SCR                  0x10
+#define MII_DM9161_SCR_INIT             0x0610
+
+/* DM9161 Specified Configuration and Status Register */
+#define MII_DM9161_SCSR                 0x11
+#define MII_DM9161_SCSR_100F            0x8000
+#define MII_DM9161_SCSR_100H            0x4000
+#define MII_DM9161_SCSR_10F             0x2000
+#define MII_DM9161_SCSR_10H             0x1000
+
+/* DM9161 Interrupt Register */
+#define MII_DM9161_INTR                 0x15
+#define MII_DM9161_INTR_PEND            0x8000
+#define MII_DM9161_INTR_DPLX_MASK       0x0800
+#define MII_DM9161_INTR_SPD_MASK        0x0400
+#define MII_DM9161_INTR_LINK_MASK       0x0200
+#define MII_DM9161_INTR_MASK            0x0100
+#define MII_DM9161_INTR_DPLX_CHANGE     0x0010
+#define MII_DM9161_INTR_SPD_CHANGE      0x0008
+#define MII_DM9161_INTR_LINK_CHANGE     0x0004
+#define MII_DM9161_INTR_INIT            0x0000
+#define MII_DM9161_INTR_STOP    \
+(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
+ | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
+
+/* DM9161 10BT Configuration/Status */
+#define MII_DM9161_10BTCSR              0x12
+#define MII_DM9161_10BTCSR_INIT         0x7800
+
+#define MII_BASIC_FEATURES    (SUPPORTED_10baseT_Half | \
+                 SUPPORTED_10baseT_Full | \
+                 SUPPORTED_100baseT_Half | \
+                 SUPPORTED_100baseT_Full | \
+                 SUPPORTED_Autoneg | \
+                 SUPPORTED_TP | \
+                 SUPPORTED_MII)
+
+#define MII_GBIT_FEATURES    (MII_BASIC_FEATURES | \
+                 SUPPORTED_1000baseT_Half | \
+                 SUPPORTED_1000baseT_Full)
+
+#define MII_READ_COMMAND                0x00000001
+
+#define MII_INTERRUPT_DISABLED          0x0
+#define MII_INTERRUPT_ENABLED           0x1
+/* Taken from mii_if_info and sungem_phy.h */
+struct ugeth_mii_info {
+	/* Information about the PHY type */
+	/* And management functions */
+	struct phy_info *phyinfo;
+
+	ucc_mii_mng_t *mii_regs;
+
+	/* forced speed & duplex (no autoneg)
+	 * partner speed & duplex & pause (autoneg)
+	 */
+	int speed;
+	int duplex;
+	int pause;
+
+	/* The most recently read link state */
+	int link;
+
+	/* Enabled Interrupts */
+	u32 interrupts;
+
+	u32 advertising;
+	int autoneg;
+	int mii_id;
+
+	/* private data pointer */
+	/* For use by PHYs to maintain extra state */
+	void *priv;
+
+	/* Provided by host chip */
+	struct net_device *dev;
+
+	/* A lock to ensure that only one thing can read/write
+	 * the MDIO bus at a time */
+	spinlock_t mdio_lock;
+
+	/* Provided by ethernet driver */
+	int (*mdio_read) (struct net_device * dev, int mii_id, int reg);
+	void (*mdio_write) (struct net_device * dev, int mii_id, int
reg,
+			    int val);
+};
+
+/* struct phy_info: a structure which defines attributes for a PHY
+ *
+ * id will contain a number which represents the PHY.  During
+ * startup, the driver will poll the PHY to find out what its
+ * UID--as defined by registers 2 and 3--is.  The 32-bit result
+ * gotten from the PHY will be ANDed with phy_id_mask to
+ * discard any bits which may change based on revision numbers
+ * unimportant to functionality
+ *
+ * There are 6 commands which take a ugeth_mii_info structure.
+ * Each PHY must declare config_aneg, and read_status.
+ */
+struct phy_info {
+	u32 phy_id;
+	char *name;
+	unsigned int phy_id_mask;
+	u32 features;
+
+	/* Called to initialize the PHY */
+	int (*init) (struct ugeth_mii_info * mii_info);
+
+	/* Called to suspend the PHY for power */
+	int (*suspend) (struct ugeth_mii_info * mii_info);
+
+	/* Reconfigures autonegotiation (or disables it) */
+	int (*config_aneg) (struct ugeth_mii_info * mii_info);
+
+	/* Determines the negotiated speed and duplex */
+	int (*read_status) (struct ugeth_mii_info * mii_info);
+
+	/* Clears any pending interrupts */
+	int (*ack_interrupt) (struct ugeth_mii_info * mii_info);
+
+	/* Enables or disables interrupts */
+	int (*config_intr) (struct ugeth_mii_info * mii_info);
+
+	/* Clears up any memory if needed */
+	void (*close) (struct ugeth_mii_info * mii_info);
+};
+
+struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info);
+void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int
value);
+int read_phy_reg(struct net_device *dev, int mii_id, int regnum);
+void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info);
+void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
+				 u32 interrupts);
+
+struct dm9161_private {
+	struct timer_list timer;
+	int resetdone;
+};
+
+#endif				/* __UCC_GETH_PHY_H__ */

^ permalink raw reply related

* [PATCH 2/3] Freescale QE UCC gigabit ethernet driver
From: Li Yang-r58472 @ 2006-07-06 12:02 UTC (permalink / raw)
  To: Andrew Morton, jgarzik; +Cc: netdev, linuxppc-dev

continues [PATCH 1/3] Freescale QE UCC gigabit ethernet driver

---
+
+static int
ugeth_82xx_filtering_clear_all_addr_in_hash(ucc_geth_private_t *
+						       ugeth,
+						       enet_addr_type_e
+						       enet_addr_type)
+{
+	ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
+	ucc_fast_private_t *uccf;
+	comm_dir_e comm_dir;
+	struct list_head *p_lh;
+	u16 i, num;
+	u32 *addr_h, *addr_l;
+	u8 *p_counter;
+
+	uccf =3D ugeth->uccf;
+
+	p_82xx_addr_filt =3D
+	    (ucc_geth_82xx_address_filtering_pram_t *)
ugeth->p_rx_glbl_pram->
+	    addressfiltering;
+
+	if (enet_addr_type =3D=3D ENET_ADDR_TYPE_GROUP) {
+		addr_h =3D &(p_82xx_addr_filt->gaddr_h);
+		addr_l =3D &(p_82xx_addr_filt->gaddr_l);
+		p_lh =3D &ugeth->group_hash_q;
+		p_counter =3D &(ugeth->numGroupAddrInHash);
+	} else if (enet_addr_type =3D=3D ENET_ADDR_TYPE_INDIVIDUAL) {
+		addr_h =3D &(p_82xx_addr_filt->iaddr_h);
+		addr_l =3D &(p_82xx_addr_filt->iaddr_l);
+		p_lh =3D &ugeth->ind_hash_q;
+		p_counter =3D &(ugeth->numIndAddrInHash);
+	} else
+		return -EINVAL;
+
+	comm_dir =3D 0;
+	if (uccf->enabled_tx)
+		comm_dir |=3D COMM_DIR_TX;
+	if (uccf->enabled_rx)
+		comm_dir |=3D 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);
+
+	if (!p_lh)
+		return 0;
+
+	num =3D *p_counter;
+
+	/* Delete all remaining CQ elements */
+	for (i =3D 0; i < num; i++)
+
put_enet_addr_container(ENET_ADDR_CONT_ENTRY(dequeue(p_lh)));
+
+	*p_counter =3D 0;
+
+	if (comm_dir)
+		ugeth_enable(ugeth, comm_dir);
+
+	return 0;
+}
+
+#ifdef CONFIG_UGETH_FILTERING
+static int ugeth_82xx_filtering_add_addr_in_paddr(ucc_geth_private_t
*ugeth,
+						  enet_addr_t
*p_enet_addr,
+						  u8 paddr_num)
+{
+	int i;
+
+	if ((*p_enet_addr)[0] & ENET_GROUP_ADDR)
+		ugeth_warn
+		    ("%s: multicast address added to paddr will have no
"
+		     "effect - is this what you wanted?",
+		     __FUNCTION__);
+
+	ugeth->indAddrRegUsed[paddr_num] =3D 1;	/* mark this paddr as
used */
+	/* store address in our database */
+	for (i =3D 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++)
+		ugeth->paddr[paddr_num][i] =3D (*p_enet_addr)[i];
+	/* put in hardware */
+	return hw_add_addr_in_paddr(ugeth, p_enet_addr, paddr_num);
+}
+#endif /* CONFIG_UGETH_FILTERING */
+
+static int ugeth_82xx_filtering_clear_addr_in_paddr(ucc_geth_private_t
*ugeth,
+						    u8 paddr_num)
+{
+	ugeth->indAddrRegUsed[paddr_num] =3D 0; /* mark this paddr as not
used */
+	return hw_clear_addr_in_paddr(ugeth, paddr_num);/* clear in
hardware */
+}
+
+static void ucc_geth_memclean(ucc_geth_private_t *ugeth)
+{
+	u16 i, j;
+	u8 *bd;
+
+	if (!ugeth)
+		return;
+
+	if (ugeth->uccf)
+		ucc_fast_free(ugeth->uccf);
+
+	if (ugeth->p_thread_data_tx) {
+		qe_muram_free(ugeth->thread_dat_tx_offset);
+		ugeth->p_thread_data_tx =3D NULL;
+	}
+	if (ugeth->p_thread_data_rx) {
+		qe_muram_free(ugeth->thread_dat_rx_offset);
+		ugeth->p_thread_data_rx =3D NULL;
+	}
+	if (ugeth->p_exf_glbl_param) {
+		qe_muram_free(ugeth->exf_glbl_param_offset);
+		ugeth->p_exf_glbl_param =3D NULL;
+	}
+	if (ugeth->p_rx_glbl_pram) {
+		qe_muram_free(ugeth->rx_glbl_pram_offset);
+		ugeth->p_rx_glbl_pram =3D NULL;
+	}
+	if (ugeth->p_tx_glbl_pram) {
+		qe_muram_free(ugeth->tx_glbl_pram_offset);
+		ugeth->p_tx_glbl_pram =3D NULL;
+	}
+	if (ugeth->p_send_q_mem_reg) {
+		qe_muram_free(ugeth->send_q_mem_reg_offset);
+		ugeth->p_send_q_mem_reg =3D NULL;
+	}
+	if (ugeth->p_scheduler) {
+		qe_muram_free(ugeth->scheduler_offset);
+		ugeth->p_scheduler =3D NULL;
+	}
+	if (ugeth->p_tx_fw_statistics_pram) {
+		qe_muram_free(ugeth->tx_fw_statistics_pram_offset);
+		ugeth->p_tx_fw_statistics_pram =3D NULL;
+	}
+	if (ugeth->p_rx_fw_statistics_pram) {
+		qe_muram_free(ugeth->rx_fw_statistics_pram_offset);
+		ugeth->p_rx_fw_statistics_pram =3D NULL;
+	}
+	if (ugeth->p_rx_irq_coalescing_tbl) {
+		qe_muram_free(ugeth->rx_irq_coalescing_tbl_offset);
+		ugeth->p_rx_irq_coalescing_tbl =3D NULL;
+	}
+	if (ugeth->p_rx_bd_qs_tbl) {
+		qe_muram_free(ugeth->rx_bd_qs_tbl_offset);
+		ugeth->p_rx_bd_qs_tbl =3D NULL;
+	}
+	if (ugeth->p_init_enet_param_shadow) {
+		return_init_enet_entries(ugeth,
+
&(ugeth->p_init_enet_param_shadow->
+					   rxthread[0]),
+					 ENET_INIT_PARAM_MAX_ENTRIES_RX,
+					 ugeth->ug_info->riscRx, 1);
+		return_init_enet_entries(ugeth,
+
&(ugeth->p_init_enet_param_shadow->
+					   txthread[0]),
+					 ENET_INIT_PARAM_MAX_ENTRIES_TX,
+					 ugeth->ug_info->riscTx, 0);
+		kfree(ugeth->p_init_enet_param_shadow);
+		ugeth->p_init_enet_param_shadow =3D NULL;
+	}
+	for (i =3D 0; i < ugeth->ug_info->numQueuesTx; i++) {
+		bd =3D ugeth->p_tx_bd_ring[i];
+		for (j =3D 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
+			if (ugeth->tx_skbuff[i][j]) {
+				dma_unmap_single(NULL,
+						 BD_BUFFER_ARG(bd),
+
(BD_STATUS_AND_LENGTH(bd) &
+						  BD_LENGTH_MASK),
+						 DMA_TO_DEVICE);
+
dev_kfree_skb_any(ugeth->tx_skbuff[i][j]);
+				ugeth->tx_skbuff[i][j] =3D NULL;
+			}
+		}
+
+		kfree(ugeth->tx_skbuff[i]);
+
+		if (ugeth->p_tx_bd_ring[i]) {
+			if (ugeth->ug_info->uf_info.bd_mem_part =3D=3D
+			    MEM_PART_SYSTEM)
+				kfree((void
*)ugeth->tx_bd_ring_offset[i]);
+			else if (ugeth->ug_info->uf_info.bd_mem_part =3D=3D
+				 MEM_PART_MURAM)
+
qe_muram_free(ugeth->tx_bd_ring_offset[i]);
+			ugeth->p_tx_bd_ring[i] =3D NULL;
+		}
+	}
+	for (i =3D 0; i < ugeth->ug_info->numQueuesRx; i++) {
+		if (ugeth->p_rx_bd_ring[i]) {
+			/* Return existing data buffers in ring */
+			bd =3D ugeth->p_rx_bd_ring[i];
+			for (j =3D 0; j < ugeth->ug_info->bdRingLenRx[i];
j++) {
+				if (ugeth->rx_skbuff[i][j]) {
+					dma_unmap_single(NULL,
BD_BUFFER(bd),
+						 ugeth->ug_info->
+						 uf_info.
+						 max_rx_buf_length +
+
UCC_GETH_RX_DATA_BUF_ALIGNMENT,
+						 DMA_FROM_DEVICE);
+
+					dev_kfree_skb_any(ugeth->
+
rx_skbuff[i][j]);
+					ugeth->rx_skbuff[i][j] =3D NULL;
+				}
+				bd +=3D UCC_GETH_SIZE_OF_BD;
+			}
+
+			kfree(ugeth->rx_skbuff[i]);
+
+			if (ugeth->ug_info->uf_info.bd_mem_part =3D=3D
+			    MEM_PART_SYSTEM)
+				kfree((void
*)ugeth->rx_bd_ring_offset[i]);
+			else if (ugeth->ug_info->uf_info.bd_mem_part =3D=3D
+				 MEM_PART_MURAM)
+
qe_muram_free(ugeth->rx_bd_ring_offset[i]);
+			ugeth->p_rx_bd_ring[i] =3D NULL;
+		}
+	}
+	while (!list_empty(&ugeth->group_hash_q))
+		put_enet_addr_container(ENET_ADDR_CONT_ENTRY
+
(dequeue(&ugeth->group_hash_q)));
+	while (!list_empty(&ugeth->ind_hash_q))
+		put_enet_addr_container(ENET_ADDR_CONT_ENTRY
+					(dequeue(&ugeth->ind_hash_q)));
+
+}
+
+static void ucc_geth_set_multi(struct net_device *dev)
+{
+	ucc_geth_private_t *ugeth;
+	struct dev_mc_list *dmi;
+	ucc_fast_t *uf_regs;
+	ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
+	enet_addr_t tempaddr;
+	u8 *mcptr, *tdptr;
+	int i, j;
+
+	ugeth =3D netdev_priv(dev);
+
+	uf_regs =3D ugeth->uccf->uf_regs;
+
+	if (dev->flags & IFF_PROMISC) {
+
+		/* Log any net taps. */
+		printk("%s: Promiscuous mode enabled.\n", dev->name);
+		uf_regs->upsmr |=3D UPSMR_PRO;
+
+	} else {
+
+		uf_regs->upsmr &=3D ~UPSMR_PRO;
+
+		p_82xx_addr_filt =3D
+		    (ucc_geth_82xx_address_filtering_pram_t *) ugeth->
+		    p_rx_glbl_pram->addressfiltering;
+
+		if (dev->flags & IFF_ALLMULTI) {
+			/* Catch all multicast addresses, so set the
+			 * filter to all 1's.
+			 */
+			out_be32(&p_82xx_addr_filt->gaddr_h,
0xffffffff);
+			out_be32(&p_82xx_addr_filt->gaddr_l,
0xffffffff);
+		} else {
+			/* Clear filter and add the addresses in the
list.
+			 */
+			out_be32(&p_82xx_addr_filt->gaddr_h, 0x0);
+			out_be32(&p_82xx_addr_filt->gaddr_l, 0x0);
+
+			dmi =3D dev->mc_list;
+
+			for (i =3D 0; i < dev->mc_count; i++, dmi =3D
dmi->next) {
+
+				/* Only support group multicast for now.
+				 */
+				if (!(dmi->dmi_addr[0] & 1))
+					continue;
+
+				/* The address in dmi_addr is LSB first,
+				 * and taddr is MSB first.  We have to
+				 * copy bytes MSB first from dmi_addr.
+				 */
+				mcptr =3D (u8 *) dmi->dmi_addr + 5;
+				tdptr =3D (u8 *) & tempaddr;
+				for (j =3D 0; j < 6; j++)
+					*tdptr++ =3D *mcptr--;
+
+				/* Ask CPM to run CRC and set bit in
+				 * filter mask.
+				 */
+				hw_add_addr_in_hash(ugeth, &tempaddr);
+
+			}
+		}
+	}
+}
+
+static void ucc_geth_stop(ucc_geth_private_t *ugeth)
+{
+	ucc_geth_t *ug_regs =3D ugeth->ug_regs;
+	u32 tempval;
+
+	ugeth_vdbg("%s: IN", __FUNCTION__);
+
+	/* Disable the controller */
+	ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
+
+	/* Tell the kernel the link is down */
+	ugeth->mii_info->link =3D 0;
+	adjust_link(ugeth->dev);
+
+	/* Mask all interrupts */
+	out_be32(ugeth->uccf->p_ucce, 0x00000000);
+
+	/* Clear all interrupts */
+	out_be32(ugeth->uccf->p_ucce, 0xffffffff);
+
+	/* Disable Rx and Tx */
+	tempval =3D in_be32(&ug_regs->maccfg1);
+	tempval &=3D ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
+	out_be32(&ug_regs->maccfg1, tempval);
+
+	if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
+		/* Clear any pending interrupts */
+		mii_clear_phy_interrupt(ugeth->mii_info);
+
+		/* Disable PHY Interrupts */
+		mii_configure_phy_interrupt(ugeth->mii_info,
+					    MII_INTERRUPT_DISABLED);
+	}
+
+	free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev);
+
+	if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
+		free_irq(ugeth->ug_info->phy_interrupt, ugeth->dev);
+	} else {
+		del_timer_sync(&ugeth->phy_info_timer);
+	}
+
+	ucc_geth_memclean(ugeth);
+}
+
+static int ucc_geth_startup(ucc_geth_private_t *ugeth)
+{
+	ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
+	ucc_geth_init_pram_t *p_init_enet_pram;
+	ucc_fast_private_t *uccf;
+	ucc_geth_info_t *ug_info;
+	ucc_fast_info_t *uf_info;
+	ucc_fast_t *uf_regs;
+	ucc_geth_t *ug_regs;
+	int ret_val =3D -EINVAL;
+	u32 remoder =3D UCC_GETH_REMODER_INIT;
+	u32 init_enet_pram_offset, cecr_subblock, command, maccfg1;
+	u32 ifstat, i, j, size, l2qt, l3qt, length;
+	u16 temoder =3D UCC_GETH_TEMODER_INIT;
+	u16 test;
+	u8 function_code =3D 0;
+	u8 *bd, *endOfRing;
+	u8 numThreadsRxNumerical, numThreadsTxNumerical;
+
+	ugeth_vdbg("%s: IN", __FUNCTION__);
+
+	ug_info =3D ugeth->ug_info;
+	uf_info =3D &ug_info->uf_info;
+
+	if (!((uf_info->bd_mem_part =3D=3D MEM_PART_SYSTEM) ||
+	      (uf_info->bd_mem_part =3D=3D MEM_PART_MURAM))) {
+		ugeth_err("%s: Bad memory partition value.",
__FUNCTION__);
+		return -EINVAL;
+	}
+
+	/* Rx BD lengths */
+	for (i =3D 0; i < ug_info->numQueuesRx; i++) {
+		if ((ug_info->bdRingLenRx[i] <
UCC_GETH_RX_BD_RING_SIZE_MIN) ||
+		    (ug_info->bdRingLenRx[i] %
+		     UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT)) {
+			ugeth_err
+			    ("%s: Rx BD ring length must be multiple of
4,"
+				" no smaller than 8.", __FUNCTION__);
+			return -EINVAL;
+		}
+	}
+
+	/* Tx BD lengths */
+	for (i =3D 0; i < ug_info->numQueuesTx; i++) {
+		if (ug_info->bdRingLenTx[i] <
UCC_GETH_TX_BD_RING_SIZE_MIN) {
+			ugeth_err
+			    ("%s: Tx BD ring length must be no smaller
than 2.",
+			     __FUNCTION__);
+			return -EINVAL;
+		}
+	}
+
+	/* mrblr */
+	if ((uf_info->max_rx_buf_length =3D=3D 0) ||
+	    (uf_info->max_rx_buf_length % UCC_GETH_MRBLR_ALIGNMENT)) {
+		ugeth_err
+		    ("%s: max_rx_buf_length must be non-zero multiple of
128.",
+		     __FUNCTION__);
+		return -EINVAL;
+	}
+
+	/* num Tx queues */
+	if (ug_info->numQueuesTx > NUM_TX_QUEUES) {
+		ugeth_err("%s: number of tx queues too large.",
__FUNCTION__);
+		return -EINVAL;
+	}
+
+	/* num Rx queues */
+	if (ug_info->numQueuesRx > NUM_RX_QUEUES) {
+		ugeth_err("%s: number of rx queues too large.",
__FUNCTION__);
+		return -EINVAL;
+	}
+
+	/* l2qt */
+	for (i =3D 0; i < UCC_GETH_VLAN_PRIORITY_MAX; i++) {
+		if (ug_info->l2qt[i] >=3D ug_info->numQueuesRx) {
+			ugeth_err
+			    ("%s: VLAN priority table entry must not be"
+				" larger than number of Rx queues.",
+			     __FUNCTION__);
+			return -EINVAL;
+		}
+	}
+
+	/* l3qt */
+	for (i =3D 0; i < UCC_GETH_IP_PRIORITY_MAX; i++) {
+		if (ug_info->l3qt[i] >=3D ug_info->numQueuesRx) {
+			ugeth_err
+			    ("%s: IP priority table entry must not be"
+				" larger than number of Rx queues.",
+			     __FUNCTION__);
+			return -EINVAL;
+		}
+	}
+
+	if (ug_info->cam && !ug_info->ecamptr) {
+		ugeth_err("%s: If cam mode is chosen, must supply cam
ptr.",
+			  __FUNCTION__);
+		return -EINVAL;
+	}
+
+	if ((ug_info->numStationAddresses !=3D
+	     UCC_GETH_NUM_OF_STATION_ADDRESSES_1)
+	    && ug_info->rxExtendedFiltering) {
+		ugeth_err("%s: Number of station addresses greater than
1 "
+			  "not allowed in extended parsing mode.",
+			  __FUNCTION__);
+		return -EINVAL;
+	}
+
+	/* Generate uccm_mask for receive */
+	uf_info->uccm_mask =3D ug_info->eventRegMask & UCCE_OTHER;/*
Errors */
+	for (i =3D 0; i < ug_info->numQueuesRx; i++)
+		uf_info->uccm_mask |=3D (UCCE_RXBF_SINGLE_MASK << i);
+
+	for (i =3D 0; i < ug_info->numQueuesTx; i++)
+		uf_info->uccm_mask |=3D (UCCE_TXBF_SINGLE_MASK << i);
+	/* Initialize the general fast UCC block. */
+	if (ucc_fast_init(uf_info, &uccf)) {
+		ugeth_err("%s: Failed to init uccf.", __FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return -ENOMEM;
+	}
+	ugeth->uccf =3D uccf;
+
+	switch (ug_info->numThreadsRx) {
+	case UCC_GETH_NUM_OF_THREADS_1:
+		numThreadsRxNumerical =3D 1;
+		break;
+	case UCC_GETH_NUM_OF_THREADS_2:
+		numThreadsRxNumerical =3D 2;
+		break;
+	case UCC_GETH_NUM_OF_THREADS_4:
+		numThreadsRxNumerical =3D 4;
+		break;
+	case UCC_GETH_NUM_OF_THREADS_6:
+		numThreadsRxNumerical =3D 6;
+		break;
+	case UCC_GETH_NUM_OF_THREADS_8:
+		numThreadsRxNumerical =3D 8;
+		break;
+	default:
+		ugeth_err("%s: Bad number of Rx threads value.",
__FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return -EINVAL;
+		break;
+	}
+
+	switch (ug_info->numThreadsTx) {
+	case UCC_GETH_NUM_OF_THREADS_1:
+		numThreadsTxNumerical =3D 1;
+		break;
+	case UCC_GETH_NUM_OF_THREADS_2:
+		numThreadsTxNumerical =3D 2;
+		break;
+	case UCC_GETH_NUM_OF_THREADS_4:
+		numThreadsTxNumerical =3D 4;
+		break;
+	case UCC_GETH_NUM_OF_THREADS_6:
+		numThreadsTxNumerical =3D 6;
+		break;
+	case UCC_GETH_NUM_OF_THREADS_8:
+		numThreadsTxNumerical =3D 8;
+		break;
+	default:
+		ugeth_err("%s: Bad number of Tx threads value.",
__FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return -EINVAL;
+		break;
+	}
+
+	/* Calculate rx_extended_features */
+	ugeth->rx_non_dynamic_extended_features =3D
ug_info->ipCheckSumCheck ||
+	    ug_info->ipAddressAlignment ||
+	    (ug_info->numStationAddresses !=3D
+	     UCC_GETH_NUM_OF_STATION_ADDRESSES_1);
+
+	ugeth->rx_extended_features =3D
ugeth->rx_non_dynamic_extended_features ||
+	    (ug_info->vlanOperationTagged !=3D
UCC_GETH_VLAN_OPERATION_TAGGED_NOP)
+	    || (ug_info->vlanOperationNonTagged !=3D
+		UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP);
+
+	uf_regs =3D uccf->uf_regs;
+	ug_regs =3D (ucc_geth_t *) (uccf->uf_regs);
+	ugeth->ug_regs =3D ug_regs;
+
+	init_default_reg_vals(&uf_regs->upsmr,
+			      &ug_regs->maccfg1, &ug_regs->maccfg2);
+
+	/*                    Set UPSMR                      */
+	/* For more details see the hardware spec.           */
+	init_rx_parameters(ug_info->bro,
+			   ug_info->rsh, ug_info->pro, &uf_regs->upsmr);
+
+	/* We're going to ignore other registers for now, */
+	/* except as needed to get up and running         */
+
+	/*                    Set MACCFG1                    */
+	/* For more details see the hardware spec.           */
+	init_flow_control_params(ug_info->aufc,
+				 ug_info->receiveFlowControl,
+				 1,
+				 ug_info->pausePeriod,
+				 ug_info->extensionField,
+				 &uf_regs->upsmr,
+				 &ug_regs->uempr, &ug_regs->maccfg1);
+
+	maccfg1 =3D in_be32(&ug_regs->maccfg1);
+	maccfg1 |=3D MACCFG1_ENABLE_RX;
+	maccfg1 |=3D MACCFG1_ENABLE_TX;
+	out_be32(&ug_regs->maccfg1, maccfg1);
+
+	/*                    Set IPGIFG                     */
+	/* For more details see the hardware spec.           */
+	ret_val =3D
init_inter_frame_gap_params(ug_info->nonBackToBackIfgPart1,
+
ug_info->nonBackToBackIfgPart2,
+					      ug_info->
+
miminumInterFrameGapEnforcement,
+
ug_info->backToBackInterFrameGap,
+					      &ug_regs->ipgifg);
+	if (ret_val !=3D 0) {
+		ugeth_err("%s: IPGIFG initialization parameter too
large.",
+			  __FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return ret_val;
+	}
+
+	/*                    Set HAFDUP                     */
+	/* For more details see the hardware spec.           */
+	ret_val =3D init_half_duplex_params(ug_info->altBeb,
+
ug_info->backPressureNoBackoff,
+					  ug_info->noBackoff,
+					  ug_info->excessDefer,
+					  ug_info->altBebTruncation,
+					  ug_info->maxRetransmission,
+					  ug_info->collisionWindow,
+					  &ug_regs->hafdup);
+	if (ret_val !=3D 0) {
+		ugeth_err("%s: Half Duplex initialization parameter too
large.",
+			  __FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return ret_val;
+	}
+
+	/*                    Set IFSTAT                     */
+	/* For more details see the hardware spec.           */
+	/* Read only - resets upon read                      */
+	ifstat =3D in_be32(&ug_regs->ifstat);
+
+	/*                    Clear UEMPR                    */
+	/* For more details see the hardware spec.           */
+	out_be32(&ug_regs->uempr, 0);
+
+	/*                    Set UESCR                      */
+	/* For more details see the hardware spec.           */
+	init_hw_statistics_gathering_mode((ug_info->statisticsMode &
+
UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE),
+				0, &uf_regs->upsmr, &ug_regs->uescr);
+
+	/* Allocate Tx bds */
+	for (j =3D 0; j < ug_info->numQueuesTx; j++) {
+		/* Allocate in multiple of=20
+		   UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT,
+		   according to spec */
+		length =3D ((ug_info->bdRingLenTx[j] *
UCC_GETH_SIZE_OF_BD)
+			  / UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT)
+		    * UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;
+		if ((ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD) %
+		    UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT)
+			length +=3D
UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;
+		if (uf_info->bd_mem_part =3D=3D MEM_PART_SYSTEM) {
+			u32 align =3D 4;
+			if (UCC_GETH_TX_BD_RING_ALIGNMENT > 4)
+				align =3D UCC_GETH_TX_BD_RING_ALIGNMENT;
+			ugeth->tx_bd_ring_offset[j] =3D
+				(u32) (kmalloc((u32) (length + align),
+				GFP_KERNEL));
+			if (ugeth->tx_bd_ring_offset[j] !=3D 0)
+				ugeth->p_tx_bd_ring[j] =3D
+
(void*)((ugeth->tx_bd_ring_offset[j] +
+					align) & ~(align - 1));
+		} else if (uf_info->bd_mem_part =3D=3D MEM_PART_MURAM) {
+			ugeth->tx_bd_ring_offset[j] =3D
+			    qe_muram_alloc(length,
+
UCC_GETH_TX_BD_RING_ALIGNMENT);
+			if (!IS_MURAM_ERR(ugeth->tx_bd_ring_offset[j]))
+				ugeth->p_tx_bd_ring[j] =3D
+				    (u8 *) qe_muram_addr(ugeth->
+
tx_bd_ring_offset[j]);
+		}
+		if (!ugeth->p_tx_bd_ring[j]) {
+			ugeth_err
+			    ("%s: Can not allocate memory for Tx bd
rings.",
+			     __FUNCTION__);
+			ucc_geth_memclean(ugeth);
+			return -ENOMEM;
+		}
+		/* Zero unused end of bd ring, according to spec */
+		memset(ugeth->p_tx_bd_ring[j] +
+		       ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD, 0,
+		       length - ug_info->bdRingLenTx[j] *
UCC_GETH_SIZE_OF_BD);
+	}
+
+	/* Allocate Rx bds */
+	for (j =3D 0; j < ug_info->numQueuesRx; j++) {
+		length =3D ug_info->bdRingLenRx[j] * UCC_GETH_SIZE_OF_BD;
+		if (uf_info->bd_mem_part =3D=3D MEM_PART_SYSTEM) {
+			u32 align =3D 4;
+			if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4)
+				align =3D UCC_GETH_RX_BD_RING_ALIGNMENT;
+			ugeth->rx_bd_ring_offset[j] =3D
+			    (u32) (kmalloc((u32) (length + align),
GFP_KERNEL));
+			if (ugeth->rx_bd_ring_offset[j] !=3D 0)
+				ugeth->p_rx_bd_ring[j] =3D
+
(void*)((ugeth->rx_bd_ring_offset[j] +
+					align) & ~(align - 1));
+		} else if (uf_info->bd_mem_part =3D=3D MEM_PART_MURAM) {
+			ugeth->rx_bd_ring_offset[j] =3D
+			    qe_muram_alloc(length,
+
UCC_GETH_RX_BD_RING_ALIGNMENT);
+			if (!IS_MURAM_ERR(ugeth->rx_bd_ring_offset[j]))
+				ugeth->p_rx_bd_ring[j] =3D
+				    (u8 *) qe_muram_addr(ugeth->
+
rx_bd_ring_offset[j]);
+		}
+		if (!ugeth->p_rx_bd_ring[j]) {
+			ugeth_err
+			    ("%s: Can not allocate memory for Rx bd
rings.",
+			     __FUNCTION__);
+			ucc_geth_memclean(ugeth);
+			return -ENOMEM;
+		}
+	}
+
+	/* Init Tx bds */
+	for (j =3D 0; j < ug_info->numQueuesTx; j++) {
+		/* Setup the skbuff rings */
+		ugeth->tx_skbuff[j] =3D
+		    (struct sk_buff **)kmalloc(sizeof(struct sk_buff *)
*
+
ugeth->ug_info->bdRingLenTx[j],
+					       GFP_KERNEL);
+
+		if (ugeth->tx_skbuff[j] =3D=3D NULL) {
+			ugeth_err("%s: Could not allocate tx_skbuff",
+				  __FUNCTION__);
+			ucc_geth_memclean(ugeth);
+			return -ENOMEM;
+		}
+
+		for (i =3D 0; i < ugeth->ug_info->bdRingLenTx[j]; i++)
+			ugeth->tx_skbuff[j][i] =3D NULL;
+
+		ugeth->skb_curtx[j] =3D ugeth->skb_dirtytx[j] =3D 0;
+		bd =3D ugeth->confBd[j] =3D ugeth->txBd[j] =3D
ugeth->p_tx_bd_ring[j];
+		for (i =3D 0; i < ug_info->bdRingLenTx[j]; i++) {
+			BD_BUFFER_CLEAR(bd);
+			BD_STATUS_AND_LENGTH_SET(bd, 0);
+			bd +=3D UCC_GETH_SIZE_OF_BD;
+		}
+		bd -=3D UCC_GETH_SIZE_OF_BD;
+		BD_STATUS_AND_LENGTH_SET(bd, T_W);/* for last BD set
Wrap bit */
+	}
+
+	/* Init Rx bds */
+	for (j =3D 0; j < ug_info->numQueuesRx; j++) {
+		/* Setup the skbuff rings */
+		ugeth->rx_skbuff[j] =3D
+		    (struct sk_buff **)kmalloc(sizeof(struct sk_buff *)
*
+
ugeth->ug_info->bdRingLenRx[j],
+					       GFP_KERNEL);
+
+		if (ugeth->rx_skbuff[j] =3D=3D NULL) {
+			ugeth_err("%s: Could not allocate rx_skbuff",
+				  __FUNCTION__);
+			ucc_geth_memclean(ugeth);
+			return -ENOMEM;
+		}
+
+		for (i =3D 0; i < ugeth->ug_info->bdRingLenRx[j]; i++)
+			ugeth->rx_skbuff[j][i] =3D NULL;
+
+		ugeth->skb_currx[j] =3D 0;
+		bd =3D ugeth->rxBd[j] =3D ugeth->p_rx_bd_ring[j];
+		for (i =3D 0; i < ug_info->bdRingLenRx[j]; i++) {
+			BD_STATUS_AND_LENGTH_SET(bd, R_I);
+			BD_BUFFER_CLEAR(bd);
+			bd +=3D UCC_GETH_SIZE_OF_BD;
+		}
+		bd -=3D UCC_GETH_SIZE_OF_BD;
+		BD_STATUS_AND_LENGTH_SET(bd, R_W);/* for last BD set
Wrap bit */
+	}
+
+	/*
+	 * Global PRAM
+	 */
+	/* Tx global PRAM */
+	/* Allocate global tx parameter RAM page */
+	ugeth->tx_glbl_pram_offset =3D
+	    qe_muram_alloc(sizeof(ucc_geth_tx_global_pram_t),
+			   UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT);
+	if (IS_MURAM_ERR(ugeth->tx_glbl_pram_offset)) {
+		ugeth_err
+		    ("%s: Can not allocate DPRAM memory for
p_tx_glbl_pram.",
+		     __FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return -ENOMEM;
+	}
+	ugeth->p_tx_glbl_pram =3D
+	    (ucc_geth_tx_global_pram_t *) qe_muram_addr(ugeth->
+
tx_glbl_pram_offset);
+	/* Zero out p_tx_glbl_pram */
+	memset(ugeth->p_tx_glbl_pram, 0,
sizeof(ucc_geth_tx_global_pram_t));
+
+	/* Fill global PRAM */
+
+	/* TQPTR */
+	/* Size varies with number of Tx threads */
+	ugeth->thread_dat_tx_offset =3D
+	    qe_muram_alloc(numThreadsTxNumerical *
+			   sizeof(ucc_geth_thread_data_tx_t) +
+			   32 * (numThreadsTxNumerical =3D=3D 1),
+			   UCC_GETH_THREAD_DATA_ALIGNMENT);
+	if (IS_MURAM_ERR(ugeth->thread_dat_tx_offset)) {
+		ugeth_err
+		    ("%s: Can not allocate DPRAM memory for
p_thread_data_tx.",
+		     __FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return -ENOMEM;
+	}
+
+	ugeth->p_thread_data_tx =3D
+	    (ucc_geth_thread_data_tx_t *) qe_muram_addr(ugeth->
+
thread_dat_tx_offset);
+	out_be32(&ugeth->p_tx_glbl_pram->tqptr,
ugeth->thread_dat_tx_offset);
+
+	/* vtagtable */
+	for (i =3D 0; i < UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX; i++)
+		out_be32(&ugeth->p_tx_glbl_pram->vtagtable[i],
+			 ug_info->vtagtable[i]);
+
+	/* iphoffset */
+	for (i =3D 0; i < TX_IP_OFFSET_ENTRY_MAX; i++)
+		ugeth->p_tx_glbl_pram->iphoffset[i] =3D
ug_info->iphoffset[i];
+
+	/* SQPTR */
+	/* Size varies with number of Tx queues */
+	ugeth->send_q_mem_reg_offset =3D
+	    qe_muram_alloc(ug_info->numQueuesTx *
+			   sizeof(ucc_geth_send_queue_qd_t),
+
UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT);
+	if (IS_MURAM_ERR(ugeth->send_q_mem_reg_offset)) {
+		ugeth_err
+		    ("%s: Can not allocate DPRAM memory for
p_send_q_mem_reg.",
+		     __FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return -ENOMEM;
+	}
+
+	ugeth->p_send_q_mem_reg =3D
+	    (ucc_geth_send_queue_mem_region_t *) qe_muram_addr(ugeth->
+			send_q_mem_reg_offset);
+	out_be32(&ugeth->p_tx_glbl_pram->sqptr,
ugeth->send_q_mem_reg_offset);
+
+	/* Setup the table */
+	/* Assume BD rings are already established */
+	for (i =3D 0; i < ug_info->numQueuesTx; i++) {
+		endOfRing =3D
+		    ugeth->p_tx_bd_ring[i] + (ug_info->bdRingLenTx[i] -
+					      1) * UCC_GETH_SIZE_OF_BD;
+		if (ugeth->ug_info->uf_info.bd_mem_part =3D=3D
MEM_PART_SYSTEM) {
+
out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base,
+				 (u32)
virt_to_phys(ugeth->p_tx_bd_ring[i]));
+			out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].
+				 last_bd_completed_address,
+				 (u32) virt_to_phys(endOfRing));
+		} else if (ugeth->ug_info->uf_info.bd_mem_part =3D=3D
+			   MEM_PART_MURAM) {
+
out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base,
+				 (u32) immrbar_virt_to_phys(ugeth->
+
p_tx_bd_ring[i]));
+			out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].
+				 last_bd_completed_address,
+				 (u32) immrbar_virt_to_phys(endOfRing));
+		}
+	}
+
+	/* schedulerbasepointer */
+
+	if (ug_info->numQueuesTx > 1) {=09
+	/* scheduler exists only if more than 1 tx queue */
+		ugeth->scheduler_offset =3D
+		    qe_muram_alloc(sizeof(ucc_geth_scheduler_t),
+				   UCC_GETH_SCHEDULER_ALIGNMENT);
+		if (IS_MURAM_ERR(ugeth->scheduler_offset)) {
+			ugeth_err
+			 ("%s: Can not allocate DPRAM memory for
p_scheduler.",
+			     __FUNCTION__);
+			ucc_geth_memclean(ugeth);
+			return -ENOMEM;
+		}
+
+		ugeth->p_scheduler =3D
+		    (ucc_geth_scheduler_t *) qe_muram_addr(ugeth->
+
scheduler_offset);
+		out_be32(&ugeth->p_tx_glbl_pram->schedulerbasepointer,
+			 ugeth->scheduler_offset);
+		/* Zero out p_scheduler */
+		memset(ugeth->p_scheduler, 0,
sizeof(ucc_geth_scheduler_t));
+
+		/* Set values in scheduler */
+		out_be32(&ugeth->p_scheduler->mblinterval,
+			 ug_info->mblinterval);
+		out_be16(&ugeth->p_scheduler->nortsrbytetime,
+			 ug_info->nortsrbytetime);
+		ugeth->p_scheduler->fracsiz =3D ug_info->fracsiz;
+		ugeth->p_scheduler->strictpriorityq =3D
ug_info->strictpriorityq;
+		ugeth->p_scheduler->txasap =3D ug_info->txasap;
+		ugeth->p_scheduler->extrabw =3D ug_info->extrabw;
+		for (i =3D 0; i < NUM_TX_QUEUES; i++)
+			ugeth->p_scheduler->weightfactor[i] =3D
+			    ug_info->weightfactor[i];
+
+		/* Set pointers to cpucount registers in scheduler */
+		ugeth->p_cpucount[0] =3D &(ugeth->p_scheduler->cpucount0);
+		ugeth->p_cpucount[1] =3D &(ugeth->p_scheduler->cpucount1);
+		ugeth->p_cpucount[2] =3D &(ugeth->p_scheduler->cpucount2);
+		ugeth->p_cpucount[3] =3D &(ugeth->p_scheduler->cpucount3);
+		ugeth->p_cpucount[4] =3D &(ugeth->p_scheduler->cpucount4);
+		ugeth->p_cpucount[5] =3D &(ugeth->p_scheduler->cpucount5);
+		ugeth->p_cpucount[6] =3D &(ugeth->p_scheduler->cpucount6);
+		ugeth->p_cpucount[7] =3D &(ugeth->p_scheduler->cpucount7);
+	}
+
+	/* schedulerbasepointer */
+	/* TxRMON_PTR (statistics) */
+	if (ug_info->
+	    statisticsMode &
UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
+		ugeth->tx_fw_statistics_pram_offset =3D
+		    qe_muram_alloc(sizeof
+
(ucc_geth_tx_firmware_statistics_pram_t),
+				   UCC_GETH_TX_STATISTICS_ALIGNMENT);
+		if (IS_MURAM_ERR(ugeth->tx_fw_statistics_pram_offset)) {
+			ugeth_err
+			    ("%s: Can not allocate DPRAM memory for"
+				" p_tx_fw_statistics_pram.",
__FUNCTION__);
+			ucc_geth_memclean(ugeth);
+			return -ENOMEM;
+		}
+		ugeth->p_tx_fw_statistics_pram =3D
+		    (ucc_geth_tx_firmware_statistics_pram_t *)
+		    qe_muram_addr(ugeth->tx_fw_statistics_pram_offset);
+		/* Zero out p_tx_fw_statistics_pram */
+		memset(ugeth->p_tx_fw_statistics_pram,
+		       0,
sizeof(ucc_geth_tx_firmware_statistics_pram_t));
+	}
+
+	/* temoder */
+	/* Already has speed set */
+
+	if (ug_info->numQueuesTx > 1)
+		temoder |=3D TEMODER_SCHEDULER_ENABLE;
+	if (ug_info->ipCheckSumGenerate)
+		temoder |=3D TEMODER_IP_CHECKSUM_GENERATE;
+	temoder |=3D ((ug_info->numQueuesTx - 1) <<
TEMODER_NUM_OF_QUEUES_SHIFT);
+	out_be16(&ugeth->p_tx_glbl_pram->temoder, temoder);
+
+	test =3D in_be16(&ugeth->p_tx_glbl_pram->temoder);
+
+	/* Function code register value to be used later */
+	function_code =3D QE_BMR_BYTE_ORDER_BO_MOT |
UCC_FAST_FUNCTION_CODE_GBL;=09
+	/* Required for QE */
+
+	/* function code register */
+	out_be32(&ugeth->p_tx_glbl_pram->tstate, ((u32) function_code)
<< 24);
+
+	/* Rx global PRAM */
+	/* Allocate global rx parameter RAM page */
+	ugeth->rx_glbl_pram_offset =3D
+	    qe_muram_alloc(sizeof(ucc_geth_rx_global_pram_t),
+			   UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT);
+	if (IS_MURAM_ERR(ugeth->rx_glbl_pram_offset)) {
+		ugeth_err
+		    ("%s: Can not allocate DPRAM memory for
p_rx_glbl_pram.",
+		     __FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return -ENOMEM;
+	}
+	ugeth->p_rx_glbl_pram =3D
+	    (ucc_geth_rx_global_pram_t *) qe_muram_addr(ugeth->
+
rx_glbl_pram_offset);
+	/* Zero out p_rx_glbl_pram */
+	memset(ugeth->p_rx_glbl_pram, 0,
sizeof(ucc_geth_rx_global_pram_t));
+
+	/* Fill global PRAM */
+
+	/* RQPTR */
+	/* Size varies with number of Rx threads */
+	ugeth->thread_dat_rx_offset =3D
+	    qe_muram_alloc(numThreadsRxNumerical *
+			   sizeof(ucc_geth_thread_data_rx_t),
+			   UCC_GETH_THREAD_DATA_ALIGNMENT);
+	if (IS_MURAM_ERR(ugeth->thread_dat_rx_offset)) {
+		ugeth_err
+		    ("%s: Can not allocate DPRAM memory for
p_thread_data_rx.",
+		     __FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return -ENOMEM;
+	}
+
+	ugeth->p_thread_data_rx =3D
+	    (ucc_geth_thread_data_rx_t *) qe_muram_addr(ugeth->
+
thread_dat_rx_offset);
+	out_be32(&ugeth->p_rx_glbl_pram->rqptr,
ugeth->thread_dat_rx_offset);
+
+	/* typeorlen */
+	out_be16(&ugeth->p_rx_glbl_pram->typeorlen, ug_info->typeorlen);
+
+	/* rxrmonbaseptr (statistics) */
+	if (ug_info->
+	    statisticsMode &
UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) {
+		ugeth->rx_fw_statistics_pram_offset =3D
+		    qe_muram_alloc(sizeof
+
(ucc_geth_rx_firmware_statistics_pram_t),
+				   UCC_GETH_RX_STATISTICS_ALIGNMENT);
+		if (IS_MURAM_ERR(ugeth->rx_fw_statistics_pram_offset)) {
+			ugeth_err
+				("%s: Can not allocate DPRAM memory for"
+				" p_rx_fw_statistics_pram.",
__FUNCTION__);
+			ucc_geth_memclean(ugeth);
+			return -ENOMEM;
+		}
+		ugeth->p_rx_fw_statistics_pram =3D
+		    (ucc_geth_rx_firmware_statistics_pram_t *)
+		    qe_muram_addr(ugeth->rx_fw_statistics_pram_offset);
+		/* Zero out p_rx_fw_statistics_pram */
+		memset(ugeth->p_rx_fw_statistics_pram, 0,
+		       sizeof(ucc_geth_rx_firmware_statistics_pram_t));
+	}
+
+	/* intCoalescingPtr */
+
+	/* Size varies with number of Rx queues */
+	ugeth->rx_irq_coalescing_tbl_offset =3D
+	    qe_muram_alloc(ug_info->numQueuesRx *
+
sizeof(ucc_geth_rx_interrupt_coalescing_entry_t),
+			   UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
+	if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) {
+		ugeth_err
+		    ("%s: Can not allocate DPRAM memory for"
+			" p_rx_irq_coalescing_tbl.", __FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return -ENOMEM;
+	}
+
+	ugeth->p_rx_irq_coalescing_tbl =3D
+	    (ucc_geth_rx_interrupt_coalescing_table_t *)
+	    qe_muram_addr(ugeth->rx_irq_coalescing_tbl_offset);
+	out_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr,
+		 ugeth->rx_irq_coalescing_tbl_offset);
+
+	/* Fill interrupt coalescing table */
+	for (i =3D 0; i < ug_info->numQueuesRx; i++) {
+
out_be32(&ugeth->p_rx_irq_coalescing_tbl->coalescingentry[i].
+			 interruptcoalescingmaxvalue,
+			 ug_info->interruptcoalescingmaxvalue[i]);
+
out_be32(&ugeth->p_rx_irq_coalescing_tbl->coalescingentry[i].
+			 interruptcoalescingcounter,
+			 ug_info->interruptcoalescingmaxvalue[i]);
+	}
+
+	/* MRBLR */
+	init_max_rx_buff_len(uf_info->max_rx_buf_length,
+			     &ugeth->p_rx_glbl_pram->mrblr);
+	/* MFLR */
+	out_be16(&ugeth->p_rx_glbl_pram->mflr, ug_info->maxFrameLength);
+	/* MINFLR */
+	init_min_frame_len(ug_info->minFrameLength,
+			   &ugeth->p_rx_glbl_pram->minflr,
+			   &ugeth->p_rx_glbl_pram->mrblr);
+	/* MAXD1 */
+	out_be16(&ugeth->p_rx_glbl_pram->maxd1, ug_info->maxD1Length);
+	/* MAXD2 */
+	out_be16(&ugeth->p_rx_glbl_pram->maxd2, ug_info->maxD2Length);
+
+	/* l2qt */
+	l2qt =3D 0;
+	for (i =3D 0; i < UCC_GETH_VLAN_PRIORITY_MAX; i++)
+		l2qt |=3D (ug_info->l2qt[i] << (28 - 4 * i));
+	out_be32(&ugeth->p_rx_glbl_pram->l2qt, l2qt);
+
+	/* l3qt */
+	for (j =3D 0; j < UCC_GETH_IP_PRIORITY_MAX; j +=3D 8) {
+		l3qt =3D 0;
+		for (i =3D 0; i < 8; i++)
+			l3qt |=3D (ug_info->l3qt[j + i] << (28 - 4 * i));
+		out_be32(&ugeth->p_rx_glbl_pram->l3qt[j], l3qt);
+	}
+
+	/* vlantype */
+	out_be16(&ugeth->p_rx_glbl_pram->vlantype, ug_info->vlantype);
+
+	/* vlantci */
+	out_be16(&ugeth->p_rx_glbl_pram->vlantci, ug_info->vlantci);
+
+	/* ecamptr */
+	out_be32(&ugeth->p_rx_glbl_pram->ecamptr, ug_info->ecamptr);
+
+	/* RBDQPTR */
+	/* Size varies with number of Rx queues */
+	ugeth->rx_bd_qs_tbl_offset =3D
+	    qe_muram_alloc(ug_info->numQueuesRx *
+			   (sizeof(ucc_geth_rx_bd_queues_entry_t) +
+			    sizeof(ucc_geth_rx_prefetched_bds_t)),
+			   UCC_GETH_RX_BD_QUEUES_ALIGNMENT);
+	if (IS_MURAM_ERR(ugeth->rx_bd_qs_tbl_offset)) {
+		ugeth_err
+		    ("%s: Can not allocate DPRAM memory for
p_rx_bd_qs_tbl.",
+		     __FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return -ENOMEM;
+	}
+
+	ugeth->p_rx_bd_qs_tbl =3D
+	    (ucc_geth_rx_bd_queues_entry_t *) qe_muram_addr(ugeth->
+				    rx_bd_qs_tbl_offset);
+	out_be32(&ugeth->p_rx_glbl_pram->rbdqptr,
ugeth->rx_bd_qs_tbl_offset);
+	/* Zero out p_rx_bd_qs_tbl */
+	memset(ugeth->p_rx_bd_qs_tbl,
+	       0,
+	       ug_info->numQueuesRx *
(sizeof(ucc_geth_rx_bd_queues_entry_t) +
+
sizeof(ucc_geth_rx_prefetched_bds_t)));
+
+	/* Setup the table */
+	/* Assume BD rings are already established */
+	for (i =3D 0; i < ug_info->numQueuesRx; i++) {
+		if (ugeth->ug_info->uf_info.bd_mem_part =3D=3D
MEM_PART_SYSTEM) {
+
out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr,
+				 (u32)
virt_to_phys(ugeth->p_rx_bd_ring[i]));
+		} else if (ugeth->ug_info->uf_info.bd_mem_part =3D=3D
+			   MEM_PART_MURAM) {
+
out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr,
+				 (u32) immrbar_virt_to_phys(ugeth->
+
p_rx_bd_ring[i]));
+		}
+		/* rest of fields handled by QE */
+	}
+
+	/* remoder */
+	/* Already has speed set */
+
+	if (ugeth->rx_extended_features)
+		remoder |=3D REMODER_RX_EXTENDED_FEATURES;
+	if (ug_info->rxExtendedFiltering)
+		remoder |=3D REMODER_RX_EXTENDED_FILTERING;
+	if (ug_info->dynamicMaxFrameLength)
+		remoder |=3D REMODER_DYNAMIC_MAX_FRAME_LENGTH;
+	if (ug_info->dynamicMinFrameLength)
+		remoder |=3D REMODER_DYNAMIC_MIN_FRAME_LENGTH;
+	remoder |=3D
+	    ug_info->vlanOperationTagged <<
REMODER_VLAN_OPERATION_TAGGED_SHIFT;
+	remoder |=3D
+	    ug_info->
+	    vlanOperationNonTagged <<
REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT;
+	remoder |=3D ug_info->rxQoSMode << REMODER_RX_QOS_MODE_SHIFT;
+	remoder |=3D ((ug_info->numQueuesRx - 1) <<
REMODER_NUM_OF_QUEUES_SHIFT);
+	if (ug_info->ipCheckSumCheck)
+		remoder |=3D REMODER_IP_CHECKSUM_CHECK;
+	if (ug_info->ipAddressAlignment)
+		remoder |=3D REMODER_IP_ADDRESS_ALIGNMENT;
+	out_be32(&ugeth->p_rx_glbl_pram->remoder, remoder);
+
+	/* Note that this function must be called */
+	/* ONLY AFTER p_tx_fw_statistics_pram */
+	/* andp_UccGethRxFirmwareStatisticsPram are allocated ! */
+	init_firmware_statistics_gathering_mode((ug_info->
+		statisticsMode &=20
+		UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX),
+		(ug_info->statisticsMode &
+		UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX),
+		&ugeth->p_tx_glbl_pram->txrmonbaseptr,
+		ugeth->tx_fw_statistics_pram_offset,
+		&ugeth->p_rx_glbl_pram->rxrmonbaseptr,
+		ugeth->rx_fw_statistics_pram_offset,
+		&ugeth->p_tx_glbl_pram->temoder,
+		&ugeth->p_rx_glbl_pram->remoder);
+
+	/* function code register */
+	ugeth->p_rx_glbl_pram->rstate =3D function_code;
+
+	/* initialize extended filtering */
+	if (ug_info->rxExtendedFiltering) {
+		if (!ug_info->extendedFilteringChainPointer) {
+			ugeth_err("%s: Null Extended Filtering Chain
Pointer.",
+				  __FUNCTION__);
+			ucc_geth_memclean(ugeth);
+			return -EINVAL;
+		}
+
+		/* Allocate memory for extended filtering Mode Global=20
+		Parameters */
+		ugeth->exf_glbl_param_offset =3D
+		    qe_muram_alloc(sizeof(ucc_geth_exf_global_pram_t),
+
UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT);
+		if (IS_MURAM_ERR(ugeth->exf_glbl_param_offset)) {
+			ugeth_err
+				("%s: Can not allocate DPRAM memory for"
+				" p_exf_glbl_param.", __FUNCTION__);
+			ucc_geth_memclean(ugeth);
+			return -ENOMEM;
+		}
+
+		ugeth->p_exf_glbl_param =3D
+		    (ucc_geth_exf_global_pram_t *) qe_muram_addr(ugeth->
+				 exf_glbl_param_offset);
+		out_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam,
+			 ugeth->exf_glbl_param_offset);
+		out_be32(&ugeth->p_exf_glbl_param->l2pcdptr,
+			 (u32) ug_info->extendedFilteringChainPointer);
+
+	} else {		/* initialize 82xx style address
filtering */
+
+		/* Init individual address recognition registers to
disabled */
+
+		for (j =3D 0; j < NUM_OF_PADDRS; j++)
+			ugeth_82xx_filtering_clear_addr_in_paddr(ugeth,
(u8) j);
+
+		/* Create CQs for hash tables */
+		if (ug_info->maxGroupAddrInHash > 0) {
+			INIT_LIST_HEAD(&ugeth->group_hash_q);
+		}
+		if (ug_info->maxIndAddrInHash > 0) {
+			INIT_LIST_HEAD(&ugeth->ind_hash_q);
+		}
+		p_82xx_addr_filt =3D
+		    (ucc_geth_82xx_address_filtering_pram_t *) ugeth->
+		    p_rx_glbl_pram->addressfiltering;
+
+		ugeth_82xx_filtering_clear_all_addr_in_hash(ugeth,
+			ENET_ADDR_TYPE_GROUP);
+		ugeth_82xx_filtering_clear_all_addr_in_hash(ugeth,
+			ENET_ADDR_TYPE_INDIVIDUAL);
+	}
+
+	/*
+	 * Initialize UCC at QE level
+	 */
+
+	command =3D QE_INIT_TX_RX;
+
+	/* Allocate shadow InitEnet command parameter structure.
+	 * This is needed because after the InitEnet command is
executed,
+	 * the structure in DPRAM is released, because DPRAM is a
premium=20
+	 * resource.=20
+	 * This shadow structure keeps a copy of what was done so that
the
+	 * allocated resources can be released when the channel is
freed.
+	 */
+	if (!(ugeth->p_init_enet_param_shadow =3D
+	     (ucc_geth_init_pram_t *)
kmalloc(sizeof(ucc_geth_init_pram_t),
+					      GFP_KERNEL))) {
+		ugeth_err
+		    ("%s: Can not allocate memory for"
+			" p_UccInitEnetParamShadows.", __FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return -ENOMEM;
+	}
+	/* Zero out *p_init_enet_param_shadow */
+	memset((char *)ugeth->p_init_enet_param_shadow,
+	       0, sizeof(ucc_geth_init_pram_t));
+
+	/* Fill shadow InitEnet command parameter structure */
+
+	ugeth->p_init_enet_param_shadow->resinit1 =3D
+	    ENET_INIT_PARAM_MAGIC_RES_INIT1;
+	ugeth->p_init_enet_param_shadow->resinit2 =3D
+	    ENET_INIT_PARAM_MAGIC_RES_INIT2;
+	ugeth->p_init_enet_param_shadow->resinit3 =3D
+	    ENET_INIT_PARAM_MAGIC_RES_INIT3;
+	ugeth->p_init_enet_param_shadow->resinit4 =3D
+	    ENET_INIT_PARAM_MAGIC_RES_INIT4;
+	ugeth->p_init_enet_param_shadow->resinit5 =3D
+	    ENET_INIT_PARAM_MAGIC_RES_INIT5;
+	ugeth->p_init_enet_param_shadow->rgftgfrxglobal |=3D
+	    ((u32) ug_info->numThreadsRx) << ENET_INIT_PARAM_RGF_SHIFT;
+	ugeth->p_init_enet_param_shadow->rgftgfrxglobal |=3D
+	    ((u32) ug_info->numThreadsTx) << ENET_INIT_PARAM_TGF_SHIFT;
+
+	ugeth->p_init_enet_param_shadow->rgftgfrxglobal |=3D
+	    ugeth->rx_glbl_pram_offset | ug_info->riscRx;
+	if ((ug_info->largestexternallookupkeysize !=3D
+	     QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE)
+	    && (ug_info->largestexternallookupkeysize !=3D
+		QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES)
+	    && (ug_info->largestexternallookupkeysize !=3D
+
QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) {
+		ugeth_err("%s: Invalid largest External Lookup Key
Size.",
+			  __FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return -EINVAL;
+	}
+	ugeth->p_init_enet_param_shadow->largestexternallookupkeysize =3D
+	    ug_info->largestexternallookupkeysize;
+	size =3D sizeof(ucc_geth_thread_rx_pram_t);
+	if (ug_info->rxExtendedFiltering) {
+		size +=3D
THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING;
+		if (ug_info->largestexternallookupkeysize =3D=3D
+		    QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES)
+			size +=3D
+
THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8;
+		if (ug_info->largestexternallookupkeysize =3D=3D
+		    QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES)
+			size +=3D
+
THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16;
+	}
+
+	if ((ret_val =3D fill_init_enet_entries(ugeth, &(ugeth->
+		p_init_enet_param_shadow->rxthread[0]),
+		(u8) (numThreadsRxNumerical + 1)
+		/* Rx needs one extra for terminator */
+		, size, UCC_GETH_THREAD_RX_PRAM_ALIGNMENT,
+		ug_info->riscRx, 1)) !=3D 0) {
+			ugeth_err("%s: Can not fill
p_init_enet_param_shadow.",
+				__FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return ret_val;
+	}
+
+	ugeth->p_init_enet_param_shadow->txglobal =3D
+	    ugeth->tx_glbl_pram_offset | ug_info->riscTx;
+	if ((ret_val =3D
+	     fill_init_enet_entries(ugeth,
+				    &(ugeth->p_init_enet_param_shadow->
+				      txthread[0]),
numThreadsTxNumerical,
+				    sizeof(ucc_geth_thread_tx_pram_t),
+				    UCC_GETH_THREAD_TX_PRAM_ALIGNMENT,
+				    ug_info->riscTx, 0)) !=3D 0) {
+		ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
+			  __FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return ret_val;
+	}
+
+	/* Load Rx bds with buffers */
+	for (i =3D 0; i < ug_info->numQueuesRx; i++) {
+		if ((ret_val =3D rx_bd_buffer_set(ugeth, (u8) i)) !=3D 0) {
+			ugeth_err("%s: Can not fill Rx bds with
buffers.",
+				  __FUNCTION__);
+			ucc_geth_memclean(ugeth);
+			return ret_val;
+		}
+	}
+
+	/* Allocate InitEnet command parameter structure */
+	init_enet_pram_offset =3D
qe_muram_alloc(sizeof(ucc_geth_init_pram_t), 4);
+	if (IS_MURAM_ERR(init_enet_pram_offset)) {
+		ugeth_err
+		    ("%s: Can not allocate DPRAM memory for
p_init_enet_pram.",
+		     __FUNCTION__);
+		ucc_geth_memclean(ugeth);
+		return -ENOMEM;
+	}
+	p_init_enet_pram =3D
+	    (ucc_geth_init_pram_t *)
qe_muram_addr(init_enet_pram_offset);
+
+	/* Copy shadow InitEnet command parameter structure into PRAM */
+	p_init_enet_pram->resinit1 =3D
ugeth->p_init_enet_param_shadow->resinit1;
+	p_init_enet_pram->resinit2 =3D
ugeth->p_init_enet_param_shadow->resinit2;
+	p_init_enet_pram->resinit3 =3D
ugeth->p_init_enet_param_shadow->resinit3;
+	p_init_enet_pram->resinit4 =3D
ugeth->p_init_enet_param_shadow->resinit4;
+	out_be16(&p_init_enet_pram->resinit5,
+		 ugeth->p_init_enet_param_shadow->resinit5);
+	p_init_enet_pram->largestexternallookupkeysize =3D
+
ugeth->p_init_enet_param_shadow->largestexternallookupkeysize;
+	out_be32(&p_init_enet_pram->rgftgfrxglobal,
+		 ugeth->p_init_enet_param_shadow->rgftgfrxglobal);
+	for (i =3D 0; i < ENET_INIT_PARAM_MAX_ENTRIES_RX; i++)
+		out_be32(&p_init_enet_pram->rxthread[i],
+			 ugeth->p_init_enet_param_shadow->rxthread[i]);
+	out_be32(&p_init_enet_pram->txglobal,
+		 ugeth->p_init_enet_param_shadow->txglobal);
+	for (i =3D 0; i < ENET_INIT_PARAM_MAX_ENTRIES_TX; i++)
+		out_be32(&p_init_enet_pram->txthread[i],
+			 ugeth->p_init_enet_param_shadow->txthread[i]);
+
+	/* Issue QE command */
+	cecr_subblock =3D
+
ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
+	qe_issue_cmd(command, cecr_subblock, (u8)
QE_CR_PROTOCOL_ETHERNET,
+		     init_enet_pram_offset);
+
+	/* Free InitEnet command parameter */
+	qe_muram_free(init_enet_pram_offset);
+
+	return 0;
+}
+
+/* returns a net_device_stats structure pointer */
+static struct net_device_stats *ucc_geth_get_stats(struct net_device
*dev)
+{
+	ucc_geth_private_t *ugeth =3D netdev_priv(dev);
+
+	return &(ugeth->stats);
+}
+
+/* ucc_geth_timeout gets called when a packet has not been
+ * transmitted after a set amount of time.
+ * For now, assume that clearing out all the structures, and
+ * starting over will fix the problem. */
+static void ucc_geth_timeout(struct net_device *dev)
+{
+	ucc_geth_private_t *ugeth =3D netdev_priv(dev);
+
+	ugeth_vdbg("%s: IN", __FUNCTION__);
+
+	ugeth->stats.tx_errors++;
+
+	ugeth_dump_regs(ugeth);
+
+	if (dev->flags & IFF_UP) {
+		ucc_geth_stop(ugeth);
+		ucc_geth_startup(ugeth);
+	}
+
+	netif_schedule(dev);
+}
+
+/* This is called by the kernel when a frame is ready for transmission.
*/
+/* It is pointed to by the dev->hard_start_xmit function pointer */
+static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device
*dev)
+{
+	ucc_geth_private_t *ugeth =3D netdev_priv(dev);
+	u8 *bd;			/* BD pointer */
+	u32 bd_status;
+	u8 txQ =3D 0;
+
+	ugeth_vdbg("%s: IN", __FUNCTION__);
+
+	spin_lock_irq(&ugeth->lock);
+
+	ugeth->stats.tx_bytes +=3D skb->len;
+
+	/* Start from the next BD that should be filled */
+	bd =3D ugeth->txBd[txQ];
+	bd_status =3D BD_STATUS_AND_LENGTH(bd);
+	/* Save the skb pointer so we can free it later */
+	ugeth->tx_skbuff[txQ][ugeth->skb_curtx[txQ]] =3D skb;
+
+	/* Update the current skb pointer (wrapping if this was the
last) */
+	ugeth->skb_curtx[txQ] =3D
+	    (ugeth->skb_curtx[txQ] +
+	     1) & TX_RING_MOD_MASK(ugeth->ug_info->bdRingLenTx[txQ]);
+
+	/* set up the buffer descriptor */
+	BD_BUFFER_SET(bd,
+		      dma_map_single(NULL, skb->data, skb->len,
DMA_TO_DEVICE));
+
+	//printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data);
+
+	bd_status =3D (bd_status & T_W) | T_R | T_I | T_L | skb->len;
+
+	BD_STATUS_AND_LENGTH_SET(bd, bd_status);
+
+	dev->trans_start =3D jiffies;
+
+	/* Move to next BD in the ring */
+	if (!(bd_status & T_W))
+		ugeth->txBd[txQ] =3D bd + UCC_GETH_SIZE_OF_BD;
+	else
+		ugeth->txBd[txQ] =3D ugeth->p_tx_bd_ring[txQ];
+
+	/* If the next BD still needs to be cleaned up, then the bds
+	   are full.  We need to tell the kernel to stop sending us
stuff. */
+	if (bd =3D=3D ugeth->confBd[txQ]) {
+		if (!netif_queue_stopped(dev))
+			netif_stop_queue(dev);
+	}
+
+	if (ugeth->p_scheduler) {
+		ugeth->cpucount[txQ]++;
+		/* Indicate to QE that there are more Tx bds ready for=20
+		transmission */
+		/* This is done by writing a running counter of the bd=20
+		count to the scheduler PRAM. */
+		out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]);
+	}
+
+	spin_unlock_irq(&ugeth->lock);
+
+	return 0;
+}
+
+static int ucc_geth_rx(ucc_geth_private_t *ugeth, u8 rxQ, int
rx_work_limit)
+{
+	struct sk_buff *skb;
+	u8 *bd;
+	u16 length, howmany =3D 0;
+	u32 bd_status;
+	u8 *bdBuffer;
+
+	ugeth_vdbg("%s: IN", __FUNCTION__);
+
+	spin_lock(&ugeth->lock);
+	/* collect received buffers */
+	bd =3D ugeth->rxBd[rxQ];
+
+	bd_status =3D BD_STATUS_AND_LENGTH(bd);
+
+	/* while there are received buffers and BD is full (~R_E) */
+	while (!((bd_status & (R_E)) || (--rx_work_limit < 0))) {
+		bdBuffer =3D (u8 *) BD_BUFFER(bd);
+		length =3D (u16) ((bd_status & BD_LENGTH_MASK) - 4);
+		skb =3D ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]];
+
+		/* determine whether buffer is first, last, first and
last=20
+		(single buffer frame) or middle (not first and not last)
*/
+		if (!skb ||
+		    (!(bd_status & (R_F | R_L))) ||
+		    (bd_status & R_ERRORS_FATAL)) {
+			ugeth_vdbg("%s, %d: ERROR!!! skb - 0x%08x",
+				   __FUNCTION__, __LINE__, (u32) skb);
+			if (skb)
+				dev_kfree_skb_any(skb);
+
+			ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] =3D
NULL;
+			ugeth->stats.rx_dropped++;
+		} else {
+			ugeth->stats.rx_packets++;
+			howmany++;
+
+			/* Prep the skb for the packet */
+			skb_put(skb, length);
+
+			/* Tell the skb what kind of packet this is */
+			skb->protocol =3D eth_type_trans(skb, ugeth->dev);
+
+			ugeth->stats.rx_bytes +=3D length;
+			/* Send the packet up the stack */
+#ifdef CONFIG_UGETH_NAPI
+			netif_receive_skb(skb);
+#else
+			netif_rx(skb);
+#endif				/* CONFIG_UGETH_NAPI */
+		}
+
+		ugeth->dev->last_rx =3D jiffies;
+
+		skb =3D get_new_skb(ugeth, bd);
+		if (!skb) {
+			ugeth_warn("%s: No Rx Data Buffer",
__FUNCTION__);
+			spin_unlock(&ugeth->lock);
+			ugeth->stats.rx_dropped++;
+			break;
+		}
+
+		ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] =3D skb;
+
+		/* update to point at the next skb */
+		ugeth->skb_currx[rxQ] =3D
+		    (ugeth->skb_currx[rxQ] +
+		     1) &
RX_RING_MOD_MASK(ugeth->ug_info->bdRingLenRx[rxQ]);
+
+		if (bd_status & R_W)
+			bd =3D ugeth->p_rx_bd_ring[rxQ];
+		else
+			bd +=3D UCC_GETH_SIZE_OF_BD;
+
+		bd_status =3D BD_STATUS_AND_LENGTH(bd);
+	}
+
+	ugeth->rxBd[rxQ] =3D bd;
+	spin_unlock(&ugeth->lock);
+	return howmany;
+}
+
+static int ucc_geth_tx(struct net_device *dev, u8 txQ)
+{
+	/* Start from the next BD that should be filled */
+	ucc_geth_private_t *ugeth =3D netdev_priv(dev);
+	u8 *bd;			/* BD pointer */
+	u32 bd_status;
+
+	bd =3D ugeth->confBd[txQ];
+	bd_status =3D BD_STATUS_AND_LENGTH(bd);
+
+	/* Normal processing. */
+	while ((bd_status & T_R) =3D=3D 0) {
+		/* BD contains already transmitted buffer.   */
+		/* Handle the transmitted buffer and release */
+		/* the BD to be used with the current frame  */
+
+		if ((bd =3D ugeth->txBd[txQ]) && (netif_queue_stopped(dev)
=3D=3D 0))
+			break;
+
+		ugeth->stats.tx_packets++;
+
+		/* Free the sk buffer associated with this TxBD */
+		dev_kfree_skb_irq(ugeth->
+
tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]);
+		ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] =3D NULL;
+		ugeth->skb_dirtytx[txQ] =3D
+		    (ugeth->skb_dirtytx[txQ] +
+		     1) &
TX_RING_MOD_MASK(ugeth->ug_info->bdRingLenTx[txQ]);
+
+		/* We freed a buffer, so now we can restart transmission
*/
+		if (netif_queue_stopped(dev))
+			netif_wake_queue(dev);
+
+		/* Advance the confirmation BD pointer */
+		if (!(bd_status & T_W))
+			ugeth->confBd[txQ] +=3D UCC_GETH_SIZE_OF_BD;
+		else
+			ugeth->confBd[txQ] =3D ugeth->p_tx_bd_ring[txQ];
+	}
+	return 0;
+}
+
+#ifdef CONFIG_UGETH_NAPI
+static int ucc_geth_poll(struct net_device *dev, int *budget)
+{
+	ucc_geth_private_t *ugeth =3D netdev_priv(dev);
+	int howmany;
+	int rx_work_limit =3D *budget;
+	u8 rxQ =3D 0;
+
+	if (rx_work_limit > dev->quota)
+		rx_work_limit =3D dev->quota;
+
+	howmany =3D ucc_geth_rx(ugeth, rxQ, rx_work_limit);
+
+	dev->quota -=3D howmany;
+	rx_work_limit -=3D howmany;
+	*budget -=3D howmany;
+
+	if (rx_work_limit >=3D 0)
+		netif_rx_complete(dev);
+
+	return (rx_work_limit < 0) ? 1 : 0;
+}
+#endif				/* CONFIG_UGETH_NAPI */
+
+static irqreturn_t ucc_geth_irq_handler(int irq, void *info,
+					struct pt_regs *regs)
+{
+	struct net_device *dev =3D (struct net_device *)info;
+	ucc_geth_private_t *ugeth =3D netdev_priv(dev);
+	ucc_fast_private_t *uccf;
+	ucc_geth_info_t *ug_info;
+	register u32 ucce =3D 0;
+	register u32 bit_mask =3D UCCE_RXBF_SINGLE_MASK;
+	register u32 tx_mask =3D UCCE_TXBF_SINGLE_MASK;
+	register u8 i;
+
+	ugeth_vdbg("%s: IN", __FUNCTION__);
+
+	if (!ugeth)
+		return IRQ_NONE;
+
+	uccf =3D ugeth->uccf;
+	ug_info =3D ugeth->ug_info;
+
+	do {
+		ucce |=3D (u32) (in_be32(uccf->p_ucce) &
in_be32(uccf->p_uccm));
+
+		/* clear event bits for next time */
+		/* Side effect here is to mask ucce variable=20
+		for future processing below. */
+		out_be32(uccf->p_ucce, ucce);	/* Clear with ones,=20
+						but only bits in UCCM */
+
+		/* We ignore Tx interrupts because Tx confirmation is=20
+		done inside Tx routine */
+
+		for (i =3D 0; i < ug_info->numQueuesRx; i++) {
+			if (ucce & bit_mask)
+				ucc_geth_rx(ugeth, i,
+					    (int)ugeth->ug_info->
+					    bdRingLenRx[i]);
+			ucce &=3D ~bit_mask;
+			bit_mask <<=3D 1;
+		}
+
+		for (i =3D 0; i < ug_info->numQueuesTx; i++) {
+			if (ucce & tx_mask)
+				ucc_geth_tx(dev, i);
+			ucce &=3D ~tx_mask;
+			tx_mask <<=3D 1;
+		}
+
+		/* Exceptions */
+		if (ucce & UCCE_BSY) {
+			ugeth_vdbg("Got BUSY irq!!!!");
+			ugeth->stats.rx_errors++;
+			ucce &=3D ~UCCE_BSY;
+		}
+		if (ucce & UCCE_OTHER) {
+			ugeth_vdbg("Got frame with error (ucce -
0x%08x)!!!!",
+				   ucce);
+			ugeth->stats.rx_errors++;
+			ucce &=3D ~ucce;
+		}
+	}
+	while (ucce);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs
*regs)
+{
+	struct net_device *dev =3D (struct net_device *)dev_id;
+	ucc_geth_private_t *ugeth =3D netdev_priv(dev);
+
+	ugeth_vdbg("%s: IN", __FUNCTION__);
+
+	/* Clear the interrupt */
+	mii_clear_phy_interrupt(ugeth->mii_info);
+
+	/* Disable PHY interrupts */
+	mii_configure_phy_interrupt(ugeth->mii_info,
MII_INTERRUPT_DISABLED);
+
+	/* Schedule the phy change */
+	schedule_work(&ugeth->tq);
+
+	return IRQ_HANDLED;
+}
+
+/* Scheduled by the phy_interrupt/timer to handle PHY changes */
+static void ugeth_phy_change(void *data)
+{
+	struct net_device *dev =3D (struct net_device *)data;
+	ucc_geth_private_t *ugeth =3D netdev_priv(dev);
+	ucc_geth_t *ug_regs;
+	int result =3D 0;
+
+	ugeth_vdbg("%s: IN", __FUNCTION__);
+
+	ug_regs =3D ugeth->ug_regs;
+
+	/* Delay to give the PHY a chance to change the
+	 * register state */
+	msleep(1);
+
+	/* Update the link, speed, duplex */
+	result =3D ugeth->mii_info->phyinfo->read_status(ugeth->mii_info);
+
+	/* Adjust the known status as long as the link
+	 * isn't still coming up */
+	if ((0 =3D=3D result) || (ugeth->mii_info->link =3D=3D 0))
+		adjust_link(dev);
+
+	/* Reenable interrupts, if needed */
+	if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR)
+		mii_configure_phy_interrupt(ugeth->mii_info,
+					    MII_INTERRUPT_ENABLED);
+}
+
+/* Called every so often on systems that don't interrupt
+ * the core for PHY changes */
+static void ugeth_phy_timer(unsigned long data)
+{
+	struct net_device *dev =3D (struct net_device *)data;
+	ucc_geth_private_t *ugeth =3D netdev_priv(dev);
+
+	schedule_work(&ugeth->tq);
+
+	mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME *
HZ);
+}
+
+/* Keep trying aneg for some time
+ * If, after GFAR_AN_TIMEOUT seconds, it has not
+ * finished, we switch to forced.
+ * Either way, once the process has completed, we either
+ * request the interrupt, or switch the timer over to=20
+ * using ugeth_phy_timer to check status */
+static void ugeth_phy_startup_timer(unsigned long data)
+{
+	struct ugeth_mii_info *mii_info =3D (struct ugeth_mii_info *)data;
+	ucc_geth_private_t *ugeth =3D netdev_priv(mii_info->dev);
+	static int secondary =3D UGETH_AN_TIMEOUT;
+	int result;
+
+	/* Configure the Auto-negotiation */
+	result =3D mii_info->phyinfo->config_aneg(mii_info);
+
+	/* If autonegotiation failed to start, and
+	 * we haven't timed out, reset the timer, and return */
+	if (result && secondary--) {
+		mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
+		return;
+	} else if (result) {
+		/* Couldn't start autonegotiation.
+		 * Try switching to forced */
+		mii_info->autoneg =3D 0;
+		result =3D mii_info->phyinfo->config_aneg(mii_info);
+
+		/* Forcing failed!  Give up */
+		if (result) {
+			ugeth_err("%s: Forcing failed!",
mii_info->dev->name);
+			return;
+		}
+	}
+
+	/* Kill the timer so it can be restarted */
+	del_timer_sync(&ugeth->phy_info_timer);
+
+	/* Grab the PHY interrupt, if necessary/possible */
+	if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
+		if (request_irq(ugeth->ug_info->phy_interrupt,
+				phy_interrupt,
+				SA_SHIRQ, "phy_interrupt",
mii_info->dev) < 0) {
+			ugeth_err("%s: Can't get IRQ %d (PHY)",
+				  mii_info->dev->name,
+				  ugeth->ug_info->phy_interrupt);
+		} else {
+			mii_configure_phy_interrupt(ugeth->mii_info,
+
MII_INTERRUPT_ENABLED);
+			return;
+		}
+	}
+
+	/* Start the timer again, this time in order to
+	 * handle a change in status */
+	init_timer(&ugeth->phy_info_timer);
+	ugeth->phy_info_timer.function =3D &ugeth_phy_timer;
+	ugeth->phy_info_timer.data =3D (unsigned long)mii_info->dev;
+	mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME *
HZ);
+}
+
+/* Called when something needs to use the ethernet device */
+/* Returns 0 for success. */
+static int ucc_geth_open(struct net_device *dev)
+{
+	ucc_geth_private_t *ugeth =3D netdev_priv(dev);
+	int err;
+
+	ugeth_vdbg("%s: IN", __FUNCTION__);
+
+	/* Test station address */
+	if (dev->dev_addr[0] & ENET_GROUP_ADDR) {
+		ugeth_err("%s: Multicast address used for station
address"
+			  " - is this what you wanted?", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	err =3D ucc_geth_startup(ugeth);
+	if (err) {
+		ugeth_err("%s: Cannot configure net device, aborting.",
+			  dev->name);
+		return err;
+	}
+
+	err =3D adjust_enet_interface(ugeth);
+	if (err) {
+		ugeth_err("%s: Cannot configure net device, aborting.",
+			  dev->name);
+		return err;
+	}
+
+	/*       Set MACSTNADDR1, MACSTNADDR2                */
+	/* For more details see the hardware spec.           */
+	init_mac_station_addr_regs(dev->dev_addr[0],
+				   dev->dev_addr[1],
+				   dev->dev_addr[2],
+				   dev->dev_addr[3],
+				   dev->dev_addr[4],
+				   dev->dev_addr[5],
+				   &ugeth->ug_regs->macstnaddr1,
+				   &ugeth->ug_regs->macstnaddr2);
+
+	err =3D init_phy(dev);
+	if (err) {
+		ugeth_err("%s: Cannot initialzie PHY, aborting.",
dev->name);
+		return err;
+	}
+#ifndef CONFIG_UGETH_NAPI
+	err =3D
+	    request_irq(ugeth->ug_info->uf_info.irq,
ucc_geth_irq_handler, 0,
+			"UCC Geth", dev);
+	if (err) {
+		ugeth_err("%s: Cannot get IRQ for net device,
aborting.",
+			  dev->name);
+		ucc_geth_stop(ugeth);
+		return err;
+	}
+#endif				/* CONFIG_UGETH_NAPI */
+
+	/* Set up the PHY change work queue */
+	INIT_WORK(&ugeth->tq, ugeth_phy_change, dev);
+
+	init_timer(&ugeth->phy_info_timer);
+	ugeth->phy_info_timer.function =3D &ugeth_phy_startup_timer;
+	ugeth->phy_info_timer.data =3D (unsigned long)ugeth->mii_info;
+	mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
+
+	err =3D ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
+	if (err) {
+		ugeth_err("%s: Cannot enable net device, aborting.",
dev->name);
+		ucc_geth_stop(ugeth);
+		return err;
+	}
+
+	netif_start_queue(dev);
+
+	return err;
+}
+
+/* Stops the kernel queue, and halts the controller */
+static int ucc_geth_close(struct net_device *dev)
+{
+	ucc_geth_private_t *ugeth =3D netdev_priv(dev);
+
+	ugeth_vdbg("%s: IN", __FUNCTION__);
+
+	ucc_geth_stop(ugeth);
+
+	/* Shutdown the PHY */
+	if (ugeth->mii_info->phyinfo->close)
+		ugeth->mii_info->phyinfo->close(ugeth->mii_info);
+
+	kfree(ugeth->mii_info);
+
+	netif_stop_queue(dev);
+
+	return 0;
+}
+
+struct ethtool_ops ucc_geth_ethtool_ops =3D {
+	.get_settings =3D NULL,
+	.get_drvinfo =3D NULL,
+	.get_regs_len =3D NULL,
+	.get_regs =3D NULL,
+	.get_link =3D NULL,
+	.get_coalesce =3D NULL,
+	.set_coalesce =3D NULL,
+	.get_ringparam =3D NULL,
+	.set_ringparam =3D NULL,
+	.get_strings =3D NULL,
+	.get_stats_count =3D NULL,
+	.get_ethtool_stats =3D NULL,
+};
+
+static int ucc_geth_probe(struct device *device)
+{
+	struct platform_device *pdev =3D to_platform_device(device);
+	struct ucc_geth_platform_data *ugeth_pdata;
+	struct net_device *dev =3D NULL;
+	struct ucc_geth_private *ugeth =3D NULL;
+	struct ucc_geth_info *ug_info;
+	int err;
+	static int mii_mng_configured =3D 0;
+
+	ugeth_vdbg("%s: IN", __FUNCTION__);
+
+	ugeth_pdata =3D (struct ucc_geth_platform_data
*)pdev->dev.platform_data;
+
+	ug_info =3D &ugeth_info[pdev->id];
+	ug_info->uf_info.ucc_num =3D pdev->id;
+	ug_info->uf_info.rx_clock =3D ugeth_pdata->rx_clock;
+	ug_info->uf_info.tx_clock =3D ugeth_pdata->tx_clock;
+	ug_info->uf_info.regs =3D ugeth_pdata->phy_reg_addr;
+	ug_info->uf_info.irq =3D platform_get_irq(pdev, 0);
+	ug_info->phy_address =3D ugeth_pdata->phy_id;
+	ug_info->enet_interface =3D ugeth_pdata->phy_interface;
+	ug_info->board_flags =3D ugeth_pdata->board_flags;
+	ug_info->phy_interrupt =3D ugeth_pdata->phy_interrupt;
+=09
+	printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq =3D %d) \n",=20
+		ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs,
+		ug_info->uf_info.irq);
+
+	if (ug_info =3D=3D NULL) {
+		ugeth_err("%s: [%d] Missing additional data!",
__FUNCTION__,
+			  pdev->id);
+		return -ENODEV;
+	}
+
+	if (!mii_mng_configured) {
+		ucc_set_qe_mux_mii_mng(ug_info->uf_info.ucc_num);
+		mii_mng_configured =3D 1;
+	}
+
+	/* Create an ethernet device instance */
+	dev =3D alloc_etherdev(sizeof(*ugeth));
+
+	if (dev =3D=3D NULL)
+		return -ENOMEM;
+
+	ugeth =3D netdev_priv(dev);
+	spin_lock_init(&ugeth->lock);
+
+	dev_set_drvdata(device, dev);
+
+	/* Set the dev->base_addr to the gfar reg region */
+	dev->base_addr =3D (unsigned long)(ug_info->uf_info.regs);
+
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, device);
+
+	/* Fill in the dev structure */
+	dev->open =3D ucc_geth_open;
+	dev->hard_start_xmit =3D ucc_geth_start_xmit;
+	dev->tx_timeout =3D ucc_geth_timeout;
+	dev->watchdog_timeo =3D TX_TIMEOUT;
+#ifdef CONFIG_UGETH_NAPI
+	dev->poll =3D ucc_geth_poll;
+	dev->weight =3D UCC_GETH_DEV_WEIGHT;
+#endif				/* CONFIG_UGETH_NAPI */
+	dev->stop =3D ucc_geth_close;
+	dev->get_stats =3D ucc_geth_get_stats;
+//    dev->change_mtu =3D ucc_geth_change_mtu;
+	dev->mtu =3D 1500;
+	dev->set_multicast_list =3D ucc_geth_set_multi;
+	dev->ethtool_ops =3D &ucc_geth_ethtool_ops;
+
+	err =3D register_netdev(dev);
+	if (err) {
+		ugeth_err("%s: Cannot register net device, aborting.",
+			  dev->name);
+		free_netdev(dev);
+		return err;
+	}
+
+	ugeth->ug_info =3D ug_info;
+	ugeth->dev =3D dev;
+	memcpy(dev->dev_addr, ugeth_pdata->mac_addr, 6);
+
+	return 0;
+}

^ permalink raw reply

* [PATCH 1/3] Freescale QE UCC gigabit ethernet driver
From: Li Yang-r58472 @ 2006-07-06 12:02 UTC (permalink / raw)
  To: Andrew Morton, jgarzik; +Cc: netdev, linuxppc-dev

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=20
 drivers/net/Makefile       |    3=20
 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
=20
+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
+=09
+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 :=3D gianfar.o \
 		gianfar_mii.o \
 		gianfar_sysfs.o
=20
+obj-$(CONFIG_UCC_GETH) +=3D ucc_geth_driver.o
+ucc_geth_driver-objs :=3D 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 =3D {
+	.uf_info =3D {
+		    .bd_mem_part =3D MEM_PART_SYSTEM,
+		    .rtsm =3D UCC_FAST_SEND_IDLES_BETWEEN_FRAMES,
+		    .max_rx_buf_length =3D 1536,
+/* FIXME: should be changed in run time for 1G and 100M */
+#ifdef CONFIG_UGETH_HAS_GIGA
+		    .urfs =3D UCC_GETH_URFS_GIGA_INIT,
+		    .urfet =3D UCC_GETH_URFET_GIGA_INIT,
+		    .urfset =3D UCC_GETH_URFSET_GIGA_INIT,
+		    .utfs =3D UCC_GETH_UTFS_GIGA_INIT,
+		    .utfet =3D UCC_GETH_UTFET_GIGA_INIT,
+		    .utftt =3D UCC_GETH_UTFTT_GIGA_INIT,
+#else
+		    .urfs =3D UCC_GETH_URFS_INIT,
+		    .urfet =3D UCC_GETH_URFET_INIT,
+		    .urfset =3D UCC_GETH_URFSET_INIT,
+		    .utfs =3D UCC_GETH_UTFS_INIT,
+		    .utfet =3D UCC_GETH_UTFET_INIT,
+		    .utftt =3D UCC_GETH_UTFTT_INIT,
+#endif
+		    .ufpt =3D 256,
+		    .mode =3D UCC_FAST_PROTOCOL_MODE_ETHERNET,
+		    .ttx_trx =3D UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL,
+		    .tenc =3D UCC_FAST_TX_ENCODING_NRZ,
+		    .renc =3D UCC_FAST_RX_ENCODING_NRZ,
+		    .tcrc =3D UCC_FAST_16_BIT_CRC,
+		    .synl =3D UCC_FAST_SYNC_LEN_NOT_USED,
+		    },
+	.numQueuesTx =3D 1,
+	.numQueuesRx =3D 1,
+	.extendedFilteringChainPointer =3D ((uint32_t) NULL),
+	.typeorlen =3D 3072 /*1536 */ ,
+	.nonBackToBackIfgPart1 =3D 0x40,
+	.nonBackToBackIfgPart2 =3D 0x60,
+	.miminumInterFrameGapEnforcement =3D 0x50,
+	.backToBackInterFrameGap =3D 0x60,
+	.mblinterval =3D 128,
+	.nortsrbytetime =3D 5,
+	.fracsiz =3D 1,
+	.strictpriorityq =3D 0xff,
+	.altBebTruncation =3D 0xa,
+	.excessDefer =3D 1,
+	.maxRetransmission =3D 0xf,
+	.collisionWindow =3D 0x37,
+	.receiveFlowControl =3D 1,
+	.maxGroupAddrInHash =3D 4,
+	.maxIndAddrInHash =3D 4,
+	.prel =3D 7,
+	.maxFrameLength =3D 1518,
+	.minFrameLength =3D 64,
+	.maxD1Length =3D 1520,
+	.maxD2Length =3D 1520,
+	.vlantype =3D 0x8100,
+	.ecamptr =3D ((uint32_t) NULL),
+	.eventRegMask =3D UCCE_OTHER,
+	.pausePeriod =3D 0xf000,
+	.interruptcoalescingmaxvalue =3D {1, 1, 1, 1, 1, 1, 1, 1},
+	.bdRingLenTx =3D {
+			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 =3D {
+			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 =3D UCC_GETH_NUM_OF_STATION_ADDRESSES_1,
+	.largestexternallookupkeysize =3D
+	    QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE,
+	.statisticsMode =3D UCC_GETH_STATISTICS_GATHERING_MODE_NONE,
+	.vlanOperationTagged =3D UCC_GETH_VLAN_OPERATION_TAGGED_NOP,
+	.vlanOperationNonTagged =3D
UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP,
+	.rxQoSMode =3D UCC_GETH_QOS_MODE_DEFAULT,
+	.aufc =3D UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_NONE,
+	.padAndCrc =3D MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC,
+	.numThreadsTx =3D UCC_GETH_NUM_OF_THREADS_4,
+	.numThreadsRx =3D UCC_GETH_NUM_OF_THREADS_4,
+	.riscTx =3D QE_RISC_ALLOCATION_RISC1_AND_RISC2,
+	.riscRx =3D 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 =3D (size >> 4) << 4;
+	int size4Aling =3D (size >> 2) << 2;
+	int notAlign =3D 0;
+	if (size % 16)
+		notAlign =3D 1;
+
+	for (i =3D addr; (u32) i < (u32) addr + size16Aling; i +=3D 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 =3D=3D 1)
+		printk("0x%08x: ", (u32) i);
+	for (; (u32) i < (u32) addr + size4Aling; i +=3D 4)
+		printk("%08x ", *((u32 *) (i)));
+	for (; (u32) i < (u32) addr + size; i++)
+		printk("%02x", *((u8 *) (i)));
+	if (notAlign =3D=3D 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 =3D 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=20
+	Configuration table */
+	switch (enet_interface) {
+	case ENET_10_MII:
+		*speed =3D ENET_SPEED_10BT;
+		break;
+	case ENET_10_RMII:
+		*speed =3D ENET_SPEED_10BT;
+		*r10m =3D 1;
+		*rmm =3D 1;
+		break;
+	case ENET_10_RGMII:
+		*speed =3D ENET_SPEED_10BT;
+		*rpm =3D 1;
+		*r10m =3D 1;
+		*limited_to_full_duplex =3D 1;
+		break;
+	case ENET_100_MII:
+		*speed =3D ENET_SPEED_100BT;
+		break;
+	case ENET_100_RMII:
+		*speed =3D ENET_SPEED_100BT;
+		*rmm =3D 1;
+		break;
+	case ENET_100_RGMII:
+		*speed =3D ENET_SPEED_100BT;
+		*rpm =3D 1;
+		*limited_to_full_duplex =3D 1;
+		break;
+	case ENET_1000_GMII:
+		*speed =3D ENET_SPEED_1000BT;
+		*limited_to_full_duplex =3D 1;
+		break;
+	case ENET_1000_RGMII:
+		*speed =3D ENET_SPEED_1000BT;
+		*rpm =3D 1;
+		*limited_to_full_duplex =3D 1;
+		break;
+	case ENET_1000_TBI:
+		*speed =3D ENET_SPEED_1000BT;
+		*tbi =3D 1;
+		*limited_to_full_duplex =3D 1;
+		break;
+	case ENET_1000_RTBI:
+		*speed =3D ENET_SPEED_1000BT;
+		*rpm =3D 1;
+		*tbi =3D 1;
+		*limited_to_full_duplex =3D 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 =3D NULL;
+
+	skb =3D dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
+				  UCC_GETH_RX_DATA_BUF_ALIGNMENT);
+
+	if (skb =3D=3D 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 =3D 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 =3D ugeth->p_rx_bd_ring[rxQ];
+	i =3D 0;
+
+	do {
+		bd_status =3D BD_STATUS_AND_LENGTH(bd);
+		skb =3D get_new_skb(ugeth, bd);
+
+		if (!skb)	/* If can not allocate data buffer,=20
+				abort. Cleanup will be elsewhere */
+			return -ENOMEM;
+
+		ugeth->rx_skbuff[rxQ][i] =3D skb;
+
+		/* advance the BD pointer */
+		bd +=3D 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 =3D 0; i < num_entries; i++) {
+		if ((snum =3D qe_get_snum()) < 0) {
+			ugeth_err("fill_init_enet_entries: Can not get
SNUM.");
+			return snum;
+		}
+		if ((i =3D=3D 0) && skip_page_for_first_entry)
+		/* First entry of Rx does not have page */
+			init_enet_offset =3D 0;
+		else {
+			init_enet_offset =3D
+			    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++) =3D
+		    ((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 =3D 0; i < num_entries; i++) {
+		/* Check that this entry was actually valid --=20
+		needed in case failed in allocations */
+		if ((*p_start & ENET_INIT_PARAM_RISC_MASK) =3D=3D risc) {
+			snum =3D
+			    (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK)
>>
+			    ENET_INIT_PARAM_SNUM_SHIFT;
+			qe_put_snum((u8) snum);
+			if (!((i =3D=3D 0) && skip_page_for_first_entry)) {=09
+			/* First entry of Rx does not have page */
+				init_enet_offset =3D
+				    (in_be32(p_start) &
+				     ENET_INIT_PARAM_PTR_MASK);
+				qe_muram_free(init_enet_offset);
+			}
+			*(p_start++) =3D 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 =3D 0; i < num_entries; i++) {
+		/* Check that this entry was actually valid --=20
+		needed in case failed in allocations */
+		if ((*p_start & ENET_INIT_PARAM_RISC_MASK) =3D=3D risc) {
+			snum =3D
+			    (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK)
>>
+			    ENET_INIT_PARAM_SNUM_SHIFT;
+			qe_put_snum((u8) snum);
+			if (!((i =3D=3D 0) && skip_page_for_first_entry)) {=09
+			/* First entry of Rx does not have page */
+				init_enet_offset =3D
+				    (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 =3D 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 =3D
+	    (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 =3D
+	    (ucc_geth_82xx_address_filtering_pram_t *)
ugeth->p_rx_glbl_pram->
+	    addressfiltering;
+
+	/* Writing address ff.ff.ff.ff.ff.ff disables address=20
+	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 =3D
+	    (ucc_geth_82xx_address_filtering_pram_t *)
ugeth->p_rx_glbl_pram->
+	    addressfiltering;
+
+	cecr_subblock =3D
+
ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
+
+	/* Ethernet frames are defined in Little Endian mode,=20
+	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 =3D ugeth->uccf;
+	ug_regs =3D ugeth->ug_regs;
+
+	/* Enable interrupts for magic packet detection */
+	uccm =3D in_be32(uccf->p_uccm);
+	uccm |=3D UCCE_MPD;
+	out_be32(uccf->p_uccm, uccm);
+
+	/* Enable magic packet detection */
+	maccfg2 =3D in_be32(&ug_regs->maccfg2);
+	maccfg2 |=3D 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 =3D ugeth->uccf;
+	ug_regs =3D ugeth->ug_regs;
+
+	/* Disable interrupts for magic packet detection */
+	uccm =3D in_be32(uccf->p_uccm);
+	uccm &=3D ~UCCE_MPD;
+	out_be32(uccf->p_uccm, uccm);
+
+	/* Disable magic packet detection */
+	maccfg2 =3D in_be32(&ug_regs->maccfg2);
+	maccfg2 &=3D ~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 =3D ugeth->ug_regs;
+	uf_regs =3D (ucc_fast_t *) ug_regs;
+	p_tx_fw_statistics_pram =3D ugeth->p_tx_fw_statistics_pram;
+	p_rx_fw_statistics_pram =3D ugeth->p_rx_fw_statistics_pram;
+
+	/* Tx firmware only if user handed pointer and driver actually=20
+	gathers Tx firmware statistics */
+	if (tx_firmware_statistics && p_tx_fw_statistics_pram) {
+		tx_firmware_statistics->sicoltx =3D
+		    in_be32(&p_tx_fw_statistics_pram->sicoltx);
+		tx_firmware_statistics->mulcoltx =3D
+		    in_be32(&p_tx_fw_statistics_pram->mulcoltx);
+		tx_firmware_statistics->latecoltxfr =3D
+		    in_be32(&p_tx_fw_statistics_pram->latecoltxfr);
+		tx_firmware_statistics->frabortduecol =3D
+		    in_be32(&p_tx_fw_statistics_pram->frabortduecol);
+		tx_firmware_statistics->frlostinmactxer =3D
+		    in_be32(&p_tx_fw_statistics_pram->frlostinmactxer);
+		tx_firmware_statistics->carriersenseertx =3D
+		    in_be32(&p_tx_fw_statistics_pram->carriersenseertx);
+		tx_firmware_statistics->frtxok =3D
+		    in_be32(&p_tx_fw_statistics_pram->frtxok);
+		tx_firmware_statistics->txfrexcessivedefer =3D
+
in_be32(&p_tx_fw_statistics_pram->txfrexcessivedefer);
+		tx_firmware_statistics->txpkts256 =3D
+		    in_be32(&p_tx_fw_statistics_pram->txpkts256);
+		tx_firmware_statistics->txpkts512 =3D
+		    in_be32(&p_tx_fw_statistics_pram->txpkts512);
+		tx_firmware_statistics->txpkts1024 =3D
+		    in_be32(&p_tx_fw_statistics_pram->txpkts1024);
+		tx_firmware_statistics->txpktsjumbo =3D
+		    in_be32(&p_tx_fw_statistics_pram->txpktsjumbo);
+	}
+
+	/* Rx firmware only if user handed pointer and driver actually=20
+	 * gathers Rx firmware statistics */
+	if (rx_firmware_statistics && p_rx_fw_statistics_pram) {
+		int i;
+		rx_firmware_statistics->frrxfcser =3D
+		    in_be32(&p_rx_fw_statistics_pram->frrxfcser);
+		rx_firmware_statistics->fraligner =3D
+		    in_be32(&p_rx_fw_statistics_pram->fraligner);
+		rx_firmware_statistics->inrangelenrxer =3D
+		    in_be32(&p_rx_fw_statistics_pram->inrangelenrxer);
+		rx_firmware_statistics->outrangelenrxer =3D
+		    in_be32(&p_rx_fw_statistics_pram->outrangelenrxer);
+		rx_firmware_statistics->frtoolong =3D
+		    in_be32(&p_rx_fw_statistics_pram->frtoolong);
+		rx_firmware_statistics->runt =3D
+		    in_be32(&p_rx_fw_statistics_pram->runt);
+		rx_firmware_statistics->verylongevent =3D
+		    in_be32(&p_rx_fw_statistics_pram->verylongevent);
+		rx_firmware_statistics->symbolerror =3D
+		    in_be32(&p_rx_fw_statistics_pram->symbolerror);
+		rx_firmware_statistics->dropbsy =3D
+		    in_be32(&p_rx_fw_statistics_pram->dropbsy);
+		for (i =3D 0; i < 0x8; i++)
+			rx_firmware_statistics->res0[i] =3D
+			    p_rx_fw_statistics_pram->res0[i];
+		rx_firmware_statistics->mismatchdrop =3D
+		    in_be32(&p_rx_fw_statistics_pram->mismatchdrop);
+		rx_firmware_statistics->underpkts =3D
+		    in_be32(&p_rx_fw_statistics_pram->underpkts);
+		rx_firmware_statistics->pkts256 =3D
+		    in_be32(&p_rx_fw_statistics_pram->pkts256);
+		rx_firmware_statistics->pkts512 =3D
+		    in_be32(&p_rx_fw_statistics_pram->pkts512);
+		rx_firmware_statistics->pkts1024 =3D
+		    in_be32(&p_rx_fw_statistics_pram->pkts1024);
+		rx_firmware_statistics->pktsjumbo =3D
+		    in_be32(&p_rx_fw_statistics_pram->pktsjumbo);
+		rx_firmware_statistics->frlossinmacer =3D
+		    in_be32(&p_rx_fw_statistics_pram->frlossinmacer);
+		rx_firmware_statistics->pausefr =3D
+		    in_be32(&p_rx_fw_statistics_pram->pausefr);
+		for (i =3D 0; i < 0x4; i++)
+			rx_firmware_statistics->res1[i] =3D
+			    p_rx_fw_statistics_pram->res1[i];
+		rx_firmware_statistics->removevlan =3D
+		    in_be32(&p_rx_fw_statistics_pram->removevlan);
+		rx_firmware_statistics->replacevlan =3D
+		    in_be32(&p_rx_fw_statistics_pram->replacevlan);
+		rx_firmware_statistics->insertvlan =3D
+		    in_be32(&p_rx_fw_statistics_pram->insertvlan);
+	}
+
+	/* Hardware only if user handed pointer and driver actually=20
+	gathers hardware statistics */
+	if (hardware_statistics && (in_be32(&uf_regs->upsmr) &
UPSMR_HSE)) {
+		hardware_statistics->tx64 =3D in_be32(&ug_regs->tx64);
+		hardware_statistics->tx127 =3D in_be32(&ug_regs->tx127);
+		hardware_statistics->tx255 =3D in_be32(&ug_regs->tx255);
+		hardware_statistics->rx64 =3D in_be32(&ug_regs->rx64);
+		hardware_statistics->rx127 =3D in_be32(&ug_regs->rx127);
+		hardware_statistics->rx255 =3D in_be32(&ug_regs->rx255);
+		hardware_statistics->txok =3D in_be32(&ug_regs->txok);
+		hardware_statistics->txcf =3D in_be16(&ug_regs->txcf);
+		hardware_statistics->tmca =3D in_be32(&ug_regs->tmca);
+		hardware_statistics->tbca =3D in_be32(&ug_regs->tbca);
+		hardware_statistics->rxfok =3D in_be32(&ug_regs->rxfok);
+		hardware_statistics->rxbok =3D in_be32(&ug_regs->rxbok);
+		hardware_statistics->rbyt =3D in_be32(&ug_regs->rbyt);
+		hardware_statistics->rmca =3D in_be32(&ug_regs->rmca);
+		hardware_statistics->rbca =3D in_be32(&ug_regs->rbca);
+	}
+}
+
+static void dump_bds(ucc_geth_private_t *ugeth)
+{
+	int i;
+	int length;
+
+	for (i =3D 0; i < ugeth->ug_info->numQueuesTx; i++) {
+		if (ugeth->p_tx_bd_ring[i]) {
+			length =3D
+			    (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 =3D 0; i < ugeth->ug_info->numQueuesRx; i++) {
+		if (ugeth->p_rx_bd_ring[i]) {
+			length =3D
+			    (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 =3D 1;
+			break;
+		case UCC_GETH_NUM_OF_THREADS_2:
+			numThreadsTxNumerical =3D 2;
+			break;
+		case UCC_GETH_NUM_OF_THREADS_4:
+			numThreadsTxNumerical =3D 4;
+			break;
+		case UCC_GETH_NUM_OF_THREADS_6:
+			numThreadsTxNumerical =3D 6;
+			break;
+		case UCC_GETH_NUM_OF_THREADS_8:
+			numThreadsTxNumerical =3D 8;
+			break;
+		default:
+			numThreadsTxNumerical =3D 0;
+			break;
+		}
+
+		ugeth_info("Thread data TXs:");
+		ugeth_info("Base address: 0x%08x",
+			   (u32) ugeth->p_thread_data_tx);
+		for (i =3D 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 =3D 1;
+			break;
+		case UCC_GETH_NUM_OF_THREADS_2:
+			numThreadsRxNumerical =3D 2;
+			break;
+		case UCC_GETH_NUM_OF_THREADS_4:
+			numThreadsRxNumerical =3D 4;
+			break;
+		case UCC_GETH_NUM_OF_THREADS_6:
+			numThreadsRxNumerical =3D 6;
+			break;
+		case UCC_GETH_NUM_OF_THREADS_8:
+			numThreadsRxNumerical =3D 8;
+			break;
+		default:
+			numThreadsRxNumerical =3D 0;
+			break;
+		}
+
+		ugeth_info("Thread data RX:");
+		ugeth_info("Base address: 0x%08x",
+			   (u32) ugeth->p_thread_data_rx);
+		for (i =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D sizeof(ucc_geth_thread_rx_pram_t);
+		if (ugeth->ug_info->rxExtendedFiltering) {
+			size +=3D
+
THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING;
+			if (ugeth->ug_info->largestexternallookupkeysize
=3D=3D
+			    QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES)
+				size +=3D
+
THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8;
+			if (ugeth->ug_info->largestexternallookupkeysize
=3D=3D
+			    QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES)
+				size +=3D
+
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 =3D 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 =3D (u32) (alt_beb_truncation <<
HALFDUP_ALT_BEB_TRUNCATION_SHIFT);
+
+	if (alt_beb)
+		value |=3D HALFDUP_ALT_BEB;
+	if (back_pressure_no_backoff)
+		value |=3D HALFDUP_BACK_PRESSURE_NO_BACKOFF;
+	if (no_backoff)
+		value |=3D HALFDUP_NO_BACKOFF;
+	if (excess_defer)
+		value |=3D HALFDUP_EXCESSIVE_DEFER;
+
+	value |=3D (max_retransmissions <<
HALFDUP_MAX_RETRANSMISSION_SHIFT);
+
+	value |=3D 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 =3D 0;
+
+	/* Non-Back-to-back IPG part 1 should be <=3D Non-Back-to-back=20
+	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 |=3D
+	    ((non_btb_cs_ipg << IPGIFG_NON_BACK_TO_BACK_IFG_PART1_SHIFT)
&
+	     IPGIFG_NBTB_CS_IPG_MASK);
+	value |=3D
+	    ((non_btb_ipg << IPGIFG_NON_BACK_TO_BACK_IFG_PART2_SHIFT) &
+	     IPGIFG_NBTB_IPG_MASK);
+	value |=3D
+	    ((min_ifg << IPGIFG_MINIMUM_IFG_ENFORCEMENT_SHIFT) &
+	     IPGIFG_MIN_IFG_MASK);
+	value |=3D (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 =3D 0;
+
+	/* Set UEMPR register */
+	value =3D (u32) pause_period << UEMPR_PAUSE_TIME_VALUE_SHIFT;
+	value |=3D (u32) extension_field <<
UEMPR_EXTENDED_PAUSE_TIME_VALUE_SHIFT;
+	out_be32(uempr_register, value);
+
+	/* Set UPSMR register */
+	value =3D in_be32(upsmr_register);
+	value |=3D automatic_flow_control_mode;
+	out_be32(upsmr_register, value);
+
+	value =3D in_be32(maccfg1_register);
+	if (rx_flow_control_enable)
+		value |=3D MACCFG1_FLOW_RX;
+	if (tx_flow_control_enable)
+		value |=3D 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 =3D 0;
+	u16 uescr_value =3D 0;
+	/* Enable hardware statistics gathering if requested */
+	if (enable_hardware_statistics) {
+		upsmr_value =3D in_be32(upsmr_register);
+		upsmr_value |=3D UPSMR_HSE;
+		out_be32(upsmr_register, upsmr_value);
+	}
+
+	/* Clear hardware statistics counters */
+	uescr_value =3D in_be16(uescr_register);
+	uescr_value |=3D UESCR_CLRCNT;
+	/* Automatically zero hardware statistics counters on read,=20
+	if requested */
+	if (auto_zero_hardware_statistics)
+		uescr_value |=3D 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 =3D in_be16(temoder_register);
+		temoder_value |=3D 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 =3D in_be32(remoder_register);
+		remoder_value |=3D 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 =3D 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 |=3D (u32) ((address_byte_2 << 0) & 0x000000FF);
+	value |=3D (u32) ((address_byte_3 << 8) & 0x0000FF00);
+	value |=3D (u32) ((address_byte_4 << 16) & 0x00FF0000);
+	value |=3D (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 =3D 0;
+	value |=3D (u32) ((address_byte_0 << 16) & 0x00FF0000);
+	value |=3D (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 =3D 0;
+
+	/* some interfaces must work in full duplex mode */
+	if ((full_duplex =3D=3D 0) && (limited_to_full_duplex =3D=3D 1))
+		return -EINVAL;
+
+	value =3D in_be32(maccfg2_register);
+
+	if (full_duplex)
+		value |=3D MACCFG2_FDX;
+	else
+		value &=3D ~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 =3D 0;
+
+	value =3D in_be32(maccfg2_register);
+
+	if (length_check)
+		value |=3D MACCFG2_LC;
+	else
+		value &=3D ~MACCFG2_LC;
+
+	out_be32(maccfg2_register, value);
+	return 0;
+}
+
+static int init_preamble_length(u8 preamble_length,
+				volatile u32 *maccfg2_register)
+{
+	u32 value =3D 0;
+
+	if ((preamble_length < 3) || (preamble_length > 7))
+		return -EINVAL;
+
+	value =3D in_be32(maccfg2_register);
+	value &=3D ~MACCFG2_PREL_MASK;
+	value |=3D (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 =3D PHY_INIT_TIMEOUT;
+	u32 value =3D 0;
+
+	value =3D in_be32(miimcfg_register);
+	if (reset_mgmt) {
+		value |=3D MIIMCFG_RESET_MANAGEMENT;
+		out_be32(miimcfg_register, value);
+	}
+
+	value =3D 0;
+
+	if (preamble_supress)
+		value |=3D MIIMCFG_NO_PREAMBLE;
+
+	value |=3D 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 <=3D 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 =3D 0;
+
+	value =3D in_be32(upsmr_register);
+
+	if (reject_broadcast)
+		value |=3D UPSMR_BRO;
+	else
+		value &=3D ~UPSMR_BRO;
+
+	if (receive_short_frames)
+		value |=3D UPSMR_RSH;
+	else
+		value &=3D ~UPSMR_RSH;
+
+	if (promiscuous)
+		value |=3D UPSMR_PRO;
+	else
+		value &=3D ~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 =3D=3D 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 =3D 0;
+
+	mrblr_value =3D in_be16(mrblr_register);
+	if (min_frame_length >=3D (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 =3D 0, tbi =3D 0, r10m =3D 0, rmm =3D
+	    0, limited_to_full_duplex =3D 0;
+	u32 upsmr, maccfg2, utbipar, tbiBaseAddress;
+	u16 value;
+
+	ugeth_vdbg("%s: IN", __FUNCTION__);
+
+	ug_info =3D ugeth->ug_info;
+	ug_regs =3D ugeth->ug_regs;
+	uf_regs =3D ugeth->uccf->uf_regs;
+
+	/* Analyze enet_interface according to Interface Mode
Configuration=20
+	table */
+	ret_val =3D
+	    get_interface_details(ug_info->enet_interface, &speed,
&r10m, &rmm,
+				  &rpm, &tbi, &limited_to_full_duplex);
+	if (ret_val !=3D 0) {
+		ugeth_err
+		  ("%s: half duplex not supported in requested
configuration.",
+		     __FUNCTION__);
+		return ret_val;
+	}
+
+	/*                    Set MACCFG2                    */
+	maccfg2 =3D in_be32(&ug_regs->maccfg2);
+	maccfg2 &=3D ~MACCFG2_INTERFACE_MODE_MASK;
+	if ((speed =3D=3D ENET_SPEED_10BT) || (speed =3D=3D ENET_SPEED_100BT))
+		maccfg2 |=3D MACCFG2_INTERFACE_MODE_NIBBLE;
+	else if (speed =3D=3D ENET_SPEED_1000BT)
+		maccfg2 |=3D MACCFG2_INTERFACE_MODE_BYTE;
+	maccfg2 |=3D ug_info->padAndCrc;
+	out_be32(&ug_regs->maccfg2, maccfg2);
+
+	/*                    Set UPSMR                      */
+	upsmr =3D in_be32(&uf_regs->upsmr);
+	upsmr &=3D ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM);
+	if (rpm)
+		upsmr |=3D UPSMR_RPM;
+	if (r10m)
+		upsmr |=3D UPSMR_R10M;
+	if (tbi)
+		upsmr |=3D UPSMR_TBIM;
+	if (rmm)
+		upsmr |=3D UPSMR_RMM;
+	out_be32(&uf_regs->upsmr, upsmr);
+
+	/*                    Set UTBIPAR                    */
+	utbipar =3D in_be32(&ug_regs->utbipar);
+	utbipar &=3D ~UTBIPAR_PHY_ADDRESS_MASK;
+	if (tbi)
+		utbipar |=3D
+		    (ug_info->phy_address +
+		     ugeth->ug_info->uf_info.
+		     ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
+	else
+		utbipar |=3D
+		    (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=20
+	comes up in autonegotiation mode. */
+	/* Note that this depends on proper setting in utbipar register.
*/
+	if (tbi) {
+		tbiBaseAddress =3D in_be32(&ug_regs->utbipar);
+		tbiBaseAddress &=3D UTBIPAR_PHY_ADDRESS_MASK;
+		tbiBaseAddress >>=3D UTBIPAR_PHY_ADDRESS_SHIFT;
+		value =3D
+		    ugeth->mii_info->mdio_read(ugeth->dev, (u8)
tbiBaseAddress,
+					       ENET_TBI_MII_CR);
+		value &=3D ~0x1000;	/* Turn off autonegotiation */
+		ugeth->mii_info->mdio_write(ugeth->dev, (u8)
tbiBaseAddress,
+					    ENET_TBI_MII_CR, value);
+	}
+
+	ret_val =3D init_mac_duplex_mode(1,
+				       limited_to_full_duplex,
+				       &ug_regs->maccfg2);
+	if (ret_val !=3D 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 =3D init_preamble_length(ug_info->prel,
&ug_regs->maccfg2);
+	if (ret_val !=3D 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 =3D netdev_priv(dev);
+	ucc_geth_t *ug_regs;
+	u32 tempval;
+	struct ugeth_mii_info *mii_info =3D ugeth->mii_info;
+
+	ug_regs =3D 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 !=3D ugeth->oldduplex) {
+			if (!(mii_info->duplex)) {
+				tempval =3D in_be32(&ug_regs->maccfg2);
+				tempval &=3D ~(MACCFG2_FDX);
+				out_be32(&ug_regs->maccfg2, tempval);
+
+				ugeth_info("%s: Half Duplex",
dev->name);
+			} else {
+				tempval =3D in_be32(&ug_regs->maccfg2);
+				tempval |=3D MACCFG2_FDX;
+				out_be32(&ug_regs->maccfg2, tempval);
+
+				ugeth_info("%s: Full Duplex",
dev->name);
+			}
+
+			ugeth->oldduplex =3D mii_info->duplex;
+		}
+
+		if (mii_info->speed !=3D ugeth->oldspeed) {
+			switch (mii_info->speed) {
+			case 1000:
+#ifdef CONFIG_MPC836x
+/* FIXME: This code is for 100Mbs BUG fixing,=20
+remove this when it is fixed!!! */
+				if (ugeth->ug_info->enet_interface =3D=3D
+				    ENET_1000_GMII)
+				/* Run the commands which initialize the
PHY */
+				{
+					tempval =3D
+					    (u32)
mii_info->mdio_read(ugeth->
+						dev, mii_info->mii_id,
0x1b);
+					tempval |=3D 0x000f;
+					mii_info->mdio_write(ugeth->dev,
+						mii_info->mii_id, 0x1b,
+						(u16) tempval);
+					tempval =3D
+					    (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 =3D=3D
+					   ENET_1000_RGMII)
+				/* Run the commands which initialize the
PHY */
+				{
+					tempval =3D
+					    (u32)
mii_info->mdio_read(ugeth->
+						dev, mii_info->mii_id,
0x1b);
+					tempval =3D (tempval & ~0x000f) |
0x000b;
+					mii_info->mdio_write(ugeth->dev,
+						mii_info->mii_id, 0x1b,
+						(u16) tempval);
+					tempval =3D
+					    (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,=20
+remove this lines when it will be fixed!!! */
+				ugeth->ug_info->enet_interface =3D
ENET_100_RGMII;
+				tempval =3D
+				    (u32)
mii_info->mdio_read(ugeth->dev,
+
mii_info->mii_id,
+							      0x1b);
+				tempval =3D (tempval & ~0x000f) | 0x000b;
+				mii_info->mdio_write(ugeth->dev,
+						     mii_info->mii_id,
0x1b,
+						     (u16) tempval);
+				tempval =3D
+				    (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 =3D mii_info->speed;
+		}
+
+		if (!ugeth->oldlink) {
+			ugeth_info("%s: Link is up", dev->name);
+			ugeth->oldlink =3D 1;
+			netif_carrier_on(dev);
+			netif_schedule(dev);
+		}
+	} else {
+		if (ugeth->oldlink) {
+			ugeth_info("%s: Link is down", dev->name);
+			ugeth->oldlink =3D 0;
+			ugeth->oldspeed =3D 0;
+			ugeth->oldduplex =3D -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 =3D netdev_priv(dev);
+	struct phy_info *curphy;
+	ucc_mii_mng_t *mii_regs;
+	struct ugeth_mii_info *mii_info;
+	int err;
+
+	mii_regs =3D &ugeth->ug_regs->miimng;
+
+	ugeth->oldlink =3D 0;
+	ugeth->oldspeed =3D 0;
+	ugeth->oldduplex =3D -1;
+
+	mii_info =3D kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL);
+
+	if (NULL =3D=3D mii_info) {
+		ugeth_err("%s: Could not allocate mii_info", dev->name);
+		return -ENOMEM;
+	}
+
+	mii_info->mii_regs =3D mii_regs;
+	mii_info->speed =3D SPEED_1000;
+	mii_info->duplex =3D DUPLEX_FULL;
+	mii_info->pause =3D 0;
+	mii_info->link =3D 0;
+
+	mii_info->advertising =3D (ADVERTISED_10baseT_Half |
+				 ADVERTISED_10baseT_Full |
+				 ADVERTISED_100baseT_Half |
+				 ADVERTISED_100baseT_Full |
+				 ADVERTISED_1000baseT_Full);
+	mii_info->autoneg =3D 1;
+
+	mii_info->mii_id =3D ugeth->ug_info->phy_address;
+
+	mii_info->dev =3D dev;
+
+	mii_info->mdio_read =3D &read_phy_reg;
+	mii_info->mdio_write =3D &write_phy_reg;
+
+	ugeth->mii_info =3D 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 =3D -1;
+		goto bus_fail;
+	}
+
+	spin_unlock_irq(&ugeth->lock);
+
+	/* get info for this PHY */
+	curphy =3D get_phy_info(ugeth->mii_info);
+
+	if (curphy =3D=3D NULL) {
+		ugeth_err("%s: No PHY found", dev->name);
+		err =3D -1;
+		goto no_phy;
+	}
+
+	mii_info->phyinfo =3D curphy;
+
+	/* Run the commands which initialize the PHY */
+	if (curphy->init) {
+		err =3D 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 =3D ugeth->uccf;
+
+	/* Mask GRACEFUL STOP TX interrupt bit and clear it */
+	temp =3D in_be32(uccf->p_uccm);
+	temp &=3D ~UCCE_GRA;
+	out_be32(uccf->p_uccm, temp);
+	out_be32(uccf->p_ucce, UCCE_GRA);	/* clear by writing 1 */
+
+	/* Issue host command */
+	cecr_subblock =3D
+
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 =3D in_be32(uccf->p_ucce);
+	} while (!(temp & UCCE_GRA));
+
+	uccf->stopped_tx =3D 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 =3D ugeth->uccf;
+
+	/* Clear acknowledge bit */
+	temp =3D ugeth->p_rx_glbl_pram->rxgstpack;
+	temp &=3D ~GRACEFUL_STOP_ACKNOWLEDGE_RX;
+	ugeth->p_rx_glbl_pram->rxgstpack =3D temp;
+
+	/* Keep issuing command and checking acknowledge bit until=20
+	it is asserted, according to spec */
+	do {
+		/* Issue host command */
+		cecr_subblock =3D
+		    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 =3D ugeth->p_rx_glbl_pram->rxgstpack;
+	} while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX));
+
+	uccf->stopped_rx =3D 1;
+
+	return 0;
+}
+
+static int ugeth_restart_tx(ucc_geth_private_t *ugeth)
+{
+	ucc_fast_private_t *uccf;
+	u32 cecr_subblock;
+
+	uccf =3D ugeth->uccf;
+
+	cecr_subblock =3D
+
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 =3D 0;
+
+	return 0;
+}
+
+static int ugeth_restart_rx(ucc_geth_private_t *ugeth)
+{
+	ucc_fast_private_t *uccf;
+	u32 cecr_subblock;
+
+	uccf =3D ugeth->uccf;
+
+	cecr_subblock =3D
+
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 =3D 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 =3D ugeth->uccf;
+
+	/* check if the UCC number is in range. */
+	if (ugeth->ug_info->uf_info.ucc_num >=3D UCC_MAX_NUM) {
+		ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	enabled_tx =3D uccf->enabled_tx;
+	enabled_rx =3D uccf->enabled_rx;
+
+	/* Get Tx and Rx going again, in case this channel was actively=20
+	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 =3D ugeth->uccf;
+
+	/* check if the UCC number is in range. */
+	if (ugeth->ug_info->uf_info.ucc_num >=3D 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] |=3D UCC_GETH_TAD_V;	/* Must have
this */
+	if (p_UccGethTadParams->rx_non_dynamic_extended_features_mode ||
+	    (p_UccGethTadParams->vtag_op !=3D
UCC_GETH_VLAN_OPERATION_TAGGED_NOP)
+	    || (p_UccGethTadParams->vnontag_op !=3D
+		UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP)
+	    )
+		qe_fltr_tad->serialized[0] |=3D UCC_GETH_TAD_EF;
+	if (p_UccGethTadParams->reject_frame)
+		qe_fltr_tad->serialized[0] |=3D UCC_GETH_TAD_REJ;
+	temp =3D
+	    (u16) (((u16) p_UccGethTadParams->
+		    vtag_op) << UCC_GETH_TAD_VTAG_OP_SHIFT);
+	qe_fltr_tad->serialized[0] |=3D (u8) (temp >> 8);	/* upper bits */
+
+	qe_fltr_tad->serialized[1] |=3D (u8) (temp & 0x00ff);	/* lower
bits */
+	if (p_UccGethTadParams->vnontag_op =3D=3D
+	    UCC_GETH_VLAN_OPERATION_NON_TAGGED_Q_TAG_INSERT)
+		qe_fltr_tad->serialized[1] |=3D
UCC_GETH_TAD_V_NON_VTAG_OP;
+	qe_fltr_tad->serialized[1] |=3D
+	    p_UccGethTadParams->rqos << UCC_GETH_TAD_RQOS_SHIFT;
+
+	qe_fltr_tad->serialized[2] |=3D
+	    p_UccGethTadParams->vpri << UCC_GETH_TAD_V_PRIORITY_SHIFT;
+	/* upper bits */
+	qe_fltr_tad->serialized[2] |=3D (u8) (p_UccGethTadParams->vid >>
8);
+	/* lower bits */
+	qe_fltr_tad->serialized[3] |=3D (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 =3D &ugeth->group_hash_q;
+		p_counter =3D &(ugeth->numGroupAddrInHash);
+	} else {
+		p_lh =3D &ugeth->ind_hash_q;
+		p_counter =3D &(ugeth->numIndAddrInHash);
+	}
+
+	if (!p_lh)
+		return NULL;
+
+	num =3D *p_counter;
+
+	for (i =3D 0; i < num; i++) {
+		enet_addr_cont =3D
+		    (enet_addr_container_t *)
+		    ENET_ADDR_CONT_ENTRY(dequeue(p_lh));
+		for (j =3D ENET_NUM_OCTETS_PER_ADDRESS - 1; j >=3D 0; j--) {
+			if ((*p_enet_addr)[j] !=3D
(enet_addr_cont->address)[j])
+				break;
+			if (j =3D=3D 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 =3D &ugeth->group_hash_q;
+		limit =3D ugeth->ug_info->maxGroupAddrInHash;
+		location =3D
+
UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_GROUP_HASH;
+		p_counter =3D &(ugeth->numGroupAddrInHash);
+	} else {
+		p_lh =3D &ugeth->ind_hash_q;
+		limit =3D ugeth->ug_info->maxIndAddrInHash;
+		location =3D
+
UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_INDIVIDUAL_HASH;
+		p_counter =3D &(ugeth->numIndAddrInHash);
+	}
+
+	if ((enet_addr_cont =3D
+	     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 =3D get_enet_addr_container()))
+		return -ENOMEM;
+	for (i =3D 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++)
+		(enet_addr_cont->address)[i] =3D (*p_enet_addr)[i];
+	enet_addr_cont->location =3D 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 =3D ugeth->uccf;
+
+	p_82xx_addr_filt =3D
+	    (ucc_geth_82xx_address_filtering_pram_t *)
ugeth->p_rx_glbl_pram->
+	    addressfiltering;
+
+	if (!
+	    (enet_addr_cont =3D
+	     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 =3D &(p_82xx_addr_filt->gaddr_h);
+		addr_l =3D &(p_82xx_addr_filt->gaddr_l);
+		p_lh =3D &ugeth->group_hash_q;
+		p_counter =3D &(ugeth->numGroupAddrInHash);
+	} else {
+		addr_h =3D &(p_82xx_addr_filt->iaddr_h);
+		addr_l =3D &(p_82xx_addr_filt->iaddr_l);
+		p_lh =3D &ugeth->ind_hash_q;
+		p_counter =3D &(ugeth->numIndAddrInHash);
+	}
+
+	comm_dir =3D 0;
+	if (uccf->enabled_tx)
+		comm_dir |=3D COMM_DIR_TX;
+	if (uccf->enabled_rx)
+		comm_dir |=3D 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 =3D --(*p_counter);
+	for (i =3D 0; i < num; i++) {
+		enet_addr_cont =3D
+		    (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 */

^ permalink raw reply related

* asdf
From: Horms @ 2006-07-06 10:15 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Paul Mackerras, Anton Blanchard

I have been looking at unifying the way that panic_on_oops logs
what it is doing between the different architectures that implement it.
The first cab off the rank is the patch below which removes a seemingly
silly difference between the behaviour on 32 and 64 bit powerpc.

I have not been able to test this as I do not have a ppc64 machine
at my disposal. However I did test that it compiles thanks to
the wonders of crosstool.

Signed-Off-By: Horms <horms@verge.net.au>

 arch/powerpc/kernel/traps.c |    2 --
 1 file changed, 2 deletions(-)

diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 52f5659..908231a 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -157,10 +157,8 @@ #endif
 		panic("Fatal exception in interrupt");
 
 	if (panic_on_oops) {
-#ifdef CONFIG_PPC64
 		printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
 		ssleep(5);
-#endif
 		panic("Fatal exception");
 	}
 	do_exit(err);

^ permalink raw reply related

* Re: [PATCH] powerpc: Xserve G5 thermal control fixes
From: Benjamin Herrenschmidt @ 2006-07-06  9:10 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev list, Paul Mackerras, Linux Kernel list
In-Reply-To: <20060706054639.GE5290@pb15.lixom.net>


> Doesn't it make more sense to keep this in the GIT log instead of in
> the file? (I seem to remember Freescale getting similar comments on some
> posted code just a few days ago :-)
> 
> Keeping version numbers for in-tree-only drivers isn't all that useful
> either.

Yeah, possibly.

Ben.

^ permalink raw reply

* Re: [PATCH] powerpc: Xserve G5 thermal control fixes
From: Benjamin Herrenschmidt @ 2006-07-06  9:09 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: linuxppc-dev list, Paul Mackerras, Linux Kernel list
In-Reply-To: <CCA3F98E-8F8F-4003-87BA-8091F8AB668F@kernel.crashing.org>

On Thu, 2006-07-06 at 07:37 +0200, Segher Boessenkool wrote:
> > This patch also changes the fixed value of the slots fan for
> > desktop G5s to 40% instead of 50%. It seems to still have a pretty  
> > good
> > airflow that way and is much less noisy.
> 
> Is this save when people have one of the ridiculously expensive
> (and hot) video cards installed?  And perhaps even a few other
> cards, too?

Those cards are nvidia and they only get hot if you use the 3d which you
can't do in linux/ppc (beside they have their own fan on the card
anyway).

Ben.

^ permalink raw reply

* Re: [PATCH] powerpc: Xserve G5 thermal control fixes (#2)
From: Benjamin Herrenschmidt @ 2006-07-06  8:03 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev list, Linux Kernel list
In-Reply-To: <1152162394.24632.58.camel@localhost.localdomain>

The thermal control for the Xserve G5s had a few issues. For one, the
way to program the RPM fans speeds into the FCU is different between it
and the desktop models, which I didn't figure out until recently, and it
was missing a control loop for the slots fan, running it too fast. Both
of those problems were causing the machine to be much more noisy than
necessary. This patch also changes the fixed value of the slots fan for
desktop G5s to 40% instead of 50%. It seems to still have a pretty good
airflow that way and is much less noisy.

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

This version adds code to tickle the FCU regulary so it doesn't timeout
if we decide not to change the fan speed for a while.

Index: linux-irq-work/drivers/macintosh/therm_pm72.c
===================================================================
--- linux-irq-work.orig/drivers/macintosh/therm_pm72.c	2006-07-06 16:43:34.000000000 +1000
+++ linux-irq-work/drivers/macintosh/therm_pm72.c	2006-07-06 16:52:43.000000000 +1000
@@ -95,6 +95,17 @@
  *	- Use min/max macros here or there
  *	- Latest darwin updated U3H min fan speed to 20% PWM
  *
+ *  July. 06, 2006 : 1.3
+ *	- Fix setting of RPM fans on Xserve G5 (they were going too fast)
+ *      - Add missing slots fan control loop for Xserve G5
+ *	- Lower fixed slots fan speed from 50% to 40% on desktop G5s. We
+ *        still can't properly implement the control loop for these, so let's
+ *        reduce the noise a little bit, it appears that 40% still gives us
+ *        a pretty good air flow
+ *	- Add code to "tickle" the FCU regulary so it doesn't think that
+ *        we are gone while in fact, the machine just didn't need any fan
+ *        speed change lately
+ *
  */
 
 #include <linux/types.h>
@@ -121,7 +132,7 @@
 
 #include "therm_pm72.h"
 
-#define VERSION "1.2b2"
+#define VERSION "1.3"
 
 #undef DEBUG
 
@@ -146,6 +157,7 @@
 static struct backside_pid_state	backside_state;
 static struct drives_pid_state		drives_state;
 static struct dimm_pid_state		dimms_state;
+static struct slots_pid_state		slots_state;
 static int				state;
 static int				cpu_count;
 static int				cpu_pid_type;
@@ -154,7 +166,8 @@
 static int				critical_state;
 static int				rackmac;
 static s32				dimm_output_clamp;
-
+static int 				fcu_rpm_shift;
+static int				fcu_tickle_ticks;
 static DECLARE_MUTEX(driver_lock);
 
 /*
@@ -495,13 +508,20 @@
 	rc = fan_write_reg(0x2e, &buf, 1);
 	if (rc < 0)
 		return -EIO;
+	rc = fan_read_reg(0, &buf, 1);
+	if (rc < 0)
+		return -EIO;
+	fcu_rpm_shift = (buf == 1) ? 2 : 3;
+	printk(KERN_DEBUG "FCU Initialized, RPM fan shift is %d\n",
+	       fcu_rpm_shift);
+
 	return 0;
 }
 
 static int set_rpm_fan(int fan_index, int rpm)
 {
 	unsigned char buf[2];
-	int rc, id;
+	int rc, id, min, max;
 
 	if (fcu_fans[fan_index].type != FCU_FAN_RPM)
 		return -EINVAL;
@@ -509,12 +529,15 @@
 	if (id == FCU_FAN_ABSENT_ID)
 		return -EINVAL;
 
-	if (rpm < 300)
-		rpm = 300;
-	else if (rpm > 8191)
-		rpm = 8191;
-	buf[0] = rpm >> 5;
-	buf[1] = rpm << 3;
+	min = 2400 >> fcu_rpm_shift;
+	max = 56000 >> fcu_rpm_shift;
+
+	if (rpm < min)
+		rpm = min;
+	else if (rpm > max)
+		rpm = max;
+	buf[0] = rpm >> (8 - fcu_rpm_shift);
+	buf[1] = rpm << fcu_rpm_shift;
 	rc = fan_write_reg(0x10 + (id * 2), buf, 2);
 	if (rc < 0)
 		return -EIO;
@@ -551,7 +574,7 @@
 	if (rc != 2)
 		return -EIO;
 
-	return (buf[0] << 5) | buf[1] >> 3;
+	return (buf[0] << (8 - fcu_rpm_shift)) | buf[1] >> fcu_rpm_shift;
 }
 
 static int set_pwm_fan(int fan_index, int pwm)
@@ -609,6 +632,26 @@
 	return (buf[0] * 1000) / 2559;
 }
 
+static void tickle_fcu(void)
+{
+	int pwm;
+
+	pwm = get_pwm_fan(SLOTS_FAN_PWM_INDEX);
+
+	DBG("FCU Tickle, slots fan is: %d\n", pwm);
+	if (pwm < 0)
+		pwm = 100;
+
+	if (!rackmac) {
+		pwm = SLOTS_FAN_DEFAULT_PWM;
+	} else if (pwm < SLOTS_PID_OUTPUT_MIN)
+		pwm = SLOTS_PID_OUTPUT_MIN;
+
+	/* That is hopefully enough to make the FCU happy */
+	set_pwm_fan(SLOTS_FAN_PWM_INDEX, pwm);
+}
+
+
 /*
  * Utility routine to read the CPU calibration EEPROM data
  * from the device-tree
@@ -715,6 +758,9 @@
 BUILD_SHOW_FUNC_FIX(drives_temperature, drives_state.last_temp)
 BUILD_SHOW_FUNC_INT(drives_fan_rpm, drives_state.rpm)
 
+BUILD_SHOW_FUNC_FIX(slots_temperature, slots_state.last_temp)
+BUILD_SHOW_FUNC_INT(slots_fan_pwm, slots_state.pwm)
+
 BUILD_SHOW_FUNC_FIX(dimms_temperature, dimms_state.last_temp)
 
 static DEVICE_ATTR(cpu0_temperature,S_IRUGO,show_cpu0_temperature,NULL);
@@ -735,6 +781,9 @@
 static DEVICE_ATTR(drives_temperature,S_IRUGO,show_drives_temperature,NULL);
 static DEVICE_ATTR(drives_fan_rpm,S_IRUGO,show_drives_fan_rpm,NULL);
 
+static DEVICE_ATTR(slots_temperature,S_IRUGO,show_slots_temperature,NULL);
+static DEVICE_ATTR(slots_fan_pwm,S_IRUGO,show_slots_fan_pwm,NULL);
+
 static DEVICE_ATTR(dimms_temperature,S_IRUGO,show_dimms_temperature,NULL);
 
 /*
@@ -1076,6 +1125,9 @@
 	fan_min = dimm_output_clamp;
 	fan_min = max(fan_min, (int)state->mpu.rminn_intake_fan);
 
+	DBG(" CPU min mpu = %d, min dimm = %d\n",
+	    state->mpu.rminn_intake_fan, dimm_output_clamp);
+
 	state->rpm = max(state->rpm, (int)fan_min);
 	state->rpm = min(state->rpm, (int)state->mpu.rmaxn_intake_fan);
 	state->intake_rpm = state->rpm;
@@ -1374,7 +1426,8 @@
 	DBG("  current rpm: %d\n", state->rpm);
 
 	/* Get some sensor readings */
-	temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor, DS1775_TEMP)) << 8;
+	temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor,
+						    DS1775_TEMP)) << 8;
 	state->last_temp = temp;
 	DBG("  temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp),
 	    FIX32TOPRINT(DRIVES_PID_INPUT_TARGET));
@@ -1575,7 +1628,7 @@
 }
 
 /*
- * Dispose of the state data for the drives control loop
+ * Dispose of the state data for the DIMM control loop
  */
 static void dispose_dimms_state(struct dimm_pid_state *state)
 {
@@ -1588,6 +1641,127 @@
 	state->monitor = NULL;
 }
 
+/*
+ * Slots fan control loop
+ */
+static void do_monitor_slots(struct slots_pid_state *state)
+{
+	s32 temp, integral, derivative;
+	s64 integ_p, deriv_p, prop_p, sum;
+	int i, rc;
+
+	if (--state->ticks != 0)
+		return;
+	state->ticks = SLOTS_PID_INTERVAL;
+
+	DBG("slots:\n");
+
+	/* Check fan status */
+	rc = get_pwm_fan(SLOTS_FAN_PWM_INDEX);
+	if (rc < 0) {
+		printk(KERN_WARNING "Error %d reading slots fan !\n", rc);
+		/* XXX What do we do now ? */
+	} else
+		state->pwm = rc;
+	DBG("  current pwm: %d\n", state->pwm);
+
+	/* Get some sensor readings */
+	temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor,
+						    DS1775_TEMP)) << 8;
+	state->last_temp = temp;
+	DBG("  temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp),
+	    FIX32TOPRINT(SLOTS_PID_INPUT_TARGET));
+
+	/* Store temperature and error in history array */
+	state->cur_sample = (state->cur_sample + 1) % SLOTS_PID_HISTORY_SIZE;
+	state->sample_history[state->cur_sample] = temp;
+	state->error_history[state->cur_sample] = temp - SLOTS_PID_INPUT_TARGET;
+
+	/* If first loop, fill the history table */
+	if (state->first) {
+		for (i = 0; i < (SLOTS_PID_HISTORY_SIZE - 1); i++) {
+			state->cur_sample = (state->cur_sample + 1) %
+				SLOTS_PID_HISTORY_SIZE;
+			state->sample_history[state->cur_sample] = temp;
+			state->error_history[state->cur_sample] =
+				temp - SLOTS_PID_INPUT_TARGET;
+		}
+		state->first = 0;
+	}
+
+	/* Calculate the integral term */
+	sum = 0;
+	integral = 0;
+	for (i = 0; i < SLOTS_PID_HISTORY_SIZE; i++)
+		integral += state->error_history[i];
+	integral *= SLOTS_PID_INTERVAL;
+	DBG("  integral: %08x\n", integral);
+	integ_p = ((s64)SLOTS_PID_G_r) * (s64)integral;
+	DBG("   integ_p: %d\n", (int)(integ_p >> 36));
+	sum += integ_p;
+
+	/* Calculate the derivative term */
+	derivative = state->error_history[state->cur_sample] -
+		state->error_history[(state->cur_sample + SLOTS_PID_HISTORY_SIZE - 1)
+				    % SLOTS_PID_HISTORY_SIZE];
+	derivative /= SLOTS_PID_INTERVAL;
+	deriv_p = ((s64)SLOTS_PID_G_d) * (s64)derivative;
+	DBG("   deriv_p: %d\n", (int)(deriv_p >> 36));
+	sum += deriv_p;
+
+	/* Calculate the proportional term */
+	prop_p = ((s64)SLOTS_PID_G_p) * (s64)(state->error_history[state->cur_sample]);
+	DBG("   prop_p: %d\n", (int)(prop_p >> 36));
+	sum += prop_p;
+
+	/* Scale sum */
+	sum >>= 36;
+
+	DBG("   sum: %d\n", (int)sum);
+	state->pwm = (s32)sum;
+
+	state->pwm = max(state->pwm, SLOTS_PID_OUTPUT_MIN);
+	state->pwm = min(state->pwm, SLOTS_PID_OUTPUT_MAX);
+
+	DBG("** DRIVES PWM: %d\n", (int)state->pwm);
+	set_pwm_fan(SLOTS_FAN_PWM_INDEX, state->pwm);
+}
+
+/*
+ * Initialize the state structure for the slots bay fan control loop
+ */
+static int init_slots_state(struct slots_pid_state *state)
+{
+	state->ticks = 1;
+	state->first = 1;
+	state->pwm = 50;
+
+	state->monitor = attach_i2c_chip(XSERVE_SLOTS_LM75, "slots_temp");
+	if (state->monitor == NULL)
+		return -ENODEV;
+
+	device_create_file(&of_dev->dev, &dev_attr_slots_temperature);
+	device_create_file(&of_dev->dev, &dev_attr_slots_fan_pwm);
+
+	return 0;
+}
+
+/*
+ * Dispose of the state data for the slots control loop
+ */
+static void dispose_slots_state(struct slots_pid_state *state)
+{
+	if (state->monitor == NULL)
+		return;
+
+	device_remove_file(&of_dev->dev, &dev_attr_slots_temperature);
+	device_remove_file(&of_dev->dev, &dev_attr_slots_fan_pwm);
+
+	detach_i2c_chip(state->monitor);
+	state->monitor = NULL;
+}
+
+
 static int call_critical_overtemp(void)
 {
 	char *argv[] = { critical_overtemp_path, NULL };
@@ -1617,14 +1791,17 @@
 		goto out;
 	}
 
-	/* Set the PCI fan once for now */
-	set_pwm_fan(SLOTS_FAN_PWM_INDEX, SLOTS_FAN_DEFAULT_PWM);
+	/* Set the PCI fan once for now on non-RackMac */
+	if (!rackmac)
+		set_pwm_fan(SLOTS_FAN_PWM_INDEX, SLOTS_FAN_DEFAULT_PWM);
 
 	/* Initialize ADCs */
 	initialize_adc(&cpu_state[0]);
 	if (cpu_state[1].monitor != NULL)
 		initialize_adc(&cpu_state[1]);
 
+	fcu_tickle_ticks = FCU_TICKLE_TICKS;
+
 	up(&driver_lock);
 
 	while (state == state_attached) {
@@ -1634,6 +1811,12 @@
 
 		down(&driver_lock);
 
+		/* Tickle the FCU just in case */
+		if (--fcu_tickle_ticks < 0) {
+			fcu_tickle_ticks = FCU_TICKLE_TICKS;
+			tickle_fcu();
+		}
+
 		/* First, we always calculate the new DIMMs state on an Xserve */
 		if (rackmac)
 			do_monitor_dimms(&dimms_state);
@@ -1654,7 +1837,9 @@
 		}
 		/* Then, the rest */
 		do_monitor_backside(&backside_state);
-		if (!rackmac)
+		if (rackmac)
+			do_monitor_slots(&slots_state);
+		else
 			do_monitor_drives(&drives_state);
 		up(&driver_lock);
 
@@ -1696,6 +1881,7 @@
 	dispose_cpu_state(&cpu_state[1]);
 	dispose_backside_state(&backside_state);
 	dispose_drives_state(&drives_state);
+	dispose_slots_state(&slots_state);
 	dispose_dimms_state(&dimms_state);
 }
 
@@ -1745,6 +1931,8 @@
 		goto fail;
 	if (rackmac && init_dimms_state(&dimms_state))
 		goto fail;
+	if (rackmac && init_slots_state(&slots_state))
+		goto fail;
 	if (!rackmac && init_drives_state(&drives_state))
 		goto fail;
 
Index: linux-irq-work/drivers/macintosh/therm_pm72.h
===================================================================
--- linux-irq-work.orig/drivers/macintosh/therm_pm72.h	2006-07-06 16:43:34.000000000 +1000
+++ linux-irq-work/drivers/macintosh/therm_pm72.h	2006-07-06 16:43:36.000000000 +1000
@@ -105,6 +105,7 @@
 #define DRIVES_DALLAS_ID	0x94
 #define BACKSIDE_MAX_ID		0x98
 #define XSERVE_DIMMS_LM87	0x25a
+#define XSERVE_SLOTS_LM75	0x290
 
 /*
  * Some MAX6690, DS1775, LM87 register definitions
@@ -198,7 +199,7 @@
 
 #define SLOTS_FAN_PWM_DEFAULT_ID	2
 #define SLOTS_FAN_PWM_INDEX		2
-#define	SLOTS_FAN_DEFAULT_PWM		50 /* Do better here ! */
+#define	SLOTS_FAN_DEFAULT_PWM		40 /* Do better here ! */
 
 
 /*
@@ -206,7 +207,7 @@
  */
 #define DIMM_PID_G_d			0
 #define DIMM_PID_G_p			0
-#define DIMM_PID_G_r			0x6553600
+#define DIMM_PID_G_r			0x06553600
 #define DIMM_PID_INPUT_TARGET		3276800
 #define DIMM_PID_INTERVAL    		1
 #define DIMM_PID_OUTPUT_MAX		14000
@@ -226,6 +227,31 @@
 };
 
 
+/*
+ * PID factors for the Xserve Slots control loop
+ */
+#define SLOTS_PID_G_d			0
+#define SLOTS_PID_G_p			0
+#define SLOTS_PID_G_r			0x00100000
+#define SLOTS_PID_INPUT_TARGET		3200000
+#define SLOTS_PID_INTERVAL    		1
+#define SLOTS_PID_OUTPUT_MAX		100
+#define SLOTS_PID_OUTPUT_MIN		20
+#define SLOTS_PID_HISTORY_SIZE		20
+
+struct slots_pid_state
+{
+	int			ticks;
+	struct i2c_client *	monitor;
+	s32	       		sample_history[SLOTS_PID_HISTORY_SIZE];
+	s32			error_history[SLOTS_PID_HISTORY_SIZE];
+	int			cur_sample;
+	s32			last_temp;
+	int			first;
+	int			pwm;
+};
+
+
 
 /* Desktops */
 
@@ -283,6 +309,9 @@
 	s32			pump_max;
 };
 
+/* Tickle FCU every 10 seconds */
+#define FCU_TICKLE_TICKS	10
+
 /*
  * Driver state
  */

^ permalink raw reply

* MPC5200 PCI resource allocation problem
From: robinpv @ 2006-07-06  7:17 UTC (permalink / raw)
  To: linuxppc-dev

Hi,
I am using the MPC5200 based board. I have a PCI 2250 bridge, with 2 
RTL8110S ethernet chips on the bridge.
I am using the lite5200 as reference code.
When i run the linux(2.6.16.1), during bootup the following messages are 
displayed,

PCI: Probing PCI hardware
PCI: Cannot allocate resource region 0 of PCI bridge 1
PCI: bridge 1 resource 0 moved to b0fff000..b0ffffff
PCI: Cannot allocate resource region 1 of PCI bridge 1
PCI: bridge 1 resource 1 moved to aff00000..afffffff
PCI: Cannot allocate resource region 2 of PCI bridge 1
PCI: bridge 1 resource 2 moved to 9ff00000..9fffffff

Looking at the iomem and ioports dump, shows that MMIO region has been 
allocated.
But in the ethernet driver when i try to access the ethernet registers. 
all the register content are shown as FFFF.
Also in the mpc52xx_pci.h, the default value for these macros are...
#define MPC52xx_PCI_IO_BASE       0xb0000000
#define MPC52xx_PCI_IO_START    0x00000000
For this setting, IO resource allocation fails
changing to
#define MPC52xx_PCI_IO_START    0xB0000000
passes through.

Can some suggest what could be the problem and how to go about.??

-------------------------------------------------------------------
the iomem dump is as follows
80000000-9fffffff : PCI prefetchable memory
  9ff00000-9fffffff : PCI Bus #01
a0000000-afffffff : PCI memory
  a0000000-a07fffff : 0000:00:10.0
  a0800000-a09fffff : 0000:00:10.0
    a0840000-a0840057 : ohci_hcd
  a0a00000-a0a000ff : 0000:00:11.0
    a0a00000-a0a000ff : SiI680
  a0a40000-a0a7ffff : 0000:00:1a.0
  aff00000-afffffff : PCI Bus #01
    aff00000-aff000ff : 0000:01:02.0
      aff00000-aff000ff : r8169 <= Ethernet 1
    aff00100-aff001ff : 0000:01:03.0
      aff00100-aff001ff : r8169 <=Ethernet 2
f0000900-f000097f : mpc52xx-mscan.0
f0000980-f00009ff : mpc52xx-mscan.1
f0000f00-f0000f1f : mpc52xx-spi
f0001000-f00010ff : ppc-soc-ohci
f0001300-f000130f : mpc52xx-bdlc
f0002000-f000209f : mpc52xx-psc.0
  f0002000-f000209f : mpc52xx_psc_uart
f0002200-f000229f : mpc52xx-psc.1
f0002400-f000249f : mpc52xx-psc.2
f0002600-f000269f : mpc52xx-psc.3
f0002800-f000289f : mpc52xx-psc.4
f0002c00-f0002c9f : mpc52xx-psc.5
f0003000-f00033ff : mpc52xx-fec
f0003a00-f0003aff : mpc52xx-ata
f0003d00-f0003d1f : fsl-i2c.0
f0003d40-f0003d5f : fsl-i2c.1
-------------------------------------------------------
the ioports dump is
  b0000000-b0000007 : 0000:00:11.0
  b0000008-b000000b : 0000:00:11.0
  b000000c-b000000f : 0000:00:11.0
  b0000010-b0000017 : 0000:00:11.0
  b0000020-b000002f : 0000:00:11.0
  b0fff000-b0ffffff : PCI Bus #01
    b0fff000-b0fff0ff : 0000:01:02.0
      b0fff000-b0fff0ff : r8169 <=Ethernet 1
    b0fff400-b0fff4ff : 0000:01:03.0
      b0fff400-b0fff4ff : r8169 <=Ethernet 2
----------------------------------------------------------

With Regards,
Robin

^ permalink raw reply

* Re: Problem in PCI with MPC5200B
From: Heiko Schocher @ 2006-07-06  7:08 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: hlrprasad
In-Reply-To: <mailman.656.1149719253.11183.linuxppc-embedded@ozlabs.org>

Hello Ram,

On Wed, 7 Jun 2006 11:05:16 +0530 Ram Prasad H L wrote
> hi all,
> 	We are using a customised board which is based on
> 	the reference design of lite5200B. But our board is customised by adding
> 	a PCI-PCI Bridge on the primary bus. On the secondary bus we have added
> 	a DSP(DM642) along with 2 PCI slots, which are routed through
> 	bridge (PCI2250) to MPC5200B.
> 
> 	As far as software is concerned we are using "mpc5200_lite_K26-BSP-b30"
> 	BSP downloaded from freescale's website for lite5200B. This BSP has a
> 	u-boot-1.1.3 and linux kernel-2.6.11.7. As far as u-boot is concerned
> 	the PCI devices are allocated and assigned with proper resources (BAR's)
> 	which come under the range for Mem region(40000000 - 4fffffff) and I/O
> 	region (50000000 - 50ffffff). But during the boot process of linux we
> 	are getting the following errors:
> 
> 
> ****************************************************************************
> ***
> 	PCI: Probing PCI hardware
> 	PCI: Cannot allocate resource region 1 of PCI bridge 1
> 	PCI: bridge 1 resource 1 moved to 4ff00000..4fffffff
> 	PCI: Cannot allocate resource region 2 of PCI bridge 1
> 	PCI: bridge 1 resource 2 moved to 4fe00000..4fefffff
> 	PCI: Failed to allocate mem resource #0: 400000 @ 50000000 for 0000:01:08.0
> 	PCI: Failed to allocate mem resource #1: 800000 @ 50000000 for 0000:01:08.0
> 	PCI: Failed to allocate I/O resource #2: 10 @ 1000 for 0000:01:08.0
> 
> ****************************************************************************
> ****

I had a similar problem with a 2.4.25 Kernel. I get the following
errors:

PCI: Cannot allocate resource region 0 of device 00:1b.0
PCI: moved device 00:1b.0 resource 0 (200) to e0000000

I solved the problem by adding

hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);

at the end of the function mpc5xxx_find_bridges() in
arch/ppc/kernel/mpc5xxx_pci.c

I didnt looked in the 2.6.11.7 Kernel, but maybe this helps you!

Best regards
Heiko

^ permalink raw reply

* Re: [PATCH] powerpc: Xserve G5 thermal control fixes
From: Olof Johansson @ 2006-07-06  5:46 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: linuxppc-dev list, Paul Mackerras, Linux Kernel list
In-Reply-To: <1152162394.24632.58.camel@localhost.localdomain>

On Thu, Jul 06, 2006 at 03:06:34PM +1000, Benjamin Herrenschmidt wrote:
> The thermal control for the Xserve G5s had a few issues. For one, the
> way to program the RPM fans speeds into the FCU is different between it
> and the desktop models, which I didn't figure out until recently, and it
> was missing a control loop for the slots fan, running it too fast. Both
> of those problems were causing the machine to be much more noisy than
> necessary. This patch also changes the fixed value of the slots fan for
> desktop G5s to 40% instead of 50%. It seems to still have a pretty good
> airflow that way and is much less noisy.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> 
> Index: linux-irq-work/drivers/macintosh/therm_pm72.c
> ===================================================================
> --- linux-irq-work.orig/drivers/macintosh/therm_pm72.c	2006-07-05 14:46:11.000000000 +1000
> +++ linux-irq-work/drivers/macintosh/therm_pm72.c	2006-07-06 14:42:31.000000000 +1000
> @@ -95,6 +95,14 @@
>   *	- Use min/max macros here or there
>   *	- Latest darwin updated U3H min fan speed to 20% PWM
>   *
> + *  July. 06, 2006 : 1.3
> + *	- Fix setting of RPM fans on Xserve G5 (they were going too fast)
> + *      - Add missing slots fan control loop for Xserve G5
> + *	- Lower fixed slots fan speed from 50% to 40% on desktop G5s. We
> + *        still can't properly implement the control loop for these, so let's
> + *        reduce the noise a little bit, it appears that 40% still gives us
> + *        a pretty good air flow
> + *

Doesn't it make more sense to keep this in the GIT log instead of in
the file? (I seem to remember Freescale getting similar comments on some
posted code just a few days ago :-)

Keeping version numbers for in-tree-only drivers isn't all that useful
either.


-Olof

^ permalink raw reply

* Re: [PATCH] powerpc: Xserve G5 thermal control fixes
From: Segher Boessenkool @ 2006-07-06  5:37 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: linuxppc-dev list, Paul Mackerras, Linux Kernel list
In-Reply-To: <1152162394.24632.58.camel@localhost.localdomain>

> This patch also changes the fixed value of the slots fan for
> desktop G5s to 40% instead of 50%. It seems to still have a pretty  
> good
> airflow that way and is much less noisy.

Is this save when people have one of the ridiculously expensive
(and hot) video cards installed?  And perhaps even a few other
cards, too?


Segher

^ permalink raw reply

* [PATCH] powerpc: Add cpufreq support for Xserve G5
From: Benjamin Herrenschmidt @ 2006-07-06  5:09 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev list, Linux Kernel list

The Xserve G5 are capable of frequency switching like other desktop G5s.
This enables it. It also fix a Kconfig issue which prevented from
building the G5 cpufreq support if CONFIG_PMAC_SMU was not set (the
first version of that driver only worked with SMU based macs, but this
isn't the case anymore).

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

Index: linux-irq-work/arch/powerpc/Kconfig
===================================================================
--- linux-irq-work.orig/arch/powerpc/Kconfig	2006-07-01 13:51:11.000000000 +1000
+++ linux-irq-work/arch/powerpc/Kconfig	2006-07-06 12:16:11.000000000 +1000
@@ -504,7 +504,7 @@
 
 config CPU_FREQ_PMAC64
 	bool "Support for some Apple G5s"
-	depends on CPU_FREQ && PMAC_SMU && PPC64
+	depends on CPU_FREQ && PPC64
 	select CPU_FREQ_TABLE
 	help
 	  This adds support for frequency switching on Apple iMac G5,
Index: linux-irq-work/arch/powerpc/platforms/powermac/cpufreq_64.c
===================================================================
--- linux-irq-work.orig/arch/powerpc/platforms/powermac/cpufreq_64.c	2006-07-01 13:51:11.000000000 +1000
+++ linux-irq-work/arch/powerpc/platforms/powermac/cpufreq_64.c	2006-07-06 14:58:31.000000000 +1000
@@ -10,6 +10,8 @@
  * that is iMac G5 and latest single CPU desktop.
  */
 
+#undef DEBUG
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -30,13 +32,7 @@
 #include <asm/smu.h>
 #include <asm/pmac_pfunc.h>
 
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(fmt...) printk(fmt)
-#else
-#define DBG(fmt...)
-#endif
+#define DBG(fmt...) pr_debug(fmt)
 
 /* see 970FX user manual */
 
@@ -82,8 +78,6 @@
 /* Power mode data is an array of the 32 bits PCR values to use for
  * the various frequencies, retrieved from the device-tree
  */
-static u32 *g5_pmode_data;
-static int g5_pmode_max;
 static int g5_pmode_cur;
 
 static void (*g5_switch_volt)(int speed_mode);
@@ -93,6 +87,11 @@
 static DEFINE_MUTEX(g5_switch_mutex);
 
 
+#ifdef CONFIG_PPC_SMU
+
+static u32 *g5_pmode_data;
+static int g5_pmode_max;
+
 static struct smu_sdbp_fvt *g5_fvt_table;	/* table of op. points */
 static int g5_fvt_count;			/* number of op. points */
 static int g5_fvt_cur;				/* current op. point */
@@ -210,6 +209,16 @@
 }
 
 /*
+ * Fake voltage switching for platforms with missing support
+ */
+
+static void g5_dummy_switch_volt(int speed_mode)
+{
+}
+
+#endif /* CONFIG_PPC_SMU */
+
+/*
  * Platform function based voltage switching for PowerMac7,2 & 7,3
  */
 
@@ -248,6 +257,9 @@
 	struct pmf_args args;
 	u32 done = 0;
 	unsigned long timeout;
+	int rc;
+
+	DBG("g5_pfunc_switch_freq(%d)\n", speed_mode);
 
 	/* If frequency is going up, first ramp up the voltage */
 	if (speed_mode < g5_pmode_cur)
@@ -255,9 +267,12 @@
 
 	/* Do it */
 	if (speed_mode == CPUFREQ_HIGH)
-		pmf_call_one(pfunc_cpu_setfreq_high, NULL);
+		rc = pmf_call_one(pfunc_cpu_setfreq_high, NULL);
 	else
-		pmf_call_one(pfunc_cpu_setfreq_low, NULL);
+		rc = pmf_call_one(pfunc_cpu_setfreq_low, NULL);
+
+	if (rc)
+		printk(KERN_WARNING "cpufreq: pfunc switch error %d\n", rc);
 
 	/* It's an irq GPIO so we should be able to just block here,
 	 * I'll do that later after I've properly tested the IRQ code for
@@ -296,13 +311,6 @@
 	return val ? CPUFREQ_HIGH : CPUFREQ_LOW;
 }
 
-/*
- * Fake voltage switching for platforms with missing support
- */
-
-static void g5_dummy_switch_volt(int speed_mode)
-{
-}
 
 /*
  * Common interface to the cpufreq core
@@ -375,6 +383,8 @@
 };
 
 
+#ifdef CONFIG_PPC_SMU
+
 static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
 {
 	struct device_node *cpunode;
@@ -525,6 +535,9 @@
 	return rc;
 }
 
+#endif /* CONFIG_PPC_SMU */
+
+
 static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
 {
 	struct device_node *cpuid = NULL, *hwclock = NULL, *cpunode = NULL;
@@ -533,6 +546,9 @@
 	u64 max_freq, min_freq, ih, il;
 	int has_volt = 1, rc = 0;
 
+	DBG("cpufreq: Initializing for PowerMac7,2, PowerMac7,3 and"
+	    " RackMac3,1...\n");
+
 	/* Get first CPU node */
 	for (cpunode = NULL;
 	     (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
@@ -636,6 +652,15 @@
 	 */
 	ih = *((u32 *)(eeprom + 0x10));
 	il = *((u32 *)(eeprom + 0x20));
+
+	/* Check for machines with no useful settings */
+	if (il == ih) {
+		printk(KERN_WARNING "cpufreq: No low frequency mode available"
+		       " on this model !\n");
+		rc = -ENODEV;
+		goto bail;
+	}
+
 	min_freq = 0;
 	if (ih != 0 && il != 0)
 		min_freq = (max_freq * il) / ih;
@@ -643,7 +668,7 @@
 	/* Sanity check */
 	if (min_freq >= max_freq || min_freq < 1000) {
 		printk(KERN_ERR "cpufreq: Can't calculate low frequency !\n");
-		rc = -ENODEV;
+		rc = -ENXIO;
 		goto bail;
 	}
 	g5_cpu_freqs[0].frequency = max_freq;
@@ -690,16 +715,10 @@
 	return rc;
 }
 
-static int __init g5_rm31_cpufreq_init(struct device_node *cpus)
-{
-	/* NYI */
-	return 0;
-}
-
 static int __init g5_cpufreq_init(void)
 {
 	struct device_node *cpus;
-	int rc;
+	int rc = 0;
 
 	cpus = of_find_node_by_path("/cpus");
 	if (cpus == NULL) {
@@ -708,12 +727,13 @@
 	}
 
 	if (machine_is_compatible("PowerMac7,2") ||
-	    machine_is_compatible("PowerMac7,3"))
+	    machine_is_compatible("PowerMac7,3") ||
+	    machine_is_compatible("RackMac3,1"))
 		rc = g5_pm72_cpufreq_init(cpus);
-	else if (machine_is_compatible("RackMac3,1"))
-		rc = g5_rm31_cpufreq_init(cpus);
+#ifdef CONFIG_PPC_SMU
 	else
 		rc = g5_neo2_cpufreq_init(cpus);
+#endif /* CONFIG_PPC_SMU */
 
 	of_node_put(cpus);
 	return rc;

^ permalink raw reply

* [PATCH] powerpc: Xserve G5 thermal control fixes
From: Benjamin Herrenschmidt @ 2006-07-06  5:06 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev list, Linux Kernel list

The thermal control for the Xserve G5s had a few issues. For one, the
way to program the RPM fans speeds into the FCU is different between it
and the desktop models, which I didn't figure out until recently, and it
was missing a control loop for the slots fan, running it too fast. Both
of those problems were causing the machine to be much more noisy than
necessary. This patch also changes the fixed value of the slots fan for
desktop G5s to 40% instead of 50%. It seems to still have a pretty good
airflow that way and is much less noisy.

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

Index: linux-irq-work/drivers/macintosh/therm_pm72.c
===================================================================
--- linux-irq-work.orig/drivers/macintosh/therm_pm72.c	2006-07-05 14:46:11.000000000 +1000
+++ linux-irq-work/drivers/macintosh/therm_pm72.c	2006-07-06 14:42:31.000000000 +1000
@@ -95,6 +95,14 @@
  *	- Use min/max macros here or there
  *	- Latest darwin updated U3H min fan speed to 20% PWM
  *
+ *  July. 06, 2006 : 1.3
+ *	- Fix setting of RPM fans on Xserve G5 (they were going too fast)
+ *      - Add missing slots fan control loop for Xserve G5
+ *	- Lower fixed slots fan speed from 50% to 40% on desktop G5s. We
+ *        still can't properly implement the control loop for these, so let's
+ *        reduce the noise a little bit, it appears that 40% still gives us
+ *        a pretty good air flow
+ *
  */
 
 #include <linux/types.h>
@@ -121,7 +129,7 @@
 
 #include "therm_pm72.h"
 
-#define VERSION "1.2b2"
+#define VERSION "1.3"
 
 #undef DEBUG
 
@@ -146,6 +154,7 @@
 static struct backside_pid_state	backside_state;
 static struct drives_pid_state		drives_state;
 static struct dimm_pid_state		dimms_state;
+static struct slots_pid_state		slots_state;
 static int				state;
 static int				cpu_count;
 static int				cpu_pid_type;
@@ -154,7 +163,7 @@
 static int				critical_state;
 static int				rackmac;
 static s32				dimm_output_clamp;
-
+static int 				fcu_rpm_shift;
 static DECLARE_MUTEX(driver_lock);
 
 /*
@@ -495,13 +504,20 @@
 	rc = fan_write_reg(0x2e, &buf, 1);
 	if (rc < 0)
 		return -EIO;
+	rc = fan_read_reg(0, &buf, 1);
+	if (rc < 0)
+		return -EIO;
+	fcu_rpm_shift = (buf == 1) ? 2 : 3;
+	printk(KERN_DEBUG "FCU Initialized, RPM fan shift is %d\n",
+	       fcu_rpm_shift);
+
 	return 0;
 }
 
 static int set_rpm_fan(int fan_index, int rpm)
 {
 	unsigned char buf[2];
-	int rc, id;
+	int rc, id, min, max;
 
 	if (fcu_fans[fan_index].type != FCU_FAN_RPM)
 		return -EINVAL;
@@ -509,12 +525,15 @@
 	if (id == FCU_FAN_ABSENT_ID)
 		return -EINVAL;
 
-	if (rpm < 300)
-		rpm = 300;
-	else if (rpm > 8191)
-		rpm = 8191;
-	buf[0] = rpm >> 5;
-	buf[1] = rpm << 3;
+	min = 2400 >> fcu_rpm_shift;
+	max = 56000 >> fcu_rpm_shift;
+
+	if (rpm < min)
+		rpm = min;
+	else if (rpm > max)
+		rpm = max;
+	buf[0] = rpm >> (8 - fcu_rpm_shift);
+	buf[1] = rpm << fcu_rpm_shift;
 	rc = fan_write_reg(0x10 + (id * 2), buf, 2);
 	if (rc < 0)
 		return -EIO;
@@ -551,7 +570,7 @@
 	if (rc != 2)
 		return -EIO;
 
-	return (buf[0] << 5) | buf[1] >> 3;
+	return (buf[0] << (8 - fcu_rpm_shift)) | buf[1] >> fcu_rpm_shift;
 }
 
 static int set_pwm_fan(int fan_index, int pwm)
@@ -715,6 +734,9 @@
 BUILD_SHOW_FUNC_FIX(drives_temperature, drives_state.last_temp)
 BUILD_SHOW_FUNC_INT(drives_fan_rpm, drives_state.rpm)
 
+BUILD_SHOW_FUNC_FIX(slots_temperature, slots_state.last_temp)
+BUILD_SHOW_FUNC_INT(slots_fan_pwm, slots_state.pwm)
+
 BUILD_SHOW_FUNC_FIX(dimms_temperature, dimms_state.last_temp)
 
 static DEVICE_ATTR(cpu0_temperature,S_IRUGO,show_cpu0_temperature,NULL);
@@ -735,6 +757,9 @@
 static DEVICE_ATTR(drives_temperature,S_IRUGO,show_drives_temperature,NULL);
 static DEVICE_ATTR(drives_fan_rpm,S_IRUGO,show_drives_fan_rpm,NULL);
 
+static DEVICE_ATTR(slots_temperature,S_IRUGO,show_slots_temperature,NULL);
+static DEVICE_ATTR(slots_fan_pwm,S_IRUGO,show_slots_fan_pwm,NULL);
+
 static DEVICE_ATTR(dimms_temperature,S_IRUGO,show_dimms_temperature,NULL);
 
 /*
@@ -1076,6 +1101,9 @@
 	fan_min = dimm_output_clamp;
 	fan_min = max(fan_min, (int)state->mpu.rminn_intake_fan);
 
+	DBG(" CPU min mpu = %d, min dimm = %d\n",
+	    state->mpu.rminn_intake_fan, dimm_output_clamp);
+
 	state->rpm = max(state->rpm, (int)fan_min);
 	state->rpm = min(state->rpm, (int)state->mpu.rmaxn_intake_fan);
 	state->intake_rpm = state->rpm;
@@ -1374,7 +1402,8 @@
 	DBG("  current rpm: %d\n", state->rpm);
 
 	/* Get some sensor readings */
-	temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor, DS1775_TEMP)) << 8;
+	temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor,
+						    DS1775_TEMP)) << 8;
 	state->last_temp = temp;
 	DBG("  temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp),
 	    FIX32TOPRINT(DRIVES_PID_INPUT_TARGET));
@@ -1575,7 +1604,7 @@
 }
 
 /*
- * Dispose of the state data for the drives control loop
+ * Dispose of the state data for the DIMM control loop
  */
 static void dispose_dimms_state(struct dimm_pid_state *state)
 {
@@ -1588,6 +1617,127 @@
 	state->monitor = NULL;
 }
 
+/*
+ * Slots fan control loop
+ */
+static void do_monitor_slots(struct slots_pid_state *state)
+{
+	s32 temp, integral, derivative;
+	s64 integ_p, deriv_p, prop_p, sum;
+	int i, rc;
+
+	if (--state->ticks != 0)
+		return;
+	state->ticks = SLOTS_PID_INTERVAL;
+
+	DBG("slots:\n");
+
+	/* Check fan status */
+	rc = get_pwm_fan(SLOTS_FAN_PWM_INDEX);
+	if (rc < 0) {
+		printk(KERN_WARNING "Error %d reading slots fan !\n", rc);
+		/* XXX What do we do now ? */
+	} else
+		state->pwm = rc;
+	DBG("  current pwm: %d\n", state->pwm);
+
+	/* Get some sensor readings */
+	temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor,
+						    DS1775_TEMP)) << 8;
+	state->last_temp = temp;
+	DBG("  temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp),
+	    FIX32TOPRINT(SLOTS_PID_INPUT_TARGET));
+
+	/* Store temperature and error in history array */
+	state->cur_sample = (state->cur_sample + 1) % SLOTS_PID_HISTORY_SIZE;
+	state->sample_history[state->cur_sample] = temp;
+	state->error_history[state->cur_sample] = temp - SLOTS_PID_INPUT_TARGET;
+
+	/* If first loop, fill the history table */
+	if (state->first) {
+		for (i = 0; i < (SLOTS_PID_HISTORY_SIZE - 1); i++) {
+			state->cur_sample = (state->cur_sample + 1) %
+				SLOTS_PID_HISTORY_SIZE;
+			state->sample_history[state->cur_sample] = temp;
+			state->error_history[state->cur_sample] =
+				temp - SLOTS_PID_INPUT_TARGET;
+		}
+		state->first = 0;
+	}
+
+	/* Calculate the integral term */
+	sum = 0;
+	integral = 0;
+	for (i = 0; i < SLOTS_PID_HISTORY_SIZE; i++)
+		integral += state->error_history[i];
+	integral *= SLOTS_PID_INTERVAL;
+	DBG("  integral: %08x\n", integral);
+	integ_p = ((s64)SLOTS_PID_G_r) * (s64)integral;
+	DBG("   integ_p: %d\n", (int)(integ_p >> 36));
+	sum += integ_p;
+
+	/* Calculate the derivative term */
+	derivative = state->error_history[state->cur_sample] -
+		state->error_history[(state->cur_sample + SLOTS_PID_HISTORY_SIZE - 1)
+				    % SLOTS_PID_HISTORY_SIZE];
+	derivative /= SLOTS_PID_INTERVAL;
+	deriv_p = ((s64)SLOTS_PID_G_d) * (s64)derivative;
+	DBG("   deriv_p: %d\n", (int)(deriv_p >> 36));
+	sum += deriv_p;
+
+	/* Calculate the proportional term */
+	prop_p = ((s64)SLOTS_PID_G_p) * (s64)(state->error_history[state->cur_sample]);
+	DBG("   prop_p: %d\n", (int)(prop_p >> 36));
+	sum += prop_p;
+
+	/* Scale sum */
+	sum >>= 36;
+
+	DBG("   sum: %d\n", (int)sum);
+	state->pwm = (s32)sum;
+
+	state->pwm = max(state->pwm, SLOTS_PID_OUTPUT_MIN);
+	state->pwm = min(state->pwm, SLOTS_PID_OUTPUT_MAX);
+
+	DBG("** DRIVES PWM: %d\n", (int)state->pwm);
+	set_pwm_fan(SLOTS_FAN_PWM_INDEX, state->pwm);
+}
+
+/*
+ * Initialize the state structure for the slots bay fan control loop
+ */
+static int init_slots_state(struct slots_pid_state *state)
+{
+	state->ticks = 1;
+	state->first = 1;
+	state->pwm = 50;
+
+	state->monitor = attach_i2c_chip(XSERVE_SLOTS_LM75, "slots_temp");
+	if (state->monitor == NULL)
+		return -ENODEV;
+
+	device_create_file(&of_dev->dev, &dev_attr_slots_temperature);
+	device_create_file(&of_dev->dev, &dev_attr_slots_fan_pwm);
+
+	return 0;
+}
+
+/*
+ * Dispose of the state data for the slots control loop
+ */
+static void dispose_slots_state(struct slots_pid_state *state)
+{
+	if (state->monitor == NULL)
+		return;
+
+	device_remove_file(&of_dev->dev, &dev_attr_slots_temperature);
+	device_remove_file(&of_dev->dev, &dev_attr_slots_fan_pwm);
+
+	detach_i2c_chip(state->monitor);
+	state->monitor = NULL;
+}
+
+
 static int call_critical_overtemp(void)
 {
 	char *argv[] = { critical_overtemp_path, NULL };
@@ -1617,8 +1767,9 @@
 		goto out;
 	}
 
-	/* Set the PCI fan once for now */
-	set_pwm_fan(SLOTS_FAN_PWM_INDEX, SLOTS_FAN_DEFAULT_PWM);
+	/* Set the PCI fan once for now on non-RackMac */
+	if (!rackmac)
+		set_pwm_fan(SLOTS_FAN_PWM_INDEX, SLOTS_FAN_DEFAULT_PWM);
 
 	/* Initialize ADCs */
 	initialize_adc(&cpu_state[0]);
@@ -1654,7 +1805,9 @@
 		}
 		/* Then, the rest */
 		do_monitor_backside(&backside_state);
-		if (!rackmac)
+		if (rackmac)
+			do_monitor_slots(&slots_state);
+		else
 			do_monitor_drives(&drives_state);
 		up(&driver_lock);
 
@@ -1696,6 +1849,7 @@
 	dispose_cpu_state(&cpu_state[1]);
 	dispose_backside_state(&backside_state);
 	dispose_drives_state(&drives_state);
+	dispose_slots_state(&slots_state);
 	dispose_dimms_state(&dimms_state);
 }
 
@@ -1745,6 +1899,8 @@
 		goto fail;
 	if (rackmac && init_dimms_state(&dimms_state))
 		goto fail;
+	if (rackmac && init_slots_state(&slots_state))
+		goto fail;
 	if (!rackmac && init_drives_state(&drives_state))
 		goto fail;
 
Index: linux-irq-work/drivers/macintosh/therm_pm72.h
===================================================================
--- linux-irq-work.orig/drivers/macintosh/therm_pm72.h	2006-07-01 13:51:20.000000000 +1000
+++ linux-irq-work/drivers/macintosh/therm_pm72.h	2006-07-06 14:03:16.000000000 +1000
@@ -105,6 +105,7 @@
 #define DRIVES_DALLAS_ID	0x94
 #define BACKSIDE_MAX_ID		0x98
 #define XSERVE_DIMMS_LM87	0x25a
+#define XSERVE_SLOTS_LM75	0x290
 
 /*
  * Some MAX6690, DS1775, LM87 register definitions
@@ -198,7 +199,7 @@
 
 #define SLOTS_FAN_PWM_DEFAULT_ID	2
 #define SLOTS_FAN_PWM_INDEX		2
-#define	SLOTS_FAN_DEFAULT_PWM		50 /* Do better here ! */
+#define	SLOTS_FAN_DEFAULT_PWM		40 /* Do better here ! */
 
 
 /*
@@ -206,7 +207,7 @@
  */
 #define DIMM_PID_G_d			0
 #define DIMM_PID_G_p			0
-#define DIMM_PID_G_r			0x6553600
+#define DIMM_PID_G_r			0x06553600
 #define DIMM_PID_INPUT_TARGET		3276800
 #define DIMM_PID_INTERVAL    		1
 #define DIMM_PID_OUTPUT_MAX		14000
@@ -226,6 +227,31 @@
 };
 
 
+/*
+ * PID factors for the Xserve Slots control loop
+ */
+#define SLOTS_PID_G_d			0
+#define SLOTS_PID_G_p			0
+#define SLOTS_PID_G_r			0x00100000
+#define SLOTS_PID_INPUT_TARGET		3200000
+#define SLOTS_PID_INTERVAL    		1
+#define SLOTS_PID_OUTPUT_MAX		100
+#define SLOTS_PID_OUTPUT_MIN		20
+#define SLOTS_PID_HISTORY_SIZE		20
+
+struct slots_pid_state
+{
+	int			ticks;
+	struct i2c_client *	monitor;
+	s32	       		sample_history[SLOTS_PID_HISTORY_SIZE];
+	s32			error_history[SLOTS_PID_HISTORY_SIZE];
+	int			cur_sample;
+	s32			last_temp;
+	int			first;
+	int			pwm;
+};
+
+
 
 /* Desktops */
 

^ permalink raw reply

* Re: [PATCH] Fix snd-aoa irq conversion
From: Benjamin Herrenschmidt @ 2006-07-05 23:16 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: linuxppc-dev
In-Reply-To: <jeirmbn76v.fsf@sykes.suse.de>

On Wed, 2006-07-05 at 22:11 +0200, Andreas Schwab wrote:
> Use proper irq mapping interface for snd-aoa-i2sbus.
> 
> Signed-off-by: Andreas Schwab <schwab@suse.de>

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

One could argue that the "proper" fix is to update macio_asic.c to
register the sub-nodes i2s-X as individual devices. That would also
allow to move the various resource workarounds there along with others
and simplify the code in snd-aoa.

Ben.

^ permalink raw reply

* problem with kernel debug using BDI2000
From: hb fei @ 2006-07-05 20:11 UTC (permalink / raw)
  To: linuxppc-embedded

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

Hi there,

  I met some problems when I tried to debug the 2.5.16 kernel with BDI2000
for a customerized MPC8xx.
I listed my two trials, can any one tell me what is wrong with my approachs,


[Try 1] =============================================>

(1) Build the kernel image, the map file -- System.map file

.....

c0000000 T _start

c0000000 T __start

c0000000 T _stext

c0000018 t turn_on_mmu

c0000100 t Reset

.....

(2) Copy the vmlinux into /tftpboot for load the iamge

(3) I mapped the logic address 0xc0000000 into physical address 0x00100000
in target

by loading the file through BDI telnet console, the telnet screen shows

BDI>load 0x40100000 vmlinux elf

Loading vmlinux , please wait ....

- File offset 0x00010000 to address 0x00100000 size 1728646

Loading program file passed



(4) Start the GDB command, and single step from address 0x00100000.

I tried two version of ppc gdb, both have the same result. The location of
one of

the gdb (through DENX) is,

$ which ppc_8xx-gdb

/opt/eldk/usr/bin/ppc_8xx-gdb



(5) And start the gdb through the following command,

$ ppc_8xx-gdb vmlinux (under kernel top directory)

(gdb) target remote 10.199.5.234:2001

Remote debugging using 10.199.5.234:2001

(gdb) si

0x0010000c in ?? ()

(gdb)

0x00100010 in ?? ()

(gdb)

0x00100014 in ?? ()

....

Things go well till I reach the

(gdb)

0x00100030 in ?? ()

(gdb)

Program received signal SIGSTOP, Stopped (signal).

0x00100030 in ?? ()

(gdb)

Program received signal SIGSTOP, Stopped (signal).

0x00100030 in ?? ()

(gdb)



If I check the code carefully in /arch/ppc/kernel_8xx.S, 0x00100030 address

matches the rfi comamnd in

turn_on_mmu:

mfmsr r0

ori r0,r0,MSR_DR|MSR_IR

mtspr SPRN_SRR1,r0

lis r0,start_here@h

ori r0,r0,start_here@l

mtspr SPRN_SRR0,r0

SYNC

rfi /* enables MMU */



(6) I check the BDI configuration (8xx.cfg) file, seems I had enabled the
MMI



[TARGET]

CPUCLOCK 32000000 ;the CPU clock rate after processing the init list

BDIMODE AGENT ;the BDI working mode (LOADONLY | AGENT)

BREAKMODE SOFT ;SOFT or HARD, HARD uses PPC hardware breakpoints

;STEPMODE HWBP ;TRACE or HWBP, HWPB uses one or two hardware breakpoints

;STARTUP STOP 5000 ;let the monitor initialize the system

;DCACHE FLUSH ;flush data cache, needs a workspace of 32 bytes

;WORKSPACE 0x00000040 ;workspace in target RAM for data cache flush

MMU XLAT ;translate effective to physical address

;PTBASE 0x00000f0 ;????

;REGLIST SPR ;select register to transfer to GDB

REGLIST ALL ;select register to transfer to GDB

I assume I do not need set PTBASE, since I am working on the very new
version of kernel

(2.6.15).



Question, seems to me the MMU in BDI does still map the logic address into
physical

address correctly, what did I miss here?

[Try 2 ]  ===================================================>

Exactly follow the BDI user manual,

(1) load image, BDI telnet screen shows

BDI>load 0x40100000 vmlinux elf

Loading vmlinux , please wait ....

- File offset 0x00010000 to address 0x00100000 size 1728646

Loading program file passed



(2) set hardware break point

BDI>bi 0xc0000000 0xc00fffff

Breakpoint identification is 0

(3) issue go comamnd from telnet screen

BDI>go

- TARGET: stopped

(4) Disable hardware break point

BDI> ci

(5) Start gdb from another terminal,

$ ppc_8xx-gdb vmlinux

(6) Attached target,

(gdb) target remote 10.199.5.234:2001

Remote debugging using 10.199.5.234:2001

0x00001100 in ?? ()

(7) Set software break point,

(gdb) b start_kernel

(8) let go

(gdb) c

Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.

0x00001100 in ?? ()

Seems to me the MMU still not work with BDI.

Can any one one point out what is the problem?

Thanks!

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

^ permalink raw reply

* [PATCH] Fix snd-aoa irq conversion
From: Andreas Schwab @ 2006-07-05 20:11 UTC (permalink / raw)
  To: linuxppc-dev

Use proper irq mapping interface for snd-aoa-i2sbus.

Signed-off-by: Andreas Schwab <schwab@suse.de>

---
 sound/aoa/soundbus/i2sbus/i2sbus-core.c |    9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

Index: linux-2.6.17-git24/sound/aoa/soundbus/i2sbus/i2sbus-core.c
===================================================================
--- linux-2.6.17-git24.orig/sound/aoa/soundbus/i2sbus/i2sbus-core.c	2006-07-05 20:50:07.000000000 +0200
+++ linux-2.6.17-git24/sound/aoa/soundbus/i2sbus/i2sbus-core.c	2006-07-05 22:02:47.000000000 +0200
@@ -129,9 +129,6 @@ static int i2sbus_add_dev(struct macio_d
 	if (strncmp(np->name, "i2s-", 4))
 		return 0;
 
-	if (macio_irq_count(macio) != 3)
-		return 0;
-
 	dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL);
 	if (!dev)
 		return 0;
@@ -183,10 +180,10 @@ static int i2sbus_add_dev(struct macio_d
 		snprintf(dev->rnames[i], sizeof(dev->rnames[i]), rnames[i], np->name);
 	}
 	for (i=0;i<3;i++) {
-		if (request_irq(macio_irq(macio, i), ints[i], 0,
-				dev->rnames[i], dev))
+		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] = macio_irq(macio, i);
+		dev->interrupts[i] = irq;
 	}
 
 	for (i=0;i<3;i++) {


Andreas.

-- 
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply

* append a correct "root= boot option"
From: Gabriele @ 2006-07-05 16:12 UTC (permalink / raw)
  To: linuxppc-embedded

help me

I upgrade  the linux Kernel from 2.4 to 2.6, but i don't succeed  to Configurate the mtd.

Creating 4 MTD partitions on "EVBOARD875-0":
0x00000000-0x00060000 : "u-boot"
0x00060000-0x00160000 : "kernel"
0x00160000-0x004fa000 : "cramfs"
mtd: partition "cramfs" doesn't end on an erase block -- force read-only
0x00500000-0x00806000 : "jffs2"

obtain the follw message:

"Please append a correct "root= boot option"

from what can to depend? 

thanks to all 

 Gabriele
morelli.gab@virgilio.it
2006-07-05

^ permalink raw reply

* RE: Linux 2.6.x : cpm_dpalloc alignment bug perhaps not fully resolved
From: Laurent Lagrange @ 2006-07-05 10:03 UTC (permalink / raw)
  To: 'Pantelis Antoniou'; +Cc: linuxppc-embedded
In-Reply-To: <200607051238.18237.pantelis@embeddedalley.com>



> -----Message d'origine-----
> De : Pantelis Antoniou [mailto:pantelis@embeddedalley.com]
> Envoyé : mer. 5 juillet 2006 10:38
> À : Laurent Lagrange
> Cc : 'Li Yang-r58472'; linuxppc-embedded@ozlabs.org
> Objet : Re: Linux 2.6.x : cpm_dpalloc alignment bug perhaps not fully
> resolved
>
> Should be a bug at the free. I'll take a look at it when I have a few
> spare cycles.
>
> Pantelis
>
Yes, I think so.
I'll try to get more details if I can help you.
Best regards
Laurent

^ permalink raw reply

* Re: Linux 2.6.x : cpm_dpalloc alignment bug perhaps not fully resolved
From: Pantelis Antoniou @ 2006-07-05  9:38 UTC (permalink / raw)
  To: Laurent Lagrange; +Cc: linuxppc-embedded
In-Reply-To: <000001c6a013$0f321100$5201a8c0@GEG2400>

On Wednesday 05 July 2006 12:11, Laurent Lagrange wrote:
>=20
> > -----Message d'origine-----
> > De : Li Yang-r58472 [mailto:LeoLi@freescale.com]
> > Envoy=E9 : mer. 5 juillet 2006 09:36
> > =C0 : Laurent Lagrange; pantelis@embeddedalley.com
> > >
> > > The patch, I already applied, comes directly from Pantelis
> > > and is the same code as found at
> > > http://patchwork.ozlabs.org/linuxppc/patch?id=3D3484
> >
> > Sure, it is the patch I mentioned.  Also be noted that the
> > patch only fixes rheap in arch/ppc/.  If you are using latest
> > 2.6 source, you are most probably using code under arch/powerpc/.
> > >
> I use a Linux 2.6.9 for MPC8260 and the arch/ppc/lib/rheap.c file.
> I have no arch/powerpc tree in this kernel.
>=20
> Before applying the patch, I was not able to get a right aligned area
> with cpm_dpalloc. After applying it, cpm_dpalloc seems to be right
> until I use cpm_dpfree and then cpm_dpalloc on the same area.
>=20
> Another idea ?
> Thanks
> Laurent
>=20
>=20
>=20

Should be a bug at the free. I'll take a look at it when I have a few
spare cycles.

Pantelis

^ permalink raw reply

* RE: Linux 2.6.x : cpm_dpalloc alignment bug perhaps not fully resolved
From: Laurent Lagrange @ 2006-07-05  9:11 UTC (permalink / raw)
  To: 'Li Yang-r58472', pantelis; +Cc: linuxppc-embedded
In-Reply-To: <9FCDBA58F226D911B202000BDBAD467306FFBEDC@zch01exm40.ap.freescale.net>



> -----Message d'origine-----
> De : Li Yang-r58472 [mailto:LeoLi@freescale.com]
> Envoyé : mer. 5 juillet 2006 09:36
> À : Laurent Lagrange; pantelis@embeddedalley.com
> >
> > The patch, I already applied, comes directly from Pantelis
> > and is the same code as found at
> > http://patchwork.ozlabs.org/linuxppc/patch?id=3484
>
> Sure, it is the patch I mentioned.  Also be noted that the
> patch only fixes rheap in arch/ppc/.  If you are using latest
> 2.6 source, you are most probably using code under arch/powerpc/.
> >
I use a Linux 2.6.9 for MPC8260 and the arch/ppc/lib/rheap.c file.
I have no arch/powerpc tree in this kernel.

Before applying the patch, I was not able to get a right aligned area
with cpm_dpalloc. After applying it, cpm_dpalloc seems to be right
until I use cpm_dpfree and then cpm_dpalloc on the same area.

Another idea ?
Thanks
Laurent

^ permalink raw reply

* RE: Linux 2.6.x  :  cpm_dpalloc alignment bug perhaps not fully r esolved
From: Li Yang-r58472 @ 2006-07-05  8:35 UTC (permalink / raw)
  To: Laurent Lagrange, pantelis; +Cc: linuxppc-embedded

> -----Original Message-----
> From: Laurent Lagrange [mailto:lagrange@fr.oleane.com]
> Sent: Wednesday, July 05, 2006 4:26 PM
> To: Li Yang-r58472; pantelis@embeddedalley.com
> Cc: linuxppc-embedded@ozlabs.org
> Subject: RE: Linux 2.6.x : cpm_dpalloc alignment bug perhaps not =
fully resolved
>=20
> Hi Leo,
>=20
> Thanks for the reply.
>=20
> The patch, I already applied, comes directly from Pantelis
> and is the same code as found at
> http://patchwork.ozlabs.org/linuxppc/patch?id=3D3484

Sure, it is the patch I mentioned.  Also be noted that the patch only =
fixes rheap in arch/ppc/.  If you are using latest 2.6 source, you are =
most probably using code under arch/powerpc/.
>=20
> What do you mean by the alignment patch ?
>=20
> I suspect a problem in the cpm_dpfree function,
> not in the cpm_dpalloc function.
>=20
> I'll try to give more details.
>=20
> Best regards
> Laurent
>=20
>=20
>=20
> > -----Message d'origine-----
> > De : Li Yang-r58472 [mailto:LeoLi@freescale.com]
> > Envoy=E9 : mer. 5 juillet 2006 03:32
> > =C0 : Laurent Lagrange; pantelis@embeddedalley.com
> > Cc : linuxppc-embedded@ozlabs.org
> > Objet : RE: Linux 2.6.x : cpm_dpalloc alignment bug perhaps not =
fully
> > resolved
> >
> >
> > Did you apply the alignment patch too?  AFAIK, the problem is
> > never fixed in
> > mainstream trees.
> >
> > Best Regards,
> > Leo
> >

^ permalink raw reply

* RE: Linux 2.6.x : cpm_dpalloc alignment bug perhaps not fully resolved
From: Laurent Lagrange @ 2006-07-05  8:25 UTC (permalink / raw)
  To: 'Li Yang-r58472', pantelis; +Cc: linuxppc-embedded
In-Reply-To: <9FCDBA58F226D911B202000BDBAD467306FA6F52@zch01exm40.ap.freescale.net>

Hi Leo,

Thanks for the reply.

The patch, I already applied, comes directly from Pantelis
and is the same code as found at
http://patchwork.ozlabs.org/linuxppc/patch?id=3484

What do you mean by the alignment patch ?

I suspect a problem in the cpm_dpfree function,
not in the cpm_dpalloc function.

I'll try to give more details.

Best regards
Laurent



> -----Message d'origine-----
> De : Li Yang-r58472 [mailto:LeoLi@freescale.com]
> Envoyé : mer. 5 juillet 2006 03:32
> À : Laurent Lagrange; pantelis@embeddedalley.com
> Cc : linuxppc-embedded@ozlabs.org
> Objet : RE: Linux 2.6.x : cpm_dpalloc alignment bug perhaps not fully
> resolved
>
>
> Did you apply the alignment patch too?  AFAIK, the problem is
> never fixed in
> mainstream trees.
>
> Best Regards,
> Leo
>

^ permalink raw reply

* Re: [PATCH 13/20] [powerpc, video & agp] Constify & voidify get_property()
From: Dave Jones @ 2006-07-05  5:43 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, davej
In-Reply-To: <17579.18070.211297.508029@cargo.ozlabs.ibm.com>

On Wed, Jul 05, 2006 at 02:56:54PM +1000, Paul Mackerras wrote:
 > Dave Jones writes:
 > 
 > > I assume this stuff is going in through the ppc tree?
 > 
 > Yes, I'll take care of it.  Once Linus releases -rc1 I'll start
 > pushing the for-2.6.19 patches (including these) to the master branch
 > of the powerpc.git tree.

Sounds good, thanks Paul.

		Dave

-- 
http://www.codemonkey.org.uk

^ permalink raw reply

* Re: [PATCH] powerpc: Fix loss of interrupts with MPIC (#2)
From: Benjamin Herrenschmidt @ 2006-07-05  5:36 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev list, Linus Torvalds, Linux Kernel list
In-Reply-To: <1152076021.17790.10.camel@localhost.localdomain>

And here's the right version of the patch, pls drop the other one,
sorry....

With the new interrupt rework, an interrupt "host" map() callback can be
called after the interrupt is already active (it's called again for an
already mapped interrupt to allow changing the trigger
setup, and currently this is not guarded with a test of wether the
interrupt is requested or not, I plan to change some of this logic to be
a bit less lenient against random reconfiguring of live
interrupts but just not yet). The ported MPIC driver has a bug where
when that happens, it will mask the interrupt. This changes it to
preserve the previous masking of the interrupt instead.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
Linus: It would be nice if that could still sneak into -rc1 as it causes
hangs and other bad issues on PowerMac.

Index: linux-irq-work/arch/powerpc/sysdev/mpic.c
===================================================================
--- linux-irq-work.orig/arch/powerpc/sysdev/mpic.c	2006-07-05 14:46:11.000000000 +1000
+++ linux-irq-work/arch/powerpc/sysdev/mpic.c	2006-07-05 15:34:50.000000000 +1000
@@ -405,20 +405,22 @@
 	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);
-
 	/* make sure mask gets to controller before we return to user */
 	do {
 		if (!loops--) {
 			printk(KERN_ERR "mpic_enable_irq timeout\n");
 			break;
 		}
-	} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);	
+	} 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)
@@ -426,9 +428,11 @@
 	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);
@@ -440,6 +444,7 @@
 			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)
@@ -624,9 +629,10 @@
 	struct irq_desc *desc = get_irq_desc(virq);
 	struct irq_chip *chip;
 	struct mpic *mpic = h->host_data;
-	unsigned int vecpri = MPIC_VECPRI_SENSE_LEVEL |
+	u32 v, vecpri = MPIC_VECPRI_SENSE_LEVEL |
 		MPIC_VECPRI_POLARITY_NEGATIVE;
 	int level;
+	unsigned long iflags;
 
 	pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n",
 		 virq, hw, flags);
@@ -668,11 +674,21 @@
 	}
 #endif
 
-	/* Reconfigure irq */
-	vecpri |= MPIC_VECPRI_MASK | hw | (8 << MPIC_VECPRI_PRIORITY_SHIFT);
-	mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri);
+	/* 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);
 
-	pr_debug("mpic: mapping as IRQ\n");
+	pr_debug("mpic: mapping as IRQ, vecpri = 0x%08x (was 0x%08x)\n",
+		 vecpri, v);
 
 	set_irq_chip_data(virq, mpic);
 	set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq);
@@ -904,8 +920,8 @@
 		
 		/* do senses munging */
 		if (mpic->senses && i < mpic->senses_count)
-			vecpri = mpic_flags_to_vecpri(mpic->senses[i],
-						      &level);
+			vecpri |= mpic_flags_to_vecpri(mpic->senses[i],
+						       &level);
 		else
 			vecpri |= MPIC_VECPRI_SENSE_LEVEL;
 
@@ -955,14 +971,17 @@
 
 void __init mpic_set_serial_int(struct mpic *mpic, int enable)
 {
+	unsigned long flags;
 	u32 v;
 
+	spin_lock_irqsave(&mpic_lock, flags);
 	v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1);
 	if (enable)
 		v |= MPIC_GREG_GLOBAL_CONF_1_SIE;
 	else
 		v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE;
 	mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v);
+	spin_unlock_irqrestore(&mpic_lock, flags);
 }
 
 void mpic_irq_set_priority(unsigned int irq, unsigned int pri)

^ 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