diff options
author | Li Yang <leoli@freescale.com> | 2006-08-14 23:00:11 -0700 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-08-19 17:44:29 -0400 |
commit | ce973b141dfac4a0f160c7435d65e3ea47753ce8 (patch) | |
tree | 2dfda8aa29023fca37e1f5127d2e5e6fae1c6180 /drivers | |
parent | e4c780b1ffc7d7bc27b7dc57fcf17ebb8d3006bc (diff) |
[PATCH] Freescale QE UCC gigabit ethernet driver
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>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/Kconfig | 27 | ||||
-rw-r--r-- | drivers/net/Makefile | 3 | ||||
-rw-r--r-- | drivers/net/ucc_geth.c | 4278 | ||||
-rw-r--r-- | drivers/net/ucc_geth.h | 1339 | ||||
-rw-r--r-- | drivers/net/ucc_geth_phy.c | 801 | ||||
-rw-r--r-- | drivers/net/ucc_geth_phy.h | 217 |
6 files changed, 6665 insertions, 0 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 39189903e35..ea1796e767b 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2219,6 +2219,33 @@ config GFAR_NAPI bool "NAPI Support" depends on GIANFAR +config UCC_GETH + tristate "Freescale QE UCC GETH" + depends on QUICC_ENGINE && UCC_FAST + help + This driver supports the Gigabit Ethernet mode of QE UCC. + QE can be found on MPC836x CPUs. + +config UGETH_NAPI + bool "NAPI Support" + depends on UCC_GETH + +config UGETH_MAGIC_PACKET + bool "Magic Packet detection support" + depends on UCC_GETH + +config UGETH_FILTERING + bool "Mac address filtering support" + depends on UCC_GETH + +config UGETH_TX_ON_DEMOND + bool "Transmit on Demond support" + depends on UCC_GETH + +config UGETH_HAS_GIGA + bool + depends on UCC_GETH && MPC836x + config MV643XX_ETH tristate "MV-643XX Ethernet support" depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || PPC_MULTIPLATFORM diff --git a/drivers/net/Makefile b/drivers/net/Makefile index c91e95126f7..8427bf9dec9 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -18,6 +18,9 @@ gianfar_driver-objs := gianfar.o \ gianfar_mii.o \ gianfar_sysfs.o +obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o +ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o + # # link order important here # diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c new file mode 100644 index 00000000000..47f49ef72bd --- /dev/null +++ b/drivers/net/ucc_geth.c @@ -0,0 +1,4278 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Author: Shlomi Gridish <gridish@freescale.com> + * + * Description: + * QE UCC Gigabit Ethernet Driver + * + * Changelog: + * Jul 6, 2006 Li Yang <LeoLi@freescale.com> + * - Rearrange code and style fixes + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/stddef.h> +#include <linux/interrupt.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/ethtool.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/fsl_devices.h> +#include <linux/ethtool.h> +#include <linux/platform_device.h> +#include <linux/mii.h> + +#include <asm/uaccess.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/immap_qe.h> +#include <asm/qe.h> +#include <asm/ucc.h> +#include <asm/ucc_fast.h> + +#include "ucc_geth.h" +#include "ucc_geth_phy.h" + +#undef DEBUG + +#define DRV_DESC "QE UCC Gigabit Ethernet Controller version:June 20, 2006" +#define DRV_NAME "ucc_geth" + +#define ugeth_printk(level, format, arg...) \ + printk(level format "\n", ## arg) + +#define ugeth_dbg(format, arg...) \ + ugeth_printk(KERN_DEBUG , format , ## arg) +#define ugeth_err(format, arg...) \ + ugeth_printk(KERN_ERR , format , ## arg) +#define ugeth_info(format, arg...) \ + ugeth_printk(KERN_INFO , format , ## arg) +#define ugeth_warn(format, arg...) \ + ugeth_printk(KERN_WARNING , format , ## arg) + +#ifdef UGETH_VERBOSE_DEBUG +#define ugeth_vdbg ugeth_dbg +#else +#define ugeth_vdbg(fmt, args...) do { } while (0) +#endif /* UGETH_VERBOSE_DEBUG */ + +static DEFINE_SPINLOCK(ugeth_lock); + +static ucc_geth_info_t ugeth_primary_info = { + .uf_info = { + .bd_mem_part = MEM_PART_SYSTEM, + .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES, + .max_rx_buf_length = 1536, +/* FIXME: should be changed in run time for 1G and 100M */ +#ifdef CONFIG_UGETH_HAS_GIGA + .urfs = UCC_GETH_URFS_GIGA_INIT, + .urfet = UCC_GETH_URFET_GIGA_INIT, + .urfset = UCC_GETH_URFSET_GIGA_INIT, + .utfs = UCC_GETH_UTFS_GIGA_INIT, + .utfet = UCC_GETH_UTFET_GIGA_INIT, + .utftt = UCC_GETH_UTFTT_GIGA_INIT, +#else + .urfs = UCC_GETH_URFS_INIT, + .urfet = UCC_GETH_URFET_INIT, + .urfset = UCC_GETH_URFSET_INIT, + .utfs = UCC_GETH_UTFS_INIT, + .utfet = UCC_GETH_UTFET_INIT, + .utftt = UCC_GETH_UTFTT_INIT, +#endif + .ufpt = 256, + .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET, + .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL, + .tenc = UCC_FAST_TX_ENCODING_NRZ, + .renc = UCC_FAST_RX_ENCODING_NRZ, + .tcrc = UCC_FAST_16_BIT_CRC, + .synl = UCC_FAST_SYNC_LEN_NOT_USED, + }, + .numQueuesTx = 1, + .numQueuesRx = 1, + .extendedFilteringChainPointer = ((uint32_t) NULL), + .typeorlen = 3072 /*1536 */ , + .nonBackToBackIfgPart1 = 0x40, + .nonBackToBackIfgPart2 = 0x60, + .miminumInterFrameGapEnforcement = 0x50, + .backToBackInterFrameGap = 0x60, + .mblinterval = 128, + .nortsrbytetime = 5, + .fracsiz = 1, + .strictpriorityq = 0xff, + .altBebTruncation = 0xa, + .excessDefer = 1, + .maxRetransmission = 0xf, + .collisionWindow = 0x37, + .receiveFlowControl = 1, + .maxGroupAddrInHash = 4, + .maxIndAddrInHash = 4, + .prel = 7, + .maxFrameLength = 1518, + .minFrameLength = 64, + .maxD1Length = 1520, + .maxD2Length = 1520, + .vlantype = 0x8100, + .ecamptr = ((uint32_t) NULL), + .eventRegMask = UCCE_OTHER, + .pausePeriod = 0xf000, + .interruptcoalescingmaxvalue = {1, 1, 1, 1, 1, 1, 1, 1}, + .bdRingLenTx = { + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN}, + + .bdRingLenRx = { + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN}, + + .numStationAddresses = UCC_GETH_NUM_OF_STATION_ADDRESSES_1, + .largestexternallookupkeysize = + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE, + .statisticsMode = UCC_GETH_STATISTICS_GATHERING_MODE_NONE, + .vlanOperationTagged = UCC_GETH_VLAN_OPERATION_TAGGED_NOP, + .vlanOperationNonTagged = UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP, + .rxQoSMode = UCC_GETH_QOS_MODE_DEFAULT, + .aufc = UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_NONE, + .padAndCrc = MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC, + .numThreadsTx = UCC_GETH_NUM_OF_THREADS_4, + .numThreadsRx = UCC_GETH_NUM_OF_THREADS_4, + .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, + .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, +}; + +static ucc_geth_info_t ugeth_info[8]; + +#ifdef DEBUG +static void mem_disp(u8 *addr, int size) +{ + u8 *i; + int size16Aling = (size >> 4) << 4; + int size4Aling = (size >> 2) << 2; + int notAlign = 0; + if (size % 16) + notAlign = 1; + + for (i = addr; (u32) i < (u32) addr + size16Aling; i += 16) + printk("0x%08x: %08x %08x %08x %08x\r\n", + (u32) i, + *((u32 *) (i)), + *((u32 *) (i + 4)), + *((u32 *) (i + 8)), *((u32 *) (i + 12))); + if (notAlign == 1) + printk("0x%08x: ", (u32) i); + for (; (u32) i < (u32) addr + size4Aling; i += 4) + printk("%08x ", *((u32 *) (i))); + for (; (u32) i < (u32) addr + size; i++) + printk("%02x", *((u8 *) (i))); + if (notAlign == 1) + printk("\r\n"); +} +#endif /* DEBUG */ + +#ifdef CONFIG_UGETH_FILTERING +static void enqueue(struct list_head *node, struct list_head *lh) +{ + unsigned long flags; + + spin_lock_irqsave(ugeth_lock, flags); + list_add_tail(node, lh); + spin_unlock_irqrestore(ugeth_lock, flags); +} +#endif /* CONFIG_UGETH_FILTERING */ + +static struct list_head *dequeue(struct list_head *lh) +{ + unsigned long flags; + + spin_lock_irqsave(ugeth_lock, flags); + if (!list_empty(lh)) { + struct list_head *node = lh->next; + list_del(node); + spin_unlock_irqrestore(ugeth_lock, flags); + return node; + } else { + spin_unlock_irqrestore(ugeth_lock, flags); + return NULL; + } +} + +static int get_interface_details(enet_interface_e enet_interface, + enet_speed_e *speed, + int *r10m, + int *rmm, + int *rpm, + int *tbi, int *limited_to_full_duplex) +{ + /* Analyze enet_interface according to Interface Mode + Configuration table */ + switch (enet_interface) { + case ENET_10_MII: + *speed = ENET_SPEED_10BT; + break; + case ENET_10_RMII: + *speed = ENET_SPEED_10BT; + *r10m = 1; + *rmm = 1; + break; + case ENET_10_RGMII: + *speed = ENET_SPEED_10BT; + *rpm = 1; + *r10m = 1; + *limited_to_full_duplex = 1; + break; + case ENET_100_MII: + *speed = ENET_SPEED_100BT; + break; + case ENET_100_RMII: + *speed = ENET_SPEED_100BT; + *rmm = 1; + break; + case ENET_100_RGMII: + *speed = ENET_SPEED_100BT; + *rpm = 1; + *limited_to_full_duplex = 1; + break; + case ENET_1000_GMII: + *speed = ENET_SPEED_1000BT; + *limited_to_full_duplex = 1; + break; + case ENET_1000_RGMII: + *speed = ENET_SPEED_1000BT; + *rpm = 1; + *limited_to_full_duplex = 1; + break; + case ENET_1000_TBI: + *speed = ENET_SPEED_1000BT; + *tbi = 1; + *limited_to_full_duplex = 1; + break; + case ENET_1000_RTBI: + *speed = ENET_SPEED_1000BT; + *rpm = 1; + *tbi = 1; + *limited_to_full_duplex = 1; + break; + default: + return -EINVAL; + break; + } + + return 0; +} + +static struct sk_buff *get_new_skb(ucc_geth_private_t *ugeth, u8 *bd) +{ + struct sk_buff *skb = NULL; + + skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length + + UCC_GETH_RX_DATA_BUF_ALIGNMENT); + + if (skb == NULL) + return NULL; + + /* We need the data buffer to be aligned properly. We will reserve + * as many bytes as needed to align the data properly + */ + skb_reserve(skb, + UCC_GETH_RX_DATA_BUF_ALIGNMENT - + (((unsigned)skb->data) & (UCC_GETH_RX_DATA_BUF_ALIGNMENT - + 1))); + + skb->dev = ugeth->dev; + + BD_BUFFER_SET(bd, + dma_map_single(NULL, + skb->data, + ugeth->ug_info->uf_info.max_rx_buf_length + + UCC_GETH_RX_DATA_BUF_ALIGNMENT, + DMA_FROM_DEVICE)); + + BD_STATUS_AND_LENGTH_SET(bd, + (R_E | R_I | + (BD_STATUS_AND_LENGTH(bd) & R_W))); + + return skb; +} + +static int rx_bd_buffer_set(ucc_geth_private_t *ugeth, u8 rxQ) +{ + u8 *bd; + u32 bd_status; + struct sk_buff *skb; + int i; + + bd = ugeth->p_rx_bd_ring[rxQ]; + i = 0; + + do { + bd_status = BD_STATUS_AND_LENGTH(bd); + skb = get_new_skb(ugeth, bd); + + if (!skb) /* If can not allocate data buffer, + abort. Cleanup will be elsewhere */ + return -ENOMEM; + + ugeth->rx_skbuff[rxQ][i] = skb; + + /* advance the BD pointer */ + bd += UCC_GETH_SIZE_OF_BD; + i++; + } while (!(bd_status & R_W)); + + return 0; +} + +static int fill_init_enet_entries(ucc_geth_private_t *ugeth, + volatile u32 *p_start, + u8 num_entries, + u32 thread_size, + u32 thread_alignment, + qe_risc_allocation_e risc, + int skip_page_for_first_entry) +{ + u32 init_enet_offset; + u8 i; + int snum; + + for (i = 0; i < num_entries; i++) { + if ((snum = qe_get_snum()) < 0) { + ugeth_err("fill_init_enet_entries: Can not get SNUM."); + return snum; + } + if ((i == 0) && skip_page_for_first_entry) + /* First entry of Rx does not have page */ + init_enet_offset = 0; + else { + init_enet_offset = + qe_muram_alloc(thread_size, thread_alignment); + if (IS_MURAM_ERR(init_enet_offset)) { + ugeth_err + ("fill_init_enet_entries: Can not allocate DPRAM memory."); + qe_put_snum((u8) snum); + return -ENOMEM; + } + } + *(p_start++) = + ((u8) snum << ENET_INIT_PARAM_SNUM_SHIFT) | init_enet_offset + | risc; + } + + return 0; +} + +static int return_init_enet_entries(ucc_geth_private_t *ugeth, + volatile u32 *p_start, + u8 num_entries, + qe_risc_allocation_e risc, + int skip_page_for_first_entry) +{ + u32 init_enet_offset; + u8 i; + int snum; + + for (i = 0; i < num_entries; i++) { + /* Check that this entry was actually valid -- + needed in case failed in allocations */ + if ((*p_start & ENET_INIT_PARAM_RISC_MASK) == risc) { + snum = + (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK) >> + ENET_INIT_PARAM_SNUM_SHIFT; + qe_put_snum((u8) snum); + if (!((i == 0) && skip_page_for_first_entry)) { + /* First entry of Rx does not have page */ + init_enet_offset = + (in_be32(p_start) & + ENET_INIT_PARAM_PTR_MASK); + qe_muram_free(init_enet_offset); + } + *(p_start++) = 0; /* Just for cosmetics */ + } + } + + return 0; +} + +#ifdef DEBUG +static int dump_init_enet_entries(ucc_geth_private_t *ugeth, + volatile u32 *p_start, + u8 num_entries, + u32 thread_size, + qe_risc_allocation_e risc, + int skip_page_for_first_entry) +{ + u32 init_enet_offset; + u8 i; + int snum; + + for (i = 0; i < num_entries; i++) { + /* Check that this entry was actually valid -- + needed in case failed in allocations */ + if ((*p_start & ENET_INIT_PARAM_RISC_MASK) == risc) { + snum = + (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK) >> + ENET_INIT_PARAM_SNUM_SHIFT; + qe_put_snum((u8) snum); + if (!((i == 0) && skip_page_for_first_entry)) { + /* First entry of Rx does not have page */ + init_enet_offset = + (in_be32(p_start) & + ENET_INIT_PARAM_PTR_MASK); + ugeth_info("Init enet entry %d:", i); + ugeth_info("Base address: 0x%08x", + (u32) + qe_muram_addr(init_enet_offset)); + mem_disp(qe_muram_addr(init_enet_offset), + thread_size); + } + p_start++; + } + } + + return 0; +} +#endif + +#ifdef CONFIG_UGETH_FILTERING +static enet_addr_container_t *get_enet_addr_container(void) +{ + enet_addr_container_t *enet_addr_cont; + + /* allocate memory */ + enet_addr_cont = kmalloc(sizeof(enet_addr_container_t), GFP_KERNEL); + if (!enet_addr_cont) { + ugeth_err("%s: No memory for enet_addr_container_t object.", + __FUNCTION__); + return NULL; + } + + return enet_addr_cont; +} +#endif /* CONFIG_UGETH_FILTERING */ + +static void put_enet_addr_container(enet_addr_container_t *enet_addr_cont) +{ + kfree(enet_addr_cont); +} + +#ifdef CONFIG_UGETH_FILTERING +static int hw_add_addr_in_paddr(ucc_geth_private_t *ugeth, + enet_addr_t *p_enet_addr, u8 paddr_num) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + + if (!(paddr_num < NUM_OF_PADDRS)) { + ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__); + return -EINVAL; + } + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + addressfiltering; + + /* Ethernet frames are defined in Little Endian mode, */ + /* therefore to insert the address we reverse the bytes. */ + out_be16(&p_82xx_addr_filt->paddr[paddr_num].h, + (u16) (((u16) (((u16) ((*p_enet_addr)[5])) << 8)) | + (u16) (*p_enet_addr)[4])); + out_be16(&p_82xx_addr_filt->paddr[paddr_num].m, + (u16) (((u16) (((u16) ((*p_enet_addr)[3])) << 8)) | + (u16) (*p_enet_addr)[2])); + out_be16(&p_82xx_addr_filt->paddr[paddr_num].l, + (u16) (((u16) (((u16) ((*p_enet_addr)[1])) << 8)) | + (u16) (*p_enet_addr)[0])); + + return 0; +} +#endif /* CONFIG_UGETH_FILTERING */ + +static int hw_clear_addr_in_paddr(ucc_geth_private_t *ugeth, u8 paddr_num) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + + if (!(paddr_num < NUM_OF_PADDRS)) { + ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__); + return -EINVAL; + } + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + addressfiltering; + + /* Writing address ff.ff.ff.ff.ff.ff disables address + recognition for this register */ + out_be16(&p_82xx_addr_filt->paddr[paddr_num].h, 0xffff); + out_be16(&p_82xx_addr_filt->paddr[paddr_num].m, 0xffff); + out_be16(&p_82xx_addr_filt->paddr[paddr_num].l, 0xffff); + + return 0; +} + +static void hw_add_addr_in_hash(ucc_geth_private_t *ugeth, + enet_addr_t *p_enet_addr) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + u32 cecr_subblock; + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + addressfiltering; + + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + + /* Ethernet frames are defined in Little Endian mode, + therefor to insert */ + /* the address to the hash (Big Endian mode), we reverse the bytes.*/ + out_be16(&p_82xx_addr_filt->taddr.h, + (u16) (((u16) (((u16) ((*p_enet_addr)[5])) << 8)) | + (u16) (*p_enet_addr)[4])); + out_be16(&p_82xx_addr_filt->taddr.m, + (u16) (((u16) (((u16) ((*p_enet_addr)[3])) << 8)) | + (u16) (*p_enet_addr)[2])); + out_be16(&p_82xx_addr_filt->taddr.l, + (u16) (((u16) (((u16) ((*p_enet_addr)[1])) << 8)) | + (u16) (*p_enet_addr)[0])); + + qe_issue_cmd(QE_SET_GROUP_ADDRESS, cecr_subblock, + (u8) QE_CR_PROTOCOL_ETHERNET, 0); +} + +#ifdef CONFIG_UGETH_MAGIC_PACKET +static void magic_packet_detection_enable(ucc_geth_private_t *ugeth) +{ + ucc_fast_private_t *uccf; + ucc_geth_t *ug_regs; + u32 maccfg2, uccm; + + uccf = ugeth->uccf; + ug_regs = ugeth->ug_regs; + + /* Enable interrupts for magic packet detection */ + uccm = in_be32(uccf->p_uccm); + uccm |= UCCE_MPD; + out_be32(uccf->p_uccm, uccm); + + /* Enable magic packet detection */ + maccfg2 = in_be32(&ug_regs->maccfg2); + maccfg2 |= MACCFG2_MPE; + out_be32(&ug_regs->maccfg2, maccfg2); +} + +static void magic_packet_detection_disable(ucc_geth_private_t *ugeth) +{ + ucc_fast_private_t *uccf; + ucc_geth_t *ug_regs; + u32 maccfg2, uccm; + + uccf = ugeth->uccf; + ug_regs = ugeth->ug_regs; + + /* Disable interrupts for magic packet detection */ + uccm = in_be32(uccf->p_uccm); + uccm &= ~UCCE_MPD; + out_be32(uccf->p_uccm, uccm); + + /* Disable magic packet detection */ + maccfg2 = in_be32(&ug_regs->maccfg2); + maccfg2 &= ~MACCFG2_MPE; + out_be32(&ug_regs->maccfg2, maccfg2); +} +#endif /* MAGIC_PACKET */ + +static inline int compare_addr(enet_addr_t *addr1, enet_addr_t *addr2) +{ + return memcmp(addr1, addr2, ENET_NUM_OCTETS_PER_ADDRESS); +} + +#ifdef DEBUG +static void get_statistics(ucc_geth_private_t *ugeth, + ucc_geth_tx_firmware_statistics_t * + tx_firmware_statistics, + ucc_geth_rx_firmware_statistics_t * + rx_firmware_statistics, + ucc_geth_hardware_statistics_t *hardware_statistics) +{ + ucc_fast_t *uf_regs; + ucc_geth_t *ug_regs; + ucc_geth_tx_firmware_statistics_pram_t *p_tx_fw_statistics_pram; + ucc_geth_rx_firmware_statistics_pram_t *p_rx_fw_statistics_pram; + + ug_regs = ugeth->ug_regs; + uf_regs = (ucc_fast_t *) ug_regs; + p_tx_fw_statistics_pram = ugeth->p_tx_fw_statistics_pram; + p_rx_fw_statistics_pram = ugeth->p_rx_fw_statistics_pram; + + /* Tx firmware only if user handed pointer and driver actually + gathers Tx firmware statistics */ + if (tx_firmware_statistics && p_tx_fw_statistics_pram) { + tx_firmware_statistics->sicoltx = + in_be32(&p_tx_fw_statistics_pram->sicoltx); + tx_firmware_statistics->mulcoltx = + in_be32(&p_tx_fw_statistics_pram->mulcoltx); + tx_firmware_statistics->latecoltxfr = + in_be32(&p_tx_fw_statistics_pram->latecoltxfr); + tx_firmware_statistics->frabortduecol = + in_be32(&p_tx_fw_statistics_pram->frabortduecol); + tx_firmware_statistics->frlostinmactxer = + in_be32(&p_tx_fw_statistics_pram->frlostinmactxer); + tx_firmware_statistics->carriersenseertx = + in_be32(&p_tx_fw_statistics_pram->carriersenseertx); + tx_firmware_statistics->frtxok = + in_be32(&p_tx_fw_statistics_pram->frtxok); + tx_firmware_statistics->txfrexcessivedefer = + in_be32(&p_tx_fw_statistics_pram->txfrexcessivedefer); + tx_firmware_statistics->txpkts256 = + in_be32(&p_tx_fw_statistics_pram->txpkts256); + tx_firmware_statistics->txpkts512 = + in_be32(&p_tx_fw_statistics_pram->txpkts512); + tx_firmware_statistics->txpkts1024 = + in_be32(&p_tx_fw_statistics_pram->txpkts1024); + tx_firmware_statistics->txpktsjumbo = + in_be32(&p_tx_fw_statistics_pram->txpktsjumbo); + } + + /* Rx firmware only if user handed pointer and driver actually + * gathers Rx firmware statistics */ + if (rx_firmware_statistics && p_rx_fw_statistics_pram) { + int i; + rx_firmware_statistics->frrxfcser = + in_be32(&p_rx_fw_statistics_pram->frrxfcser); + rx_firmware_statistics->fraligner = + in_be32(&p_rx_fw_statistics_pram->fraligner); + rx_firmware_statistics->inrangelenrxer = + in_be32(&p_rx_fw_statistics_pram->inrangelenrxer); + rx_firmware_statistics->outrangelenrxer = + in_be32(&p_rx_fw_statistics_pram->outrangelenrxer); + rx_firmware_statistics->frtoolong = + in_be32(&p_rx_fw_statistics_pram->frtoolong); + rx_firmware_statistics->runt = + in_be32(&p_rx_fw_statistics_pram->runt); + rx_firmware_statistics->verylongevent = + in_be32(&p_rx_fw_statistics_pram->verylongevent); + rx_firmware_statistics->symbolerror = + in_be32(&p_rx_fw_statistics_pram->symbolerror); + rx_firmware_statistics->dropbsy = + in_be32(&p_rx_fw_statistics_pram->dropbsy); + for (i = 0; i < 0x8; i++) + rx_firmware_statistics->res0[i] = + p_rx_fw_statistics_pram->res0[i]; + rx_firmware_statistics->mismatchdrop = + in_be32(&p_rx_fw_statistics_pram->mismatchdrop); + rx_firmware_statistics->underpkts = + in_be32(&p_rx_fw_statistics_pram->underpkts); + rx_firmware_statistics->pkts256 = + in_be32(&p_rx_fw_statistics_pram->pkts256); + rx_firmware_statistics->pkts512 = + in_be32(&p_rx_fw_statistics_pram->pkts512); + rx_firmware_statistics->pkts1024 = + in_be32(&p_rx_fw_statistics_pram->pkts1024); + rx_firmware_statistics->pktsjumbo = + in_be32(&p_rx_fw_statistics_pram->pktsjumbo); + rx_firmware_statistics->frlossinmacer = + in_be32(&p_rx_fw_statistics_pram->frlossinmacer); + rx_firmware_statistics->pausefr = + in_be32(&p_rx_fw_statistics_pram->pausefr); + for (i = 0; i < 0x4; i++) + rx_firmware_statistics->res1[i] = + p_rx_fw_statistics_pram->res1[i]; + rx_firmware_statistics->removevlan = + in_be32(&p_rx_fw_statistics_pram->removevlan); + rx_firmware_statistics->replacevlan = + in_be32(&p_rx_fw_statistics_pram->replacevlan); + rx_firmware_statistics->insertvlan = + in_be32(&p_rx_fw_statistics_pram->insertvlan); + } + + /* Hardware only if user handed pointer and driver actually + gathers hardware statistics */ + if (hardware_statistics && (in_be32(&uf_regs->upsmr) & UPSMR_HSE)) { + hardware_statistics->tx64 = in_be32(&ug_regs->tx64); + hardware_statistics->tx127 = in_be32(&ug_regs->tx127); + hardware_statistics->tx255 = in_be32(&ug_regs->tx255); + hardware_statistics->rx64 = in_be32(&ug_regs->rx64); + hardware_statistics->rx127 = in_be32(&ug_regs->rx127); + hardware_statistics->rx255 = in_be32(&ug_regs->rx255); + hardware_statistics->txok = in_be32(&ug_regs->txok); + hardware_statistics->txcf = in_be16(&ug_regs->txcf); + hardware_statistics->tmca = in_be32(&ug_regs->tmca); + hardware_statistics->tbca = in_be32(&ug_regs->tbca); + hardware_statistics->rxfok = in_be32(&ug_regs->rxfok); + hardware_statistics->rxbok = in_be32(&ug_regs->rxbok); + hardware_statistics->rbyt = in_be32(&ug_regs->rbyt); + hardware_statistics->rmca = in_be32(&ug_regs->rmca); + hardware_statistics->rbca = in_be32(&ug_regs->rbca); + } +} + +static void dump_bds(ucc_geth_private_t *ugeth) +{ + int i; + int length; + + for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { + if (ugeth->p_tx_bd_ring[i]) { + length = + (ugeth->ug_info->bdRingLenTx[i] * + UCC_GETH_SIZE_OF_BD); + ugeth_info("TX BDs[%d]", i); + mem_disp(ugeth->p_tx_bd_ring[i], length); + } + } + for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) { + if (ugeth->p_rx_bd_ring[i]) { + length = + (ugeth->ug_info->bdRingLenRx[i] * + UCC_GETH_SIZE_OF_BD); + ugeth_info("RX BDs[%d]", i); + mem_disp(ugeth->p_rx_bd_ring[i], length); + } + } +} + +static void dump_regs(ucc_geth_private_t *ugeth) +{ + int i; + + ugeth_info("UCC%d Geth registers:", ugeth->ug_info->uf_info.ucc_num); + ugeth_info("Base address: 0x%08x", (u32) ugeth->ug_regs); + + ugeth_info("maccfg1 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->maccfg1, + in_be32(&ugeth->ug_regs->maccfg1)); + ugeth_info("maccfg2 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->maccfg2, + in_be32(&ugeth->ug_regs->maccfg2)); + ugeth_info("ipgifg : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->ipgifg, + in_be32(&ugeth->ug_regs->ipgifg)); + ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->hafdup, + in_be32(&ugeth->ug_regs->hafdup)); + ugeth_info("miimcfg : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimcfg, + in_be32(&ugeth->ug_regs->miimng.miimcfg)); + ugeth_info("miimcom : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimcom, + in_be32(&ugeth->ug_regs->miimng.miimcom)); + ugeth_info("miimadd : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimadd, + in_be32(&ugeth->ug_regs->miimng.miimadd)); + ugeth_info("miimcon : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimcon, + in_be32(&ugeth->ug_regs->miimng.miimcon)); + ugeth_info("miimstat : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimstat, + in_be32(&ugeth->ug_regs->miimng.miimstat)); + ugeth_info("miimmind : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimind, + in_be32(&ugeth->ug_regs->miimng.miimind)); + ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->ifctl, + in_be32(&ugeth->ug_regs->ifctl)); + ugeth_info("ifstat : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->ifstat, + in_be32(&ugeth->ug_regs->ifstat)); + ugeth_info("macstnaddr1: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->macstnaddr1, + in_be32(&ugeth->ug_regs->macstnaddr1)); + ugeth_info("macstnaddr2: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->macstnaddr2, + in_be32(&ugeth->ug_regs->macstnaddr2)); + ugeth_info("uempr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->uempr, + in_be32(&ugeth->ug_regs->uempr)); + ugeth_info("utbipar : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->utbipar, + in_be32(&ugeth->ug_regs->utbipar)); + ugeth_info("uescr : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->ug_regs->uescr, + in_be16(&ugeth->ug_regs->uescr)); + ugeth_info("tx64 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tx64, + in_be32(&ugeth->ug_regs->tx64)); + ugeth_info("tx127 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tx127, + in_be32(&ugeth->ug_regs->tx127)); + ugeth_info("tx255 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tx255, + in_be32(&ugeth->ug_regs->tx255)); + ugeth_info("rx64 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rx64, + in_be32(&ugeth->ug_regs->rx64)); + ugeth_info("rx127 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rx127, + in_be32(&ugeth->ug_regs->rx127)); + ugeth_info("rx255 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rx255, + in_be32(&ugeth->ug_regs->rx255)); + ugeth_info("txok : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->txok, + in_be32(&ugeth->ug_regs->txok)); + ugeth_info("txcf : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->ug_regs->txcf, + in_be16(&ugeth->ug_regs->txcf)); + ugeth_info("tmca : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tmca, + in_be32(&ugeth->ug_regs->tmca)); + ugeth_info("tbca : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tbca, + in_be32(&ugeth->ug_regs->tbca)); + ugeth_info("rxfok : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rxfok, + in_be32(&ugeth->ug_regs->rxfok)); + ugeth_info("rxbok : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rxbok, + in_be32(&ugeth->ug_regs->rxbok)); + ugeth_info("rbyt : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rbyt, + in_be32(&ugeth->ug_regs->rbyt)); + ugeth_info("rmca : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rmca, + in_be32(&ugeth->ug_regs->rmca)); + ugeth_info("rbca : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rbca, + in_be32(&ugeth->ug_regs->rbca)); + ugeth_info("scar : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->scar, + in_be32(&ugeth->ug_regs->scar)); + ugeth_info("scam : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->scam, + in_be32(&ugeth->ug_regs->scam)); + + if (ugeth->p_thread_data_tx) { + int numThreadsTxNumerical; + switch (ugeth->ug_info->numThreadsTx) { + case UCC_GETH_NUM_OF_THREADS_1: + numThreadsTxNumerical = 1; + break; + case UCC_GETH_NUM_OF_THREADS_2: + numThreadsTxNumerical = 2; + break; + case UCC_GETH_NUM_OF_THREADS_4: + numThreadsTxNumerical = 4; + break; + case UCC_GETH_NUM_OF_THREADS_6: + numThreadsTxNumerical = 6; + break; + case UCC_GETH_NUM_OF_THREADS_8: + numThreadsTxNumerical = 8; + break; + default: + numThreadsTxNumerical = 0; + break; + } + + ugeth_info("Thread data TXs:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_thread_data_tx); + for (i = 0; i < numThreadsTxNumerical; i++) { + ugeth_info("Thread data TX[%d]:", i); + ugeth_info("Base address: 0x%08x", + (u32) & ugeth->p_thread_data_tx[i]); + mem_disp((u8 *) & ugeth->p_thread_data_tx[i], + sizeof(ucc_geth_thread_data_tx_t)); + } + } + if (ugeth->p_thread_data_rx) { + int numThreadsRxNumerical; + switch (ugeth->ug_info->numThreadsRx) { + case UCC_GETH_NUM_OF_THREADS_1: + numThreadsRxNumerical = 1; + break; + case UCC_GETH_NUM_OF_THREADS_2: + numThreadsRxNumerical = 2; + break; + case UCC_GETH_NUM_OF_THREADS_4: + numThreadsRxNumerical = 4; + break; + case UCC_GETH_NUM_OF_THREADS_6: + numThreadsRxNumerical = 6; + break; + case UCC_GETH_NUM_OF_THREADS_8: + numThreadsRxNumerical = 8; + break; + default: + numThreadsRxNumerical = 0; + break; + } + + ugeth_info("Thread data RX:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_thread_data_rx); + for (i = 0; i < numThreadsRxNumerical; i++) { + ugeth_info("Thread data RX[%d]:", i); + ugeth_info("Base address: 0x%08x", + (u32) & ugeth->p_thread_data_rx[i]); + mem_disp((u8 *) & ugeth->p_thread_data_rx[i], + sizeof(ucc_geth_thread_data_rx_t)); + } + } + if (ugeth->p_exf_glbl_param) { + ugeth_info("EXF global param:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_exf_glbl_param); + mem_disp((u8 *) ugeth->p_exf_glbl_param, + sizeof(*ugeth->p_exf_glbl_param)); + } + if (ugeth->p_tx_glbl_pram) { + ugeth_info("TX global param:"); + ugeth_info("Base address: 0x%08x", (u32) ugeth->p_tx_glbl_pram); + ugeth_info("temoder : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_tx_glbl_pram->temoder, + in_be16(&ugeth->p_tx_glbl_pram->temoder)); + ugeth_info("sqptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->sqptr, + in_be32(&ugeth->p_tx_glbl_pram->sqptr)); + ugeth_info("schedulerbasepointer: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->schedulerbasepointer, + in_be32(&ugeth->p_tx_glbl_pram-> + schedulerbasepointer)); + ugeth_info("txrmonbaseptr: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->txrmonbaseptr, + in_be32(&ugeth->p_tx_glbl_pram->txrmonbaseptr)); + ugeth_info("tstate : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->tstate, + in_be32(&ugeth->p_tx_glbl_pram->tstate)); + ugeth_info("iphoffset[0] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[0], + ugeth->p_tx_glbl_pram->iphoffset[0]); + ugeth_info("iphoffset[1] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[1], + ug |