| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1 | /* | 
| Kim Phillips | 4e19b5c | 2007-05-11 18:25:07 -0500 | [diff] [blame] | 2 | * Copyright (C) 2006-2007 Freescale Semicondutor, Inc. All rights reserved. | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3 | * | 
|  | 4 | * Author: Shlomi Gridish <gridish@freescale.com> | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 5 | *	   Li Yang <leoli@freescale.com> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 6 | * | 
|  | 7 | * Description: | 
|  | 8 | * QE UCC Gigabit Ethernet Driver | 
|  | 9 | * | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 10 | * This program is free software; you can redistribute  it and/or modify it | 
|  | 11 | * under  the terms of  the GNU General  Public License as published by the | 
|  | 12 | * Free Software Foundation;  either version 2 of the  License, or (at your | 
|  | 13 | * option) any later version. | 
|  | 14 | */ | 
|  | 15 | #include <linux/kernel.h> | 
|  | 16 | #include <linux/init.h> | 
|  | 17 | #include <linux/errno.h> | 
|  | 18 | #include <linux/slab.h> | 
|  | 19 | #include <linux/stddef.h> | 
|  | 20 | #include <linux/interrupt.h> | 
|  | 21 | #include <linux/netdevice.h> | 
|  | 22 | #include <linux/etherdevice.h> | 
|  | 23 | #include <linux/skbuff.h> | 
|  | 24 | #include <linux/spinlock.h> | 
|  | 25 | #include <linux/mm.h> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 26 | #include <linux/dma-mapping.h> | 
|  | 27 | #include <linux/fsl_devices.h> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 28 | #include <linux/mii.h> | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 29 | #include <linux/phy.h> | 
| Timur Tabi | df19b6b | 2007-01-09 12:31:38 -0600 | [diff] [blame] | 30 | #include <linux/workqueue.h> | 
| Stephen Rothwell | 55b6c8e | 2008-05-23 16:28:54 +1000 | [diff] [blame] | 31 | #include <linux/of_platform.h> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 32 |  | 
|  | 33 | #include <asm/uaccess.h> | 
|  | 34 | #include <asm/irq.h> | 
|  | 35 | #include <asm/io.h> | 
|  | 36 | #include <asm/immap_qe.h> | 
|  | 37 | #include <asm/qe.h> | 
|  | 38 | #include <asm/ucc.h> | 
|  | 39 | #include <asm/ucc_fast.h> | 
|  | 40 |  | 
|  | 41 | #include "ucc_geth.h" | 
| Andy Fleming | 1577ece | 2009-02-04 16:42:12 -0800 | [diff] [blame] | 42 | #include "fsl_pq_mdio.h" | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 43 |  | 
|  | 44 | #undef DEBUG | 
|  | 45 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 46 | #define ugeth_printk(level, format, arg...)  \ | 
|  | 47 | printk(level format "\n", ## arg) | 
|  | 48 |  | 
|  | 49 | #define ugeth_dbg(format, arg...)            \ | 
|  | 50 | ugeth_printk(KERN_DEBUG , format , ## arg) | 
|  | 51 | #define ugeth_err(format, arg...)            \ | 
|  | 52 | ugeth_printk(KERN_ERR , format , ## arg) | 
|  | 53 | #define ugeth_info(format, arg...)           \ | 
|  | 54 | ugeth_printk(KERN_INFO , format , ## arg) | 
|  | 55 | #define ugeth_warn(format, arg...)           \ | 
|  | 56 | ugeth_printk(KERN_WARNING , format , ## arg) | 
|  | 57 |  | 
|  | 58 | #ifdef UGETH_VERBOSE_DEBUG | 
|  | 59 | #define ugeth_vdbg ugeth_dbg | 
|  | 60 | #else | 
|  | 61 | #define ugeth_vdbg(fmt, args...) do { } while (0) | 
|  | 62 | #endif				/* UGETH_VERBOSE_DEBUG */ | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 63 | #define UGETH_MSG_DEFAULT	(NETIF_MSG_IFUP << 1 ) - 1 | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 64 |  | 
| Emil Medve | 88a15f2 | 2007-10-15 08:43:50 -0500 | [diff] [blame] | 65 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 66 | static DEFINE_SPINLOCK(ugeth_lock); | 
|  | 67 |  | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 68 | static struct { | 
|  | 69 | u32 msg_enable; | 
|  | 70 | } debug = { -1 }; | 
|  | 71 |  | 
|  | 72 | module_param_named(debug, debug.msg_enable, int, 0); | 
|  | 73 | MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 0xffff=all)"); | 
|  | 74 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 75 | static struct ucc_geth_info ugeth_primary_info = { | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 76 | .uf_info = { | 
|  | 77 | .bd_mem_part = MEM_PART_SYSTEM, | 
|  | 78 | .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES, | 
|  | 79 | .max_rx_buf_length = 1536, | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 80 | /* adjusted at startup if max-speed 1000 */ | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 81 | .urfs = UCC_GETH_URFS_INIT, | 
|  | 82 | .urfet = UCC_GETH_URFET_INIT, | 
|  | 83 | .urfset = UCC_GETH_URFSET_INIT, | 
|  | 84 | .utfs = UCC_GETH_UTFS_INIT, | 
|  | 85 | .utfet = UCC_GETH_UTFET_INIT, | 
|  | 86 | .utftt = UCC_GETH_UTFTT_INIT, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 87 | .ufpt = 256, | 
|  | 88 | .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET, | 
|  | 89 | .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL, | 
|  | 90 | .tenc = UCC_FAST_TX_ENCODING_NRZ, | 
|  | 91 | .renc = UCC_FAST_RX_ENCODING_NRZ, | 
|  | 92 | .tcrc = UCC_FAST_16_BIT_CRC, | 
|  | 93 | .synl = UCC_FAST_SYNC_LEN_NOT_USED, | 
|  | 94 | }, | 
|  | 95 | .numQueuesTx = 1, | 
|  | 96 | .numQueuesRx = 1, | 
|  | 97 | .extendedFilteringChainPointer = ((uint32_t) NULL), | 
|  | 98 | .typeorlen = 3072 /*1536 */ , | 
|  | 99 | .nonBackToBackIfgPart1 = 0x40, | 
|  | 100 | .nonBackToBackIfgPart2 = 0x60, | 
|  | 101 | .miminumInterFrameGapEnforcement = 0x50, | 
|  | 102 | .backToBackInterFrameGap = 0x60, | 
|  | 103 | .mblinterval = 128, | 
|  | 104 | .nortsrbytetime = 5, | 
|  | 105 | .fracsiz = 1, | 
|  | 106 | .strictpriorityq = 0xff, | 
|  | 107 | .altBebTruncation = 0xa, | 
|  | 108 | .excessDefer = 1, | 
|  | 109 | .maxRetransmission = 0xf, | 
|  | 110 | .collisionWindow = 0x37, | 
|  | 111 | .receiveFlowControl = 1, | 
| Li Yang | ac42185 | 2007-07-19 11:47:47 +0800 | [diff] [blame] | 112 | .transmitFlowControl = 1, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 113 | .maxGroupAddrInHash = 4, | 
|  | 114 | .maxIndAddrInHash = 4, | 
|  | 115 | .prel = 7, | 
|  | 116 | .maxFrameLength = 1518, | 
|  | 117 | .minFrameLength = 64, | 
|  | 118 | .maxD1Length = 1520, | 
|  | 119 | .maxD2Length = 1520, | 
|  | 120 | .vlantype = 0x8100, | 
|  | 121 | .ecamptr = ((uint32_t) NULL), | 
|  | 122 | .eventRegMask = UCCE_OTHER, | 
|  | 123 | .pausePeriod = 0xf000, | 
|  | 124 | .interruptcoalescingmaxvalue = {1, 1, 1, 1, 1, 1, 1, 1}, | 
|  | 125 | .bdRingLenTx = { | 
|  | 126 | TX_BD_RING_LEN, | 
|  | 127 | TX_BD_RING_LEN, | 
|  | 128 | TX_BD_RING_LEN, | 
|  | 129 | TX_BD_RING_LEN, | 
|  | 130 | TX_BD_RING_LEN, | 
|  | 131 | TX_BD_RING_LEN, | 
|  | 132 | TX_BD_RING_LEN, | 
|  | 133 | TX_BD_RING_LEN}, | 
|  | 134 |  | 
|  | 135 | .bdRingLenRx = { | 
|  | 136 | RX_BD_RING_LEN, | 
|  | 137 | RX_BD_RING_LEN, | 
|  | 138 | RX_BD_RING_LEN, | 
|  | 139 | RX_BD_RING_LEN, | 
|  | 140 | RX_BD_RING_LEN, | 
|  | 141 | RX_BD_RING_LEN, | 
|  | 142 | RX_BD_RING_LEN, | 
|  | 143 | RX_BD_RING_LEN}, | 
|  | 144 |  | 
|  | 145 | .numStationAddresses = UCC_GETH_NUM_OF_STATION_ADDRESSES_1, | 
|  | 146 | .largestexternallookupkeysize = | 
|  | 147 | QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE, | 
| Li Yang | ac42185 | 2007-07-19 11:47:47 +0800 | [diff] [blame] | 148 | .statisticsMode = UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE | | 
|  | 149 | UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX | | 
|  | 150 | UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 151 | .vlanOperationTagged = UCC_GETH_VLAN_OPERATION_TAGGED_NOP, | 
|  | 152 | .vlanOperationNonTagged = UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP, | 
|  | 153 | .rxQoSMode = UCC_GETH_QOS_MODE_DEFAULT, | 
|  | 154 | .aufc = UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_NONE, | 
|  | 155 | .padAndCrc = MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC, | 
| Joakim Tjernlund | ffea31e | 2008-03-06 18:48:46 +0800 | [diff] [blame] | 156 | .numThreadsTx = UCC_GETH_NUM_OF_THREADS_1, | 
|  | 157 | .numThreadsRx = UCC_GETH_NUM_OF_THREADS_1, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 158 | .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, | 
|  | 159 | .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, | 
|  | 160 | }; | 
|  | 161 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 162 | static struct ucc_geth_info ugeth_info[8]; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 163 |  | 
|  | 164 | #ifdef DEBUG | 
|  | 165 | static void mem_disp(u8 *addr, int size) | 
|  | 166 | { | 
|  | 167 | u8 *i; | 
|  | 168 | int size16Aling = (size >> 4) << 4; | 
|  | 169 | int size4Aling = (size >> 2) << 2; | 
|  | 170 | int notAlign = 0; | 
|  | 171 | if (size % 16) | 
|  | 172 | notAlign = 1; | 
|  | 173 |  | 
|  | 174 | for (i = addr; (u32) i < (u32) addr + size16Aling; i += 16) | 
|  | 175 | printk("0x%08x: %08x %08x %08x %08x\r\n", | 
|  | 176 | (u32) i, | 
|  | 177 | *((u32 *) (i)), | 
|  | 178 | *((u32 *) (i + 4)), | 
|  | 179 | *((u32 *) (i + 8)), *((u32 *) (i + 12))); | 
|  | 180 | if (notAlign == 1) | 
|  | 181 | printk("0x%08x: ", (u32) i); | 
|  | 182 | for (; (u32) i < (u32) addr + size4Aling; i += 4) | 
|  | 183 | printk("%08x ", *((u32 *) (i))); | 
|  | 184 | for (; (u32) i < (u32) addr + size; i++) | 
|  | 185 | printk("%02x", *((u8 *) (i))); | 
|  | 186 | if (notAlign == 1) | 
|  | 187 | printk("\r\n"); | 
|  | 188 | } | 
|  | 189 | #endif /* DEBUG */ | 
|  | 190 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 191 | static struct list_head *dequeue(struct list_head *lh) | 
|  | 192 | { | 
|  | 193 | unsigned long flags; | 
|  | 194 |  | 
| Scott Wood | 1083cfe | 2006-12-07 13:31:07 -0600 | [diff] [blame] | 195 | spin_lock_irqsave(&ugeth_lock, flags); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 196 | if (!list_empty(lh)) { | 
|  | 197 | struct list_head *node = lh->next; | 
|  | 198 | list_del(node); | 
| Scott Wood | 1083cfe | 2006-12-07 13:31:07 -0600 | [diff] [blame] | 199 | spin_unlock_irqrestore(&ugeth_lock, flags); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 200 | return node; | 
|  | 201 | } else { | 
| Scott Wood | 1083cfe | 2006-12-07 13:31:07 -0600 | [diff] [blame] | 202 | spin_unlock_irqrestore(&ugeth_lock, flags); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 203 | return NULL; | 
|  | 204 | } | 
|  | 205 | } | 
|  | 206 |  | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 207 | static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, | 
|  | 208 | u8 __iomem *bd) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 209 | { | 
|  | 210 | struct sk_buff *skb = NULL; | 
|  | 211 |  | 
|  | 212 | skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length + | 
|  | 213 | UCC_GETH_RX_DATA_BUF_ALIGNMENT); | 
|  | 214 |  | 
|  | 215 | if (skb == NULL) | 
|  | 216 | return NULL; | 
|  | 217 |  | 
|  | 218 | /* We need the data buffer to be aligned properly.  We will reserve | 
|  | 219 | * as many bytes as needed to align the data properly | 
|  | 220 | */ | 
|  | 221 | skb_reserve(skb, | 
|  | 222 | UCC_GETH_RX_DATA_BUF_ALIGNMENT - | 
|  | 223 | (((unsigned)skb->data) & (UCC_GETH_RX_DATA_BUF_ALIGNMENT - | 
|  | 224 | 1))); | 
|  | 225 |  | 
|  | 226 | skb->dev = ugeth->dev; | 
|  | 227 |  | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 228 | out_be32(&((struct qe_bd __iomem *)bd)->buf, | 
| Andy Fleming | 7f80202 | 2008-05-15 17:00:21 -0500 | [diff] [blame] | 229 | dma_map_single(&ugeth->dev->dev, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 230 | skb->data, | 
|  | 231 | ugeth->ug_info->uf_info.max_rx_buf_length + | 
|  | 232 | UCC_GETH_RX_DATA_BUF_ALIGNMENT, | 
|  | 233 | DMA_FROM_DEVICE)); | 
|  | 234 |  | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 235 | out_be32((u32 __iomem *)bd, | 
|  | 236 | (R_E | R_I | (in_be32((u32 __iomem*)bd) & R_W))); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 237 |  | 
|  | 238 | return skb; | 
|  | 239 | } | 
|  | 240 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 241 | static int rx_bd_buffer_set(struct ucc_geth_private *ugeth, u8 rxQ) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 242 | { | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 243 | u8 __iomem *bd; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 244 | u32 bd_status; | 
|  | 245 | struct sk_buff *skb; | 
|  | 246 | int i; | 
|  | 247 |  | 
|  | 248 | bd = ugeth->p_rx_bd_ring[rxQ]; | 
|  | 249 | i = 0; | 
|  | 250 |  | 
|  | 251 | do { | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 252 | bd_status = in_be32((u32 __iomem *)bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 253 | skb = get_new_skb(ugeth, bd); | 
|  | 254 |  | 
|  | 255 | if (!skb)	/* If can not allocate data buffer, | 
|  | 256 | abort. Cleanup will be elsewhere */ | 
|  | 257 | return -ENOMEM; | 
|  | 258 |  | 
|  | 259 | ugeth->rx_skbuff[rxQ][i] = skb; | 
|  | 260 |  | 
|  | 261 | /* advance the BD pointer */ | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 262 | bd += sizeof(struct qe_bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 263 | i++; | 
|  | 264 | } while (!(bd_status & R_W)); | 
|  | 265 |  | 
|  | 266 | return 0; | 
|  | 267 | } | 
|  | 268 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 269 | static int fill_init_enet_entries(struct ucc_geth_private *ugeth, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 270 | u32 *p_start, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 271 | u8 num_entries, | 
|  | 272 | u32 thread_size, | 
|  | 273 | u32 thread_alignment, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 274 | enum qe_risc_allocation risc, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 275 | int skip_page_for_first_entry) | 
|  | 276 | { | 
|  | 277 | u32 init_enet_offset; | 
|  | 278 | u8 i; | 
|  | 279 | int snum; | 
|  | 280 |  | 
|  | 281 | for (i = 0; i < num_entries; i++) { | 
|  | 282 | if ((snum = qe_get_snum()) < 0) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 283 | if (netif_msg_ifup(ugeth)) | 
|  | 284 | ugeth_err("fill_init_enet_entries: Can not get SNUM."); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 285 | return snum; | 
|  | 286 | } | 
|  | 287 | if ((i == 0) && skip_page_for_first_entry) | 
|  | 288 | /* First entry of Rx does not have page */ | 
|  | 289 | init_enet_offset = 0; | 
|  | 290 | else { | 
|  | 291 | init_enet_offset = | 
|  | 292 | qe_muram_alloc(thread_size, thread_alignment); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 293 | if (IS_ERR_VALUE(init_enet_offset)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 294 | if (netif_msg_ifup(ugeth)) | 
|  | 295 | ugeth_err("fill_init_enet_entries: Can not allocate DPRAM memory."); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 296 | qe_put_snum((u8) snum); | 
|  | 297 | return -ENOMEM; | 
|  | 298 | } | 
|  | 299 | } | 
|  | 300 | *(p_start++) = | 
|  | 301 | ((u8) snum << ENET_INIT_PARAM_SNUM_SHIFT) | init_enet_offset | 
|  | 302 | | risc; | 
|  | 303 | } | 
|  | 304 |  | 
|  | 305 | return 0; | 
|  | 306 | } | 
|  | 307 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 308 | static int return_init_enet_entries(struct ucc_geth_private *ugeth, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 309 | u32 *p_start, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 310 | u8 num_entries, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 311 | enum qe_risc_allocation risc, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 312 | int skip_page_for_first_entry) | 
|  | 313 | { | 
|  | 314 | u32 init_enet_offset; | 
|  | 315 | u8 i; | 
|  | 316 | int snum; | 
|  | 317 |  | 
|  | 318 | for (i = 0; i < num_entries; i++) { | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 319 | u32 val = *p_start; | 
|  | 320 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 321 | /* Check that this entry was actually valid -- | 
|  | 322 | needed in case failed in allocations */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 323 | if ((val & ENET_INIT_PARAM_RISC_MASK) == risc) { | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 324 | snum = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 325 | (u32) (val & ENET_INIT_PARAM_SNUM_MASK) >> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 326 | ENET_INIT_PARAM_SNUM_SHIFT; | 
|  | 327 | qe_put_snum((u8) snum); | 
|  | 328 | if (!((i == 0) && skip_page_for_first_entry)) { | 
|  | 329 | /* First entry of Rx does not have page */ | 
|  | 330 | init_enet_offset = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 331 | (val & ENET_INIT_PARAM_PTR_MASK); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 332 | qe_muram_free(init_enet_offset); | 
|  | 333 | } | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 334 | *p_start++ = 0; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 335 | } | 
|  | 336 | } | 
|  | 337 |  | 
|  | 338 | return 0; | 
|  | 339 | } | 
|  | 340 |  | 
|  | 341 | #ifdef DEBUG | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 342 | static int dump_init_enet_entries(struct ucc_geth_private *ugeth, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 343 | u32 __iomem *p_start, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 344 | u8 num_entries, | 
|  | 345 | u32 thread_size, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 346 | enum qe_risc_allocation risc, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 347 | int skip_page_for_first_entry) | 
|  | 348 | { | 
|  | 349 | u32 init_enet_offset; | 
|  | 350 | u8 i; | 
|  | 351 | int snum; | 
|  | 352 |  | 
|  | 353 | for (i = 0; i < num_entries; i++) { | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 354 | u32 val = in_be32(p_start); | 
|  | 355 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 356 | /* Check that this entry was actually valid -- | 
|  | 357 | needed in case failed in allocations */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 358 | if ((val & ENET_INIT_PARAM_RISC_MASK) == risc) { | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 359 | snum = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 360 | (u32) (val & ENET_INIT_PARAM_SNUM_MASK) >> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 361 | ENET_INIT_PARAM_SNUM_SHIFT; | 
|  | 362 | qe_put_snum((u8) snum); | 
|  | 363 | if (!((i == 0) && skip_page_for_first_entry)) { | 
|  | 364 | /* First entry of Rx does not have page */ | 
|  | 365 | init_enet_offset = | 
|  | 366 | (in_be32(p_start) & | 
|  | 367 | ENET_INIT_PARAM_PTR_MASK); | 
|  | 368 | ugeth_info("Init enet entry %d:", i); | 
|  | 369 | ugeth_info("Base address: 0x%08x", | 
|  | 370 | (u32) | 
|  | 371 | qe_muram_addr(init_enet_offset)); | 
|  | 372 | mem_disp(qe_muram_addr(init_enet_offset), | 
|  | 373 | thread_size); | 
|  | 374 | } | 
|  | 375 | p_start++; | 
|  | 376 | } | 
|  | 377 | } | 
|  | 378 |  | 
|  | 379 | return 0; | 
|  | 380 | } | 
|  | 381 | #endif | 
|  | 382 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 383 | static void put_enet_addr_container(struct enet_addr_container *enet_addr_cont) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 384 | { | 
|  | 385 | kfree(enet_addr_cont); | 
|  | 386 | } | 
|  | 387 |  | 
| Timur Tabi | df19b6b | 2007-01-09 12:31:38 -0600 | [diff] [blame] | 388 | static void set_mac_addr(__be16 __iomem *reg, u8 *mac) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 389 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 390 | out_be16(®[0], ((u16)mac[5] << 8) | mac[4]); | 
|  | 391 | out_be16(®[1], ((u16)mac[3] << 8) | mac[2]); | 
|  | 392 | out_be16(®[2], ((u16)mac[1] << 8) | mac[0]); | 
|  | 393 | } | 
|  | 394 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 395 | static int hw_clear_addr_in_paddr(struct ucc_geth_private *ugeth, u8 paddr_num) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 396 | { | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 397 | struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 398 |  | 
|  | 399 | if (!(paddr_num < NUM_OF_PADDRS)) { | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 400 | ugeth_warn("%s: Illagel paddr_num.", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 401 | return -EINVAL; | 
|  | 402 | } | 
|  | 403 |  | 
|  | 404 | p_82xx_addr_filt = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 405 | (struct ucc_geth_82xx_address_filtering_pram __iomem *) ugeth->p_rx_glbl_pram-> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 406 | addressfiltering; | 
|  | 407 |  | 
|  | 408 | /* Writing address ff.ff.ff.ff.ff.ff disables address | 
|  | 409 | recognition for this register */ | 
|  | 410 | out_be16(&p_82xx_addr_filt->paddr[paddr_num].h, 0xffff); | 
|  | 411 | out_be16(&p_82xx_addr_filt->paddr[paddr_num].m, 0xffff); | 
|  | 412 | out_be16(&p_82xx_addr_filt->paddr[paddr_num].l, 0xffff); | 
|  | 413 |  | 
|  | 414 | return 0; | 
|  | 415 | } | 
|  | 416 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 417 | static void hw_add_addr_in_hash(struct ucc_geth_private *ugeth, | 
|  | 418 | u8 *p_enet_addr) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 419 | { | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 420 | struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 421 | u32 cecr_subblock; | 
|  | 422 |  | 
|  | 423 | p_82xx_addr_filt = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 424 | (struct ucc_geth_82xx_address_filtering_pram __iomem *) ugeth->p_rx_glbl_pram-> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 425 | addressfiltering; | 
|  | 426 |  | 
|  | 427 | cecr_subblock = | 
|  | 428 | ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); | 
|  | 429 |  | 
|  | 430 | /* Ethernet frames are defined in Little Endian mode, | 
|  | 431 | therefor to insert */ | 
|  | 432 | /* the address to the hash (Big Endian mode), we reverse the bytes.*/ | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 433 |  | 
|  | 434 | set_mac_addr(&p_82xx_addr_filt->taddr.h, p_enet_addr); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 435 |  | 
|  | 436 | qe_issue_cmd(QE_SET_GROUP_ADDRESS, cecr_subblock, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 437 | QE_CR_PROTOCOL_ETHERNET, 0); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 438 | } | 
|  | 439 |  | 
|  | 440 | #ifdef CONFIG_UGETH_MAGIC_PACKET | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 441 | static void magic_packet_detection_enable(struct ucc_geth_private *ugeth) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 442 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 443 | struct ucc_fast_private *uccf; | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 444 | struct ucc_geth __iomem *ug_regs; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 445 |  | 
|  | 446 | uccf = ugeth->uccf; | 
|  | 447 | ug_regs = ugeth->ug_regs; | 
|  | 448 |  | 
|  | 449 | /* Enable interrupts for magic packet detection */ | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 450 | setbits32(uccf->p_uccm, UCC_GETH_UCCE_MPD); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 451 |  | 
|  | 452 | /* Enable magic packet detection */ | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 453 | setbits32(&ug_regs->maccfg2, MACCFG2_MPE); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 454 | } | 
|  | 455 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 456 | static void magic_packet_detection_disable(struct ucc_geth_private *ugeth) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 457 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 458 | struct ucc_fast_private *uccf; | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 459 | struct ucc_geth __iomem *ug_regs; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 460 |  | 
|  | 461 | uccf = ugeth->uccf; | 
|  | 462 | ug_regs = ugeth->ug_regs; | 
|  | 463 |  | 
|  | 464 | /* Disable interrupts for magic packet detection */ | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 465 | clrbits32(uccf->p_uccm, UCC_GETH_UCCE_MPD); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 466 |  | 
|  | 467 | /* Disable magic packet detection */ | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 468 | clrbits32(&ug_regs->maccfg2, MACCFG2_MPE); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 469 | } | 
|  | 470 | #endif /* MAGIC_PACKET */ | 
|  | 471 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 472 | static inline int compare_addr(u8 **addr1, u8 **addr2) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 473 | { | 
|  | 474 | return memcmp(addr1, addr2, ENET_NUM_OCTETS_PER_ADDRESS); | 
|  | 475 | } | 
|  | 476 |  | 
|  | 477 | #ifdef DEBUG | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 478 | static void get_statistics(struct ucc_geth_private *ugeth, | 
|  | 479 | struct ucc_geth_tx_firmware_statistics * | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 480 | tx_firmware_statistics, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 481 | struct ucc_geth_rx_firmware_statistics * | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 482 | rx_firmware_statistics, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 483 | struct ucc_geth_hardware_statistics *hardware_statistics) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 484 | { | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 485 | struct ucc_fast __iomem *uf_regs; | 
|  | 486 | struct ucc_geth __iomem *ug_regs; | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 487 | struct ucc_geth_tx_firmware_statistics_pram *p_tx_fw_statistics_pram; | 
|  | 488 | struct ucc_geth_rx_firmware_statistics_pram *p_rx_fw_statistics_pram; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 489 |  | 
|  | 490 | ug_regs = ugeth->ug_regs; | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 491 | uf_regs = (struct ucc_fast __iomem *) ug_regs; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 492 | p_tx_fw_statistics_pram = ugeth->p_tx_fw_statistics_pram; | 
|  | 493 | p_rx_fw_statistics_pram = ugeth->p_rx_fw_statistics_pram; | 
|  | 494 |  | 
|  | 495 | /* Tx firmware only if user handed pointer and driver actually | 
|  | 496 | gathers Tx firmware statistics */ | 
|  | 497 | if (tx_firmware_statistics && p_tx_fw_statistics_pram) { | 
|  | 498 | tx_firmware_statistics->sicoltx = | 
|  | 499 | in_be32(&p_tx_fw_statistics_pram->sicoltx); | 
|  | 500 | tx_firmware_statistics->mulcoltx = | 
|  | 501 | in_be32(&p_tx_fw_statistics_pram->mulcoltx); | 
|  | 502 | tx_firmware_statistics->latecoltxfr = | 
|  | 503 | in_be32(&p_tx_fw_statistics_pram->latecoltxfr); | 
|  | 504 | tx_firmware_statistics->frabortduecol = | 
|  | 505 | in_be32(&p_tx_fw_statistics_pram->frabortduecol); | 
|  | 506 | tx_firmware_statistics->frlostinmactxer = | 
|  | 507 | in_be32(&p_tx_fw_statistics_pram->frlostinmactxer); | 
|  | 508 | tx_firmware_statistics->carriersenseertx = | 
|  | 509 | in_be32(&p_tx_fw_statistics_pram->carriersenseertx); | 
|  | 510 | tx_firmware_statistics->frtxok = | 
|  | 511 | in_be32(&p_tx_fw_statistics_pram->frtxok); | 
|  | 512 | tx_firmware_statistics->txfrexcessivedefer = | 
|  | 513 | in_be32(&p_tx_fw_statistics_pram->txfrexcessivedefer); | 
|  | 514 | tx_firmware_statistics->txpkts256 = | 
|  | 515 | in_be32(&p_tx_fw_statistics_pram->txpkts256); | 
|  | 516 | tx_firmware_statistics->txpkts512 = | 
|  | 517 | in_be32(&p_tx_fw_statistics_pram->txpkts512); | 
|  | 518 | tx_firmware_statistics->txpkts1024 = | 
|  | 519 | in_be32(&p_tx_fw_statistics_pram->txpkts1024); | 
|  | 520 | tx_firmware_statistics->txpktsjumbo = | 
|  | 521 | in_be32(&p_tx_fw_statistics_pram->txpktsjumbo); | 
|  | 522 | } | 
|  | 523 |  | 
|  | 524 | /* Rx firmware only if user handed pointer and driver actually | 
|  | 525 | * gathers Rx firmware statistics */ | 
|  | 526 | if (rx_firmware_statistics && p_rx_fw_statistics_pram) { | 
|  | 527 | int i; | 
|  | 528 | rx_firmware_statistics->frrxfcser = | 
|  | 529 | in_be32(&p_rx_fw_statistics_pram->frrxfcser); | 
|  | 530 | rx_firmware_statistics->fraligner = | 
|  | 531 | in_be32(&p_rx_fw_statistics_pram->fraligner); | 
|  | 532 | rx_firmware_statistics->inrangelenrxer = | 
|  | 533 | in_be32(&p_rx_fw_statistics_pram->inrangelenrxer); | 
|  | 534 | rx_firmware_statistics->outrangelenrxer = | 
|  | 535 | in_be32(&p_rx_fw_statistics_pram->outrangelenrxer); | 
|  | 536 | rx_firmware_statistics->frtoolong = | 
|  | 537 | in_be32(&p_rx_fw_statistics_pram->frtoolong); | 
|  | 538 | rx_firmware_statistics->runt = | 
|  | 539 | in_be32(&p_rx_fw_statistics_pram->runt); | 
|  | 540 | rx_firmware_statistics->verylongevent = | 
|  | 541 | in_be32(&p_rx_fw_statistics_pram->verylongevent); | 
|  | 542 | rx_firmware_statistics->symbolerror = | 
|  | 543 | in_be32(&p_rx_fw_statistics_pram->symbolerror); | 
|  | 544 | rx_firmware_statistics->dropbsy = | 
|  | 545 | in_be32(&p_rx_fw_statistics_pram->dropbsy); | 
|  | 546 | for (i = 0; i < 0x8; i++) | 
|  | 547 | rx_firmware_statistics->res0[i] = | 
|  | 548 | p_rx_fw_statistics_pram->res0[i]; | 
|  | 549 | rx_firmware_statistics->mismatchdrop = | 
|  | 550 | in_be32(&p_rx_fw_statistics_pram->mismatchdrop); | 
|  | 551 | rx_firmware_statistics->underpkts = | 
|  | 552 | in_be32(&p_rx_fw_statistics_pram->underpkts); | 
|  | 553 | rx_firmware_statistics->pkts256 = | 
|  | 554 | in_be32(&p_rx_fw_statistics_pram->pkts256); | 
|  | 555 | rx_firmware_statistics->pkts512 = | 
|  | 556 | in_be32(&p_rx_fw_statistics_pram->pkts512); | 
|  | 557 | rx_firmware_statistics->pkts1024 = | 
|  | 558 | in_be32(&p_rx_fw_statistics_pram->pkts1024); | 
|  | 559 | rx_firmware_statistics->pktsjumbo = | 
|  | 560 | in_be32(&p_rx_fw_statistics_pram->pktsjumbo); | 
|  | 561 | rx_firmware_statistics->frlossinmacer = | 
|  | 562 | in_be32(&p_rx_fw_statistics_pram->frlossinmacer); | 
|  | 563 | rx_firmware_statistics->pausefr = | 
|  | 564 | in_be32(&p_rx_fw_statistics_pram->pausefr); | 
|  | 565 | for (i = 0; i < 0x4; i++) | 
|  | 566 | rx_firmware_statistics->res1[i] = | 
|  | 567 | p_rx_fw_statistics_pram->res1[i]; | 
|  | 568 | rx_firmware_statistics->removevlan = | 
|  | 569 | in_be32(&p_rx_fw_statistics_pram->removevlan); | 
|  | 570 | rx_firmware_statistics->replacevlan = | 
|  | 571 | in_be32(&p_rx_fw_statistics_pram->replacevlan); | 
|  | 572 | rx_firmware_statistics->insertvlan = | 
|  | 573 | in_be32(&p_rx_fw_statistics_pram->insertvlan); | 
|  | 574 | } | 
|  | 575 |  | 
|  | 576 | /* Hardware only if user handed pointer and driver actually | 
|  | 577 | gathers hardware statistics */ | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 578 | if (hardware_statistics && | 
|  | 579 | (in_be32(&uf_regs->upsmr) & UCC_GETH_UPSMR_HSE)) { | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 580 | hardware_statistics->tx64 = in_be32(&ug_regs->tx64); | 
|  | 581 | hardware_statistics->tx127 = in_be32(&ug_regs->tx127); | 
|  | 582 | hardware_statistics->tx255 = in_be32(&ug_regs->tx255); | 
|  | 583 | hardware_statistics->rx64 = in_be32(&ug_regs->rx64); | 
|  | 584 | hardware_statistics->rx127 = in_be32(&ug_regs->rx127); | 
|  | 585 | hardware_statistics->rx255 = in_be32(&ug_regs->rx255); | 
|  | 586 | hardware_statistics->txok = in_be32(&ug_regs->txok); | 
|  | 587 | hardware_statistics->txcf = in_be16(&ug_regs->txcf); | 
|  | 588 | hardware_statistics->tmca = in_be32(&ug_regs->tmca); | 
|  | 589 | hardware_statistics->tbca = in_be32(&ug_regs->tbca); | 
|  | 590 | hardware_statistics->rxfok = in_be32(&ug_regs->rxfok); | 
|  | 591 | hardware_statistics->rxbok = in_be32(&ug_regs->rxbok); | 
|  | 592 | hardware_statistics->rbyt = in_be32(&ug_regs->rbyt); | 
|  | 593 | hardware_statistics->rmca = in_be32(&ug_regs->rmca); | 
|  | 594 | hardware_statistics->rbca = in_be32(&ug_regs->rbca); | 
|  | 595 | } | 
|  | 596 | } | 
|  | 597 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 598 | static void dump_bds(struct ucc_geth_private *ugeth) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 599 | { | 
|  | 600 | int i; | 
|  | 601 | int length; | 
|  | 602 |  | 
|  | 603 | for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { | 
|  | 604 | if (ugeth->p_tx_bd_ring[i]) { | 
|  | 605 | length = | 
|  | 606 | (ugeth->ug_info->bdRingLenTx[i] * | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 607 | sizeof(struct qe_bd)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 608 | ugeth_info("TX BDs[%d]", i); | 
|  | 609 | mem_disp(ugeth->p_tx_bd_ring[i], length); | 
|  | 610 | } | 
|  | 611 | } | 
|  | 612 | for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) { | 
|  | 613 | if (ugeth->p_rx_bd_ring[i]) { | 
|  | 614 | length = | 
|  | 615 | (ugeth->ug_info->bdRingLenRx[i] * | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 616 | sizeof(struct qe_bd)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 617 | ugeth_info("RX BDs[%d]", i); | 
|  | 618 | mem_disp(ugeth->p_rx_bd_ring[i], length); | 
|  | 619 | } | 
|  | 620 | } | 
|  | 621 | } | 
|  | 622 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 623 | static void dump_regs(struct ucc_geth_private *ugeth) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 624 | { | 
|  | 625 | int i; | 
|  | 626 |  | 
|  | 627 | ugeth_info("UCC%d Geth registers:", ugeth->ug_info->uf_info.ucc_num); | 
|  | 628 | ugeth_info("Base address: 0x%08x", (u32) ugeth->ug_regs); | 
|  | 629 |  | 
|  | 630 | ugeth_info("maccfg1    : addr - 0x%08x, val - 0x%08x", | 
|  | 631 | (u32) & ugeth->ug_regs->maccfg1, | 
|  | 632 | in_be32(&ugeth->ug_regs->maccfg1)); | 
|  | 633 | ugeth_info("maccfg2    : addr - 0x%08x, val - 0x%08x", | 
|  | 634 | (u32) & ugeth->ug_regs->maccfg2, | 
|  | 635 | in_be32(&ugeth->ug_regs->maccfg2)); | 
|  | 636 | ugeth_info("ipgifg     : addr - 0x%08x, val - 0x%08x", | 
|  | 637 | (u32) & ugeth->ug_regs->ipgifg, | 
|  | 638 | in_be32(&ugeth->ug_regs->ipgifg)); | 
|  | 639 | ugeth_info("hafdup     : addr - 0x%08x, val - 0x%08x", | 
|  | 640 | (u32) & ugeth->ug_regs->hafdup, | 
|  | 641 | in_be32(&ugeth->ug_regs->hafdup)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 642 | ugeth_info("ifctl      : addr - 0x%08x, val - 0x%08x", | 
|  | 643 | (u32) & ugeth->ug_regs->ifctl, | 
|  | 644 | in_be32(&ugeth->ug_regs->ifctl)); | 
|  | 645 | ugeth_info("ifstat     : addr - 0x%08x, val - 0x%08x", | 
|  | 646 | (u32) & ugeth->ug_regs->ifstat, | 
|  | 647 | in_be32(&ugeth->ug_regs->ifstat)); | 
|  | 648 | ugeth_info("macstnaddr1: addr - 0x%08x, val - 0x%08x", | 
|  | 649 | (u32) & ugeth->ug_regs->macstnaddr1, | 
|  | 650 | in_be32(&ugeth->ug_regs->macstnaddr1)); | 
|  | 651 | ugeth_info("macstnaddr2: addr - 0x%08x, val - 0x%08x", | 
|  | 652 | (u32) & ugeth->ug_regs->macstnaddr2, | 
|  | 653 | in_be32(&ugeth->ug_regs->macstnaddr2)); | 
|  | 654 | ugeth_info("uempr      : addr - 0x%08x, val - 0x%08x", | 
|  | 655 | (u32) & ugeth->ug_regs->uempr, | 
|  | 656 | in_be32(&ugeth->ug_regs->uempr)); | 
|  | 657 | ugeth_info("utbipar    : addr - 0x%08x, val - 0x%08x", | 
|  | 658 | (u32) & ugeth->ug_regs->utbipar, | 
|  | 659 | in_be32(&ugeth->ug_regs->utbipar)); | 
|  | 660 | ugeth_info("uescr      : addr - 0x%08x, val - 0x%04x", | 
|  | 661 | (u32) & ugeth->ug_regs->uescr, | 
|  | 662 | in_be16(&ugeth->ug_regs->uescr)); | 
|  | 663 | ugeth_info("tx64       : addr - 0x%08x, val - 0x%08x", | 
|  | 664 | (u32) & ugeth->ug_regs->tx64, | 
|  | 665 | in_be32(&ugeth->ug_regs->tx64)); | 
|  | 666 | ugeth_info("tx127      : addr - 0x%08x, val - 0x%08x", | 
|  | 667 | (u32) & ugeth->ug_regs->tx127, | 
|  | 668 | in_be32(&ugeth->ug_regs->tx127)); | 
|  | 669 | ugeth_info("tx255      : addr - 0x%08x, val - 0x%08x", | 
|  | 670 | (u32) & ugeth->ug_regs->tx255, | 
|  | 671 | in_be32(&ugeth->ug_regs->tx255)); | 
|  | 672 | ugeth_info("rx64       : addr - 0x%08x, val - 0x%08x", | 
|  | 673 | (u32) & ugeth->ug_regs->rx64, | 
|  | 674 | in_be32(&ugeth->ug_regs->rx64)); | 
|  | 675 | ugeth_info("rx127      : addr - 0x%08x, val - 0x%08x", | 
|  | 676 | (u32) & ugeth->ug_regs->rx127, | 
|  | 677 | in_be32(&ugeth->ug_regs->rx127)); | 
|  | 678 | ugeth_info("rx255      : addr - 0x%08x, val - 0x%08x", | 
|  | 679 | (u32) & ugeth->ug_regs->rx255, | 
|  | 680 | in_be32(&ugeth->ug_regs->rx255)); | 
|  | 681 | ugeth_info("txok       : addr - 0x%08x, val - 0x%08x", | 
|  | 682 | (u32) & ugeth->ug_regs->txok, | 
|  | 683 | in_be32(&ugeth->ug_regs->txok)); | 
|  | 684 | ugeth_info("txcf       : addr - 0x%08x, val - 0x%04x", | 
|  | 685 | (u32) & ugeth->ug_regs->txcf, | 
|  | 686 | in_be16(&ugeth->ug_regs->txcf)); | 
|  | 687 | ugeth_info("tmca       : addr - 0x%08x, val - 0x%08x", | 
|  | 688 | (u32) & ugeth->ug_regs->tmca, | 
|  | 689 | in_be32(&ugeth->ug_regs->tmca)); | 
|  | 690 | ugeth_info("tbca       : addr - 0x%08x, val - 0x%08x", | 
|  | 691 | (u32) & ugeth->ug_regs->tbca, | 
|  | 692 | in_be32(&ugeth->ug_regs->tbca)); | 
|  | 693 | ugeth_info("rxfok      : addr - 0x%08x, val - 0x%08x", | 
|  | 694 | (u32) & ugeth->ug_regs->rxfok, | 
|  | 695 | in_be32(&ugeth->ug_regs->rxfok)); | 
|  | 696 | ugeth_info("rxbok      : addr - 0x%08x, val - 0x%08x", | 
|  | 697 | (u32) & ugeth->ug_regs->rxbok, | 
|  | 698 | in_be32(&ugeth->ug_regs->rxbok)); | 
|  | 699 | ugeth_info("rbyt       : addr - 0x%08x, val - 0x%08x", | 
|  | 700 | (u32) & ugeth->ug_regs->rbyt, | 
|  | 701 | in_be32(&ugeth->ug_regs->rbyt)); | 
|  | 702 | ugeth_info("rmca       : addr - 0x%08x, val - 0x%08x", | 
|  | 703 | (u32) & ugeth->ug_regs->rmca, | 
|  | 704 | in_be32(&ugeth->ug_regs->rmca)); | 
|  | 705 | ugeth_info("rbca       : addr - 0x%08x, val - 0x%08x", | 
|  | 706 | (u32) & ugeth->ug_regs->rbca, | 
|  | 707 | in_be32(&ugeth->ug_regs->rbca)); | 
|  | 708 | ugeth_info("scar       : addr - 0x%08x, val - 0x%08x", | 
|  | 709 | (u32) & ugeth->ug_regs->scar, | 
|  | 710 | in_be32(&ugeth->ug_regs->scar)); | 
|  | 711 | ugeth_info("scam       : addr - 0x%08x, val - 0x%08x", | 
|  | 712 | (u32) & ugeth->ug_regs->scam, | 
|  | 713 | in_be32(&ugeth->ug_regs->scam)); | 
|  | 714 |  | 
|  | 715 | if (ugeth->p_thread_data_tx) { | 
|  | 716 | int numThreadsTxNumerical; | 
|  | 717 | switch (ugeth->ug_info->numThreadsTx) { | 
|  | 718 | case UCC_GETH_NUM_OF_THREADS_1: | 
|  | 719 | numThreadsTxNumerical = 1; | 
|  | 720 | break; | 
|  | 721 | case UCC_GETH_NUM_OF_THREADS_2: | 
|  | 722 | numThreadsTxNumerical = 2; | 
|  | 723 | break; | 
|  | 724 | case UCC_GETH_NUM_OF_THREADS_4: | 
|  | 725 | numThreadsTxNumerical = 4; | 
|  | 726 | break; | 
|  | 727 | case UCC_GETH_NUM_OF_THREADS_6: | 
|  | 728 | numThreadsTxNumerical = 6; | 
|  | 729 | break; | 
|  | 730 | case UCC_GETH_NUM_OF_THREADS_8: | 
|  | 731 | numThreadsTxNumerical = 8; | 
|  | 732 | break; | 
|  | 733 | default: | 
|  | 734 | numThreadsTxNumerical = 0; | 
|  | 735 | break; | 
|  | 736 | } | 
|  | 737 |  | 
|  | 738 | ugeth_info("Thread data TXs:"); | 
|  | 739 | ugeth_info("Base address: 0x%08x", | 
|  | 740 | (u32) ugeth->p_thread_data_tx); | 
|  | 741 | for (i = 0; i < numThreadsTxNumerical; i++) { | 
|  | 742 | ugeth_info("Thread data TX[%d]:", i); | 
|  | 743 | ugeth_info("Base address: 0x%08x", | 
|  | 744 | (u32) & ugeth->p_thread_data_tx[i]); | 
|  | 745 | mem_disp((u8 *) & ugeth->p_thread_data_tx[i], | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 746 | sizeof(struct ucc_geth_thread_data_tx)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 747 | } | 
|  | 748 | } | 
|  | 749 | if (ugeth->p_thread_data_rx) { | 
|  | 750 | int numThreadsRxNumerical; | 
|  | 751 | switch (ugeth->ug_info->numThreadsRx) { | 
|  | 752 | case UCC_GETH_NUM_OF_THREADS_1: | 
|  | 753 | numThreadsRxNumerical = 1; | 
|  | 754 | break; | 
|  | 755 | case UCC_GETH_NUM_OF_THREADS_2: | 
|  | 756 | numThreadsRxNumerical = 2; | 
|  | 757 | break; | 
|  | 758 | case UCC_GETH_NUM_OF_THREADS_4: | 
|  | 759 | numThreadsRxNumerical = 4; | 
|  | 760 | break; | 
|  | 761 | case UCC_GETH_NUM_OF_THREADS_6: | 
|  | 762 | numThreadsRxNumerical = 6; | 
|  | 763 | break; | 
|  | 764 | case UCC_GETH_NUM_OF_THREADS_8: | 
|  | 765 | numThreadsRxNumerical = 8; | 
|  | 766 | break; | 
|  | 767 | default: | 
|  | 768 | numThreadsRxNumerical = 0; | 
|  | 769 | break; | 
|  | 770 | } | 
|  | 771 |  | 
|  | 772 | ugeth_info("Thread data RX:"); | 
|  | 773 | ugeth_info("Base address: 0x%08x", | 
|  | 774 | (u32) ugeth->p_thread_data_rx); | 
|  | 775 | for (i = 0; i < numThreadsRxNumerical; i++) { | 
|  | 776 | ugeth_info("Thread data RX[%d]:", i); | 
|  | 777 | ugeth_info("Base address: 0x%08x", | 
|  | 778 | (u32) & ugeth->p_thread_data_rx[i]); | 
|  | 779 | mem_disp((u8 *) & ugeth->p_thread_data_rx[i], | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 780 | sizeof(struct ucc_geth_thread_data_rx)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 781 | } | 
|  | 782 | } | 
|  | 783 | if (ugeth->p_exf_glbl_param) { | 
|  | 784 | ugeth_info("EXF global param:"); | 
|  | 785 | ugeth_info("Base address: 0x%08x", | 
|  | 786 | (u32) ugeth->p_exf_glbl_param); | 
|  | 787 | mem_disp((u8 *) ugeth->p_exf_glbl_param, | 
|  | 788 | sizeof(*ugeth->p_exf_glbl_param)); | 
|  | 789 | } | 
|  | 790 | if (ugeth->p_tx_glbl_pram) { | 
|  | 791 | ugeth_info("TX global param:"); | 
|  | 792 | ugeth_info("Base address: 0x%08x", (u32) ugeth->p_tx_glbl_pram); | 
|  | 793 | ugeth_info("temoder      : addr - 0x%08x, val - 0x%04x", | 
|  | 794 | (u32) & ugeth->p_tx_glbl_pram->temoder, | 
|  | 795 | in_be16(&ugeth->p_tx_glbl_pram->temoder)); | 
|  | 796 | ugeth_info("sqptr        : addr - 0x%08x, val - 0x%08x", | 
|  | 797 | (u32) & ugeth->p_tx_glbl_pram->sqptr, | 
|  | 798 | in_be32(&ugeth->p_tx_glbl_pram->sqptr)); | 
|  | 799 | ugeth_info("schedulerbasepointer: addr - 0x%08x, val - 0x%08x", | 
|  | 800 | (u32) & ugeth->p_tx_glbl_pram->schedulerbasepointer, | 
|  | 801 | in_be32(&ugeth->p_tx_glbl_pram-> | 
|  | 802 | schedulerbasepointer)); | 
|  | 803 | ugeth_info("txrmonbaseptr: addr - 0x%08x, val - 0x%08x", | 
|  | 804 | (u32) & ugeth->p_tx_glbl_pram->txrmonbaseptr, | 
|  | 805 | in_be32(&ugeth->p_tx_glbl_pram->txrmonbaseptr)); | 
|  | 806 | ugeth_info("tstate       : addr - 0x%08x, val - 0x%08x", | 
|  | 807 | (u32) & ugeth->p_tx_glbl_pram->tstate, | 
|  | 808 | in_be32(&ugeth->p_tx_glbl_pram->tstate)); | 
|  | 809 | ugeth_info("iphoffset[0] : addr - 0x%08x, val - 0x%02x", | 
|  | 810 | (u32) & ugeth->p_tx_glbl_pram->iphoffset[0], | 
|  | 811 | ugeth->p_tx_glbl_pram->iphoffset[0]); | 
|  | 812 | ugeth_info("iphoffset[1] : addr - 0x%08x, val - 0x%02x", | 
|  | 813 | (u32) & ugeth->p_tx_glbl_pram->iphoffset[1], | 
|  | 814 | ugeth->p_tx_glbl_pram->iphoffset[1]); | 
|  | 815 | ugeth_info("iphoffset[2] : addr - 0x%08x, val - 0x%02x", | 
|  | 816 | (u32) & ugeth->p_tx_glbl_pram->iphoffset[2], | 
|  | 817 | ugeth->p_tx_glbl_pram->iphoffset[2]); | 
|  | 818 | ugeth_info("iphoffset[3] : addr - 0x%08x, val - 0x%02x", | 
|  | 819 | (u32) & ugeth->p_tx_glbl_pram->iphoffset[3], | 
|  | 820 | ugeth->p_tx_glbl_pram->iphoffset[3]); | 
|  | 821 | ugeth_info("iphoffset[4] : addr - 0x%08x, val - 0x%02x", | 
|  | 822 | (u32) & ugeth->p_tx_glbl_pram->iphoffset[4], | 
|  | 823 | ugeth->p_tx_glbl_pram->iphoffset[4]); | 
|  | 824 | ugeth_info("iphoffset[5] : addr - 0x%08x, val - 0x%02x", | 
|  | 825 | (u32) & ugeth->p_tx_glbl_pram->iphoffset[5], | 
|  | 826 | ugeth->p_tx_glbl_pram->iphoffset[5]); | 
|  | 827 | ugeth_info("iphoffset[6] : addr - 0x%08x, val - 0x%02x", | 
|  | 828 | (u32) & ugeth->p_tx_glbl_pram->iphoffset[6], | 
|  | 829 | ugeth->p_tx_glbl_pram->iphoffset[6]); | 
|  | 830 | ugeth_info("iphoffset[7] : addr - 0x%08x, val - 0x%02x", | 
|  | 831 | (u32) & ugeth->p_tx_glbl_pram->iphoffset[7], | 
|  | 832 | ugeth->p_tx_glbl_pram->iphoffset[7]); | 
|  | 833 | ugeth_info("vtagtable[0] : addr - 0x%08x, val - 0x%08x", | 
|  | 834 | (u32) & ugeth->p_tx_glbl_pram->vtagtable[0], | 
|  | 835 | in_be32(&ugeth->p_tx_glbl_pram->vtagtable[0])); | 
|  | 836 | ugeth_info("vtagtable[1] : addr - 0x%08x, val - 0x%08x", | 
|  | 837 | (u32) & ugeth->p_tx_glbl_pram->vtagtable[1], | 
|  | 838 | in_be32(&ugeth->p_tx_glbl_pram->vtagtable[1])); | 
|  | 839 | ugeth_info("vtagtable[2] : addr - 0x%08x, val - 0x%08x", | 
|  | 840 | (u32) & ugeth->p_tx_glbl_pram->vtagtable[2], | 
|  | 841 | in_be32(&ugeth->p_tx_glbl_pram->vtagtable[2])); | 
|  | 842 | ugeth_info("vtagtable[3] : addr - 0x%08x, val - 0x%08x", | 
|  | 843 | (u32) & ugeth->p_tx_glbl_pram->vtagtable[3], | 
|  | 844 | in_be32(&ugeth->p_tx_glbl_pram->vtagtable[3])); | 
|  | 845 | ugeth_info("vtagtable[4] : addr - 0x%08x, val - 0x%08x", | 
|  | 846 | (u32) & ugeth->p_tx_glbl_pram->vtagtable[4], | 
|  | 847 | in_be32(&ugeth->p_tx_glbl_pram->vtagtable[4])); | 
|  | 848 | ugeth_info("vtagtable[5] : addr - 0x%08x, val - 0x%08x", | 
|  | 849 | (u32) & ugeth->p_tx_glbl_pram->vtagtable[5], | 
|  | 850 | in_be32(&ugeth->p_tx_glbl_pram->vtagtable[5])); | 
|  | 851 | ugeth_info("vtagtable[6] : addr - 0x%08x, val - 0x%08x", | 
|  | 852 | (u32) & ugeth->p_tx_glbl_pram->vtagtable[6], | 
|  | 853 | in_be32(&ugeth->p_tx_glbl_pram->vtagtable[6])); | 
|  | 854 | ugeth_info("vtagtable[7] : addr - 0x%08x, val - 0x%08x", | 
|  | 855 | (u32) & ugeth->p_tx_glbl_pram->vtagtable[7], | 
|  | 856 | in_be32(&ugeth->p_tx_glbl_pram->vtagtable[7])); | 
|  | 857 | ugeth_info("tqptr        : addr - 0x%08x, val - 0x%08x", | 
|  | 858 | (u32) & ugeth->p_tx_glbl_pram->tqptr, | 
|  | 859 | in_be32(&ugeth->p_tx_glbl_pram->tqptr)); | 
|  | 860 | } | 
|  | 861 | if (ugeth->p_rx_glbl_pram) { | 
|  | 862 | ugeth_info("RX global param:"); | 
|  | 863 | ugeth_info("Base address: 0x%08x", (u32) ugeth->p_rx_glbl_pram); | 
|  | 864 | ugeth_info("remoder         : addr - 0x%08x, val - 0x%08x", | 
|  | 865 | (u32) & ugeth->p_rx_glbl_pram->remoder, | 
|  | 866 | in_be32(&ugeth->p_rx_glbl_pram->remoder)); | 
|  | 867 | ugeth_info("rqptr           : addr - 0x%08x, val - 0x%08x", | 
|  | 868 | (u32) & ugeth->p_rx_glbl_pram->rqptr, | 
|  | 869 | in_be32(&ugeth->p_rx_glbl_pram->rqptr)); | 
|  | 870 | ugeth_info("typeorlen       : addr - 0x%08x, val - 0x%04x", | 
|  | 871 | (u32) & ugeth->p_rx_glbl_pram->typeorlen, | 
|  | 872 | in_be16(&ugeth->p_rx_glbl_pram->typeorlen)); | 
|  | 873 | ugeth_info("rxgstpack       : addr - 0x%08x, val - 0x%02x", | 
|  | 874 | (u32) & ugeth->p_rx_glbl_pram->rxgstpack, | 
|  | 875 | ugeth->p_rx_glbl_pram->rxgstpack); | 
|  | 876 | ugeth_info("rxrmonbaseptr   : addr - 0x%08x, val - 0x%08x", | 
|  | 877 | (u32) & ugeth->p_rx_glbl_pram->rxrmonbaseptr, | 
|  | 878 | in_be32(&ugeth->p_rx_glbl_pram->rxrmonbaseptr)); | 
|  | 879 | ugeth_info("intcoalescingptr: addr - 0x%08x, val - 0x%08x", | 
|  | 880 | (u32) & ugeth->p_rx_glbl_pram->intcoalescingptr, | 
|  | 881 | in_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr)); | 
|  | 882 | ugeth_info("rstate          : addr - 0x%08x, val - 0x%02x", | 
|  | 883 | (u32) & ugeth->p_rx_glbl_pram->rstate, | 
|  | 884 | ugeth->p_rx_glbl_pram->rstate); | 
|  | 885 | ugeth_info("mrblr           : addr - 0x%08x, val - 0x%04x", | 
|  | 886 | (u32) & ugeth->p_rx_glbl_pram->mrblr, | 
|  | 887 | in_be16(&ugeth->p_rx_glbl_pram->mrblr)); | 
|  | 888 | ugeth_info("rbdqptr         : addr - 0x%08x, val - 0x%08x", | 
|  | 889 | (u32) & ugeth->p_rx_glbl_pram->rbdqptr, | 
|  | 890 | in_be32(&ugeth->p_rx_glbl_pram->rbdqptr)); | 
|  | 891 | ugeth_info("mflr            : addr - 0x%08x, val - 0x%04x", | 
|  | 892 | (u32) & ugeth->p_rx_glbl_pram->mflr, | 
|  | 893 | in_be16(&ugeth->p_rx_glbl_pram->mflr)); | 
|  | 894 | ugeth_info("minflr          : addr - 0x%08x, val - 0x%04x", | 
|  | 895 | (u32) & ugeth->p_rx_glbl_pram->minflr, | 
|  | 896 | in_be16(&ugeth->p_rx_glbl_pram->minflr)); | 
|  | 897 | ugeth_info("maxd1           : addr - 0x%08x, val - 0x%04x", | 
|  | 898 | (u32) & ugeth->p_rx_glbl_pram->maxd1, | 
|  | 899 | in_be16(&ugeth->p_rx_glbl_pram->maxd1)); | 
|  | 900 | ugeth_info("maxd2           : addr - 0x%08x, val - 0x%04x", | 
|  | 901 | (u32) & ugeth->p_rx_glbl_pram->maxd2, | 
|  | 902 | in_be16(&ugeth->p_rx_glbl_pram->maxd2)); | 
|  | 903 | ugeth_info("ecamptr         : addr - 0x%08x, val - 0x%08x", | 
|  | 904 | (u32) & ugeth->p_rx_glbl_pram->ecamptr, | 
|  | 905 | in_be32(&ugeth->p_rx_glbl_pram->ecamptr)); | 
|  | 906 | ugeth_info("l2qt            : addr - 0x%08x, val - 0x%08x", | 
|  | 907 | (u32) & ugeth->p_rx_glbl_pram->l2qt, | 
|  | 908 | in_be32(&ugeth->p_rx_glbl_pram->l2qt)); | 
|  | 909 | ugeth_info("l3qt[0]         : addr - 0x%08x, val - 0x%08x", | 
|  | 910 | (u32) & ugeth->p_rx_glbl_pram->l3qt[0], | 
|  | 911 | in_be32(&ugeth->p_rx_glbl_pram->l3qt[0])); | 
|  | 912 | ugeth_info("l3qt[1]         : addr - 0x%08x, val - 0x%08x", | 
|  | 913 | (u32) & ugeth->p_rx_glbl_pram->l3qt[1], | 
|  | 914 | in_be32(&ugeth->p_rx_glbl_pram->l3qt[1])); | 
|  | 915 | ugeth_info("l3qt[2]         : addr - 0x%08x, val - 0x%08x", | 
|  | 916 | (u32) & ugeth->p_rx_glbl_pram->l3qt[2], | 
|  | 917 | in_be32(&ugeth->p_rx_glbl_pram->l3qt[2])); | 
|  | 918 | ugeth_info("l3qt[3]         : addr - 0x%08x, val - 0x%08x", | 
|  | 919 | (u32) & ugeth->p_rx_glbl_pram->l3qt[3], | 
|  | 920 | in_be32(&ugeth->p_rx_glbl_pram->l3qt[3])); | 
|  | 921 | ugeth_info("l3qt[4]         : addr - 0x%08x, val - 0x%08x", | 
|  | 922 | (u32) & ugeth->p_rx_glbl_pram->l3qt[4], | 
|  | 923 | in_be32(&ugeth->p_rx_glbl_pram->l3qt[4])); | 
|  | 924 | ugeth_info("l3qt[5]         : addr - 0x%08x, val - 0x%08x", | 
|  | 925 | (u32) & ugeth->p_rx_glbl_pram->l3qt[5], | 
|  | 926 | in_be32(&ugeth->p_rx_glbl_pram->l3qt[5])); | 
|  | 927 | ugeth_info("l3qt[6]         : addr - 0x%08x, val - 0x%08x", | 
|  | 928 | (u32) & ugeth->p_rx_glbl_pram->l3qt[6], | 
|  | 929 | in_be32(&ugeth->p_rx_glbl_pram->l3qt[6])); | 
|  | 930 | ugeth_info("l3qt[7]         : addr - 0x%08x, val - 0x%08x", | 
|  | 931 | (u32) & ugeth->p_rx_glbl_pram->l3qt[7], | 
|  | 932 | in_be32(&ugeth->p_rx_glbl_pram->l3qt[7])); | 
|  | 933 | ugeth_info("vlantype        : addr - 0x%08x, val - 0x%04x", | 
|  | 934 | (u32) & ugeth->p_rx_glbl_pram->vlantype, | 
|  | 935 | in_be16(&ugeth->p_rx_glbl_pram->vlantype)); | 
|  | 936 | ugeth_info("vlantci         : addr - 0x%08x, val - 0x%04x", | 
|  | 937 | (u32) & ugeth->p_rx_glbl_pram->vlantci, | 
|  | 938 | in_be16(&ugeth->p_rx_glbl_pram->vlantci)); | 
|  | 939 | for (i = 0; i < 64; i++) | 
|  | 940 | ugeth_info | 
|  | 941 | ("addressfiltering[%d]: addr - 0x%08x, val - 0x%02x", | 
|  | 942 | i, | 
|  | 943 | (u32) & ugeth->p_rx_glbl_pram->addressfiltering[i], | 
|  | 944 | ugeth->p_rx_glbl_pram->addressfiltering[i]); | 
|  | 945 | ugeth_info("exfGlobalParam  : addr - 0x%08x, val - 0x%08x", | 
|  | 946 | (u32) & ugeth->p_rx_glbl_pram->exfGlobalParam, | 
|  | 947 | in_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam)); | 
|  | 948 | } | 
|  | 949 | if (ugeth->p_send_q_mem_reg) { | 
|  | 950 | ugeth_info("Send Q memory registers:"); | 
|  | 951 | ugeth_info("Base address: 0x%08x", | 
|  | 952 | (u32) ugeth->p_send_q_mem_reg); | 
|  | 953 | for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { | 
|  | 954 | ugeth_info("SQQD[%d]:", i); | 
|  | 955 | ugeth_info("Base address: 0x%08x", | 
|  | 956 | (u32) & ugeth->p_send_q_mem_reg->sqqd[i]); | 
|  | 957 | mem_disp((u8 *) & ugeth->p_send_q_mem_reg->sqqd[i], | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 958 | sizeof(struct ucc_geth_send_queue_qd)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 959 | } | 
|  | 960 | } | 
|  | 961 | if (ugeth->p_scheduler) { | 
|  | 962 | ugeth_info("Scheduler:"); | 
|  | 963 | ugeth_info("Base address: 0x%08x", (u32) ugeth->p_scheduler); | 
|  | 964 | mem_disp((u8 *) ugeth->p_scheduler, | 
|  | 965 | sizeof(*ugeth->p_scheduler)); | 
|  | 966 | } | 
|  | 967 | if (ugeth->p_tx_fw_statistics_pram) { | 
|  | 968 | ugeth_info("TX FW statistics pram:"); | 
|  | 969 | ugeth_info("Base address: 0x%08x", | 
|  | 970 | (u32) ugeth->p_tx_fw_statistics_pram); | 
|  | 971 | mem_disp((u8 *) ugeth->p_tx_fw_statistics_pram, | 
|  | 972 | sizeof(*ugeth->p_tx_fw_statistics_pram)); | 
|  | 973 | } | 
|  | 974 | if (ugeth->p_rx_fw_statistics_pram) { | 
|  | 975 | ugeth_info("RX FW statistics pram:"); | 
|  | 976 | ugeth_info("Base address: 0x%08x", | 
|  | 977 | (u32) ugeth->p_rx_fw_statistics_pram); | 
|  | 978 | mem_disp((u8 *) ugeth->p_rx_fw_statistics_pram, | 
|  | 979 | sizeof(*ugeth->p_rx_fw_statistics_pram)); | 
|  | 980 | } | 
|  | 981 | if (ugeth->p_rx_irq_coalescing_tbl) { | 
|  | 982 | ugeth_info("RX IRQ coalescing tables:"); | 
|  | 983 | ugeth_info("Base address: 0x%08x", | 
|  | 984 | (u32) ugeth->p_rx_irq_coalescing_tbl); | 
|  | 985 | for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) { | 
|  | 986 | ugeth_info("RX IRQ coalescing table entry[%d]:", i); | 
|  | 987 | ugeth_info("Base address: 0x%08x", | 
|  | 988 | (u32) & ugeth->p_rx_irq_coalescing_tbl-> | 
|  | 989 | coalescingentry[i]); | 
|  | 990 | ugeth_info | 
|  | 991 | ("interruptcoalescingmaxvalue: addr - 0x%08x, val - 0x%08x", | 
|  | 992 | (u32) & ugeth->p_rx_irq_coalescing_tbl-> | 
|  | 993 | coalescingentry[i].interruptcoalescingmaxvalue, | 
|  | 994 | in_be32(&ugeth->p_rx_irq_coalescing_tbl-> | 
|  | 995 | coalescingentry[i]. | 
|  | 996 | interruptcoalescingmaxvalue)); | 
|  | 997 | ugeth_info | 
|  | 998 | ("interruptcoalescingcounter : addr - 0x%08x, val - 0x%08x", | 
|  | 999 | (u32) & ugeth->p_rx_irq_coalescing_tbl-> | 
|  | 1000 | coalescingentry[i].interruptcoalescingcounter, | 
|  | 1001 | in_be32(&ugeth->p_rx_irq_coalescing_tbl-> | 
|  | 1002 | coalescingentry[i]. | 
|  | 1003 | interruptcoalescingcounter)); | 
|  | 1004 | } | 
|  | 1005 | } | 
|  | 1006 | if (ugeth->p_rx_bd_qs_tbl) { | 
|  | 1007 | ugeth_info("RX BD QS tables:"); | 
|  | 1008 | ugeth_info("Base address: 0x%08x", (u32) ugeth->p_rx_bd_qs_tbl); | 
|  | 1009 | for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) { | 
|  | 1010 | ugeth_info("RX BD QS table[%d]:", i); | 
|  | 1011 | ugeth_info("Base address: 0x%08x", | 
|  | 1012 | (u32) & ugeth->p_rx_bd_qs_tbl[i]); | 
|  | 1013 | ugeth_info | 
|  | 1014 | ("bdbaseptr        : addr - 0x%08x, val - 0x%08x", | 
|  | 1015 | (u32) & ugeth->p_rx_bd_qs_tbl[i].bdbaseptr, | 
|  | 1016 | in_be32(&ugeth->p_rx_bd_qs_tbl[i].bdbaseptr)); | 
|  | 1017 | ugeth_info | 
|  | 1018 | ("bdptr            : addr - 0x%08x, val - 0x%08x", | 
|  | 1019 | (u32) & ugeth->p_rx_bd_qs_tbl[i].bdptr, | 
|  | 1020 | in_be32(&ugeth->p_rx_bd_qs_tbl[i].bdptr)); | 
|  | 1021 | ugeth_info | 
|  | 1022 | ("externalbdbaseptr: addr - 0x%08x, val - 0x%08x", | 
|  | 1023 | (u32) & ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr, | 
|  | 1024 | in_be32(&ugeth->p_rx_bd_qs_tbl[i]. | 
|  | 1025 | externalbdbaseptr)); | 
|  | 1026 | ugeth_info | 
|  | 1027 | ("externalbdptr    : addr - 0x%08x, val - 0x%08x", | 
|  | 1028 | (u32) & ugeth->p_rx_bd_qs_tbl[i].externalbdptr, | 
|  | 1029 | in_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdptr)); | 
|  | 1030 | ugeth_info("ucode RX Prefetched BDs:"); | 
|  | 1031 | ugeth_info("Base address: 0x%08x", | 
|  | 1032 | (u32) | 
|  | 1033 | qe_muram_addr(in_be32 | 
|  | 1034 | (&ugeth->p_rx_bd_qs_tbl[i]. | 
|  | 1035 | bdbaseptr))); | 
|  | 1036 | mem_disp((u8 *) | 
|  | 1037 | qe_muram_addr(in_be32 | 
|  | 1038 | (&ugeth->p_rx_bd_qs_tbl[i]. | 
|  | 1039 | bdbaseptr)), | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1040 | sizeof(struct ucc_geth_rx_prefetched_bds)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1041 | } | 
|  | 1042 | } | 
|  | 1043 | if (ugeth->p_init_enet_param_shadow) { | 
|  | 1044 | int size; | 
|  | 1045 | ugeth_info("Init enet param shadow:"); | 
|  | 1046 | ugeth_info("Base address: 0x%08x", | 
|  | 1047 | (u32) ugeth->p_init_enet_param_shadow); | 
|  | 1048 | mem_disp((u8 *) ugeth->p_init_enet_param_shadow, | 
|  | 1049 | sizeof(*ugeth->p_init_enet_param_shadow)); | 
|  | 1050 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1051 | size = sizeof(struct ucc_geth_thread_rx_pram); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1052 | if (ugeth->ug_info->rxExtendedFiltering) { | 
|  | 1053 | size += | 
|  | 1054 | THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING; | 
|  | 1055 | if (ugeth->ug_info->largestexternallookupkeysize == | 
|  | 1056 | QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES) | 
|  | 1057 | size += | 
|  | 1058 | THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8; | 
|  | 1059 | if (ugeth->ug_info->largestexternallookupkeysize == | 
|  | 1060 | QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES) | 
|  | 1061 | size += | 
|  | 1062 | THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16; | 
|  | 1063 | } | 
|  | 1064 |  | 
|  | 1065 | dump_init_enet_entries(ugeth, | 
|  | 1066 | &(ugeth->p_init_enet_param_shadow-> | 
|  | 1067 | txthread[0]), | 
|  | 1068 | ENET_INIT_PARAM_MAX_ENTRIES_TX, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1069 | sizeof(struct ucc_geth_thread_tx_pram), | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1070 | ugeth->ug_info->riscTx, 0); | 
|  | 1071 | dump_init_enet_entries(ugeth, | 
|  | 1072 | &(ugeth->p_init_enet_param_shadow-> | 
|  | 1073 | rxthread[0]), | 
|  | 1074 | ENET_INIT_PARAM_MAX_ENTRIES_RX, size, | 
|  | 1075 | ugeth->ug_info->riscRx, 1); | 
|  | 1076 | } | 
|  | 1077 | } | 
|  | 1078 | #endif /* DEBUG */ | 
|  | 1079 |  | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1080 | static void init_default_reg_vals(u32 __iomem *upsmr_register, | 
|  | 1081 | u32 __iomem *maccfg1_register, | 
|  | 1082 | u32 __iomem *maccfg2_register) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1083 | { | 
|  | 1084 | out_be32(upsmr_register, UCC_GETH_UPSMR_INIT); | 
|  | 1085 | out_be32(maccfg1_register, UCC_GETH_MACCFG1_INIT); | 
|  | 1086 | out_be32(maccfg2_register, UCC_GETH_MACCFG2_INIT); | 
|  | 1087 | } | 
|  | 1088 |  | 
|  | 1089 | static int init_half_duplex_params(int alt_beb, | 
|  | 1090 | int back_pressure_no_backoff, | 
|  | 1091 | int no_backoff, | 
|  | 1092 | int excess_defer, | 
|  | 1093 | u8 alt_beb_truncation, | 
|  | 1094 | u8 max_retransmissions, | 
|  | 1095 | u8 collision_window, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1096 | u32 __iomem *hafdup_register) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1097 | { | 
|  | 1098 | u32 value = 0; | 
|  | 1099 |  | 
|  | 1100 | if ((alt_beb_truncation > HALFDUP_ALT_BEB_TRUNCATION_MAX) || | 
|  | 1101 | (max_retransmissions > HALFDUP_MAX_RETRANSMISSION_MAX) || | 
|  | 1102 | (collision_window > HALFDUP_COLLISION_WINDOW_MAX)) | 
|  | 1103 | return -EINVAL; | 
|  | 1104 |  | 
|  | 1105 | value = (u32) (alt_beb_truncation << HALFDUP_ALT_BEB_TRUNCATION_SHIFT); | 
|  | 1106 |  | 
|  | 1107 | if (alt_beb) | 
|  | 1108 | value |= HALFDUP_ALT_BEB; | 
|  | 1109 | if (back_pressure_no_backoff) | 
|  | 1110 | value |= HALFDUP_BACK_PRESSURE_NO_BACKOFF; | 
|  | 1111 | if (no_backoff) | 
|  | 1112 | value |= HALFDUP_NO_BACKOFF; | 
|  | 1113 | if (excess_defer) | 
|  | 1114 | value |= HALFDUP_EXCESSIVE_DEFER; | 
|  | 1115 |  | 
|  | 1116 | value |= (max_retransmissions << HALFDUP_MAX_RETRANSMISSION_SHIFT); | 
|  | 1117 |  | 
|  | 1118 | value |= collision_window; | 
|  | 1119 |  | 
|  | 1120 | out_be32(hafdup_register, value); | 
|  | 1121 | return 0; | 
|  | 1122 | } | 
|  | 1123 |  | 
|  | 1124 | static int init_inter_frame_gap_params(u8 non_btb_cs_ipg, | 
|  | 1125 | u8 non_btb_ipg, | 
|  | 1126 | u8 min_ifg, | 
|  | 1127 | u8 btb_ipg, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1128 | u32 __iomem *ipgifg_register) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1129 | { | 
|  | 1130 | u32 value = 0; | 
|  | 1131 |  | 
|  | 1132 | /* Non-Back-to-back IPG part 1 should be <= Non-Back-to-back | 
|  | 1133 | IPG part 2 */ | 
|  | 1134 | if (non_btb_cs_ipg > non_btb_ipg) | 
|  | 1135 | return -EINVAL; | 
|  | 1136 |  | 
|  | 1137 | if ((non_btb_cs_ipg > IPGIFG_NON_BACK_TO_BACK_IFG_PART1_MAX) || | 
|  | 1138 | (non_btb_ipg > IPGIFG_NON_BACK_TO_BACK_IFG_PART2_MAX) || | 
|  | 1139 | /*(min_ifg        > IPGIFG_MINIMUM_IFG_ENFORCEMENT_MAX) || */ | 
|  | 1140 | (btb_ipg > IPGIFG_BACK_TO_BACK_IFG_MAX)) | 
|  | 1141 | return -EINVAL; | 
|  | 1142 |  | 
|  | 1143 | value |= | 
|  | 1144 | ((non_btb_cs_ipg << IPGIFG_NON_BACK_TO_BACK_IFG_PART1_SHIFT) & | 
|  | 1145 | IPGIFG_NBTB_CS_IPG_MASK); | 
|  | 1146 | value |= | 
|  | 1147 | ((non_btb_ipg << IPGIFG_NON_BACK_TO_BACK_IFG_PART2_SHIFT) & | 
|  | 1148 | IPGIFG_NBTB_IPG_MASK); | 
|  | 1149 | value |= | 
|  | 1150 | ((min_ifg << IPGIFG_MINIMUM_IFG_ENFORCEMENT_SHIFT) & | 
|  | 1151 | IPGIFG_MIN_IFG_MASK); | 
|  | 1152 | value |= (btb_ipg & IPGIFG_BTB_IPG_MASK); | 
|  | 1153 |  | 
|  | 1154 | out_be32(ipgifg_register, value); | 
|  | 1155 | return 0; | 
|  | 1156 | } | 
|  | 1157 |  | 
| Li Yang | ac42185 | 2007-07-19 11:47:47 +0800 | [diff] [blame] | 1158 | int init_flow_control_params(u32 automatic_flow_control_mode, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1159 | int rx_flow_control_enable, | 
|  | 1160 | int tx_flow_control_enable, | 
|  | 1161 | u16 pause_period, | 
|  | 1162 | u16 extension_field, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1163 | u32 __iomem *upsmr_register, | 
|  | 1164 | u32 __iomem *uempr_register, | 
|  | 1165 | u32 __iomem *maccfg1_register) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1166 | { | 
|  | 1167 | u32 value = 0; | 
|  | 1168 |  | 
|  | 1169 | /* Set UEMPR register */ | 
|  | 1170 | value = (u32) pause_period << UEMPR_PAUSE_TIME_VALUE_SHIFT; | 
|  | 1171 | value |= (u32) extension_field << UEMPR_EXTENDED_PAUSE_TIME_VALUE_SHIFT; | 
|  | 1172 | out_be32(uempr_register, value); | 
|  | 1173 |  | 
|  | 1174 | /* Set UPSMR register */ | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1175 | setbits32(upsmr_register, automatic_flow_control_mode); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1176 |  | 
|  | 1177 | value = in_be32(maccfg1_register); | 
|  | 1178 | if (rx_flow_control_enable) | 
|  | 1179 | value |= MACCFG1_FLOW_RX; | 
|  | 1180 | if (tx_flow_control_enable) | 
|  | 1181 | value |= MACCFG1_FLOW_TX; | 
|  | 1182 | out_be32(maccfg1_register, value); | 
|  | 1183 |  | 
|  | 1184 | return 0; | 
|  | 1185 | } | 
|  | 1186 |  | 
|  | 1187 | static int init_hw_statistics_gathering_mode(int enable_hardware_statistics, | 
|  | 1188 | int auto_zero_hardware_statistics, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1189 | u32 __iomem *upsmr_register, | 
|  | 1190 | u16 __iomem *uescr_register) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1191 | { | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1192 | u16 uescr_value = 0; | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1193 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1194 | /* Enable hardware statistics gathering if requested */ | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1195 | if (enable_hardware_statistics) | 
|  | 1196 | setbits32(upsmr_register, UCC_GETH_UPSMR_HSE); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1197 |  | 
|  | 1198 | /* Clear hardware statistics counters */ | 
|  | 1199 | uescr_value = in_be16(uescr_register); | 
|  | 1200 | uescr_value |= UESCR_CLRCNT; | 
|  | 1201 | /* Automatically zero hardware statistics counters on read, | 
|  | 1202 | if requested */ | 
|  | 1203 | if (auto_zero_hardware_statistics) | 
|  | 1204 | uescr_value |= UESCR_AUTOZ; | 
|  | 1205 | out_be16(uescr_register, uescr_value); | 
|  | 1206 |  | 
|  | 1207 | return 0; | 
|  | 1208 | } | 
|  | 1209 |  | 
|  | 1210 | static int init_firmware_statistics_gathering_mode(int | 
|  | 1211 | enable_tx_firmware_statistics, | 
|  | 1212 | int enable_rx_firmware_statistics, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1213 | u32 __iomem *tx_rmon_base_ptr, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1214 | u32 tx_firmware_statistics_structure_address, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1215 | u32 __iomem *rx_rmon_base_ptr, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1216 | u32 rx_firmware_statistics_structure_address, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1217 | u16 __iomem *temoder_register, | 
|  | 1218 | u32 __iomem *remoder_register) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1219 | { | 
|  | 1220 | /* Note: this function does not check if */ | 
|  | 1221 | /* the parameters it receives are NULL   */ | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1222 |  | 
|  | 1223 | if (enable_tx_firmware_statistics) { | 
|  | 1224 | out_be32(tx_rmon_base_ptr, | 
|  | 1225 | tx_firmware_statistics_structure_address); | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1226 | setbits16(temoder_register, TEMODER_TX_RMON_STATISTICS_ENABLE); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1227 | } | 
|  | 1228 |  | 
|  | 1229 | if (enable_rx_firmware_statistics) { | 
|  | 1230 | out_be32(rx_rmon_base_ptr, | 
|  | 1231 | rx_firmware_statistics_structure_address); | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1232 | setbits32(remoder_register, REMODER_RX_RMON_STATISTICS_ENABLE); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1233 | } | 
|  | 1234 |  | 
|  | 1235 | return 0; | 
|  | 1236 | } | 
|  | 1237 |  | 
|  | 1238 | static int init_mac_station_addr_regs(u8 address_byte_0, | 
|  | 1239 | u8 address_byte_1, | 
|  | 1240 | u8 address_byte_2, | 
|  | 1241 | u8 address_byte_3, | 
|  | 1242 | u8 address_byte_4, | 
|  | 1243 | u8 address_byte_5, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1244 | u32 __iomem *macstnaddr1_register, | 
|  | 1245 | u32 __iomem *macstnaddr2_register) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1246 | { | 
|  | 1247 | u32 value = 0; | 
|  | 1248 |  | 
|  | 1249 | /* Example: for a station address of 0x12345678ABCD, */ | 
|  | 1250 | /* 0x12 is byte 0, 0x34 is byte 1 and so on and 0xCD is byte 5 */ | 
|  | 1251 |  | 
|  | 1252 | /* MACSTNADDR1 Register: */ | 
|  | 1253 |  | 
|  | 1254 | /* 0                      7   8                      15  */ | 
|  | 1255 | /* station address byte 5     station address byte 4     */ | 
|  | 1256 | /* 16                     23  24                     31  */ | 
|  | 1257 | /* station address byte 3     station address byte 2     */ | 
|  | 1258 | value |= (u32) ((address_byte_2 << 0) & 0x000000FF); | 
|  | 1259 | value |= (u32) ((address_byte_3 << 8) & 0x0000FF00); | 
|  | 1260 | value |= (u32) ((address_byte_4 << 16) & 0x00FF0000); | 
|  | 1261 | value |= (u32) ((address_byte_5 << 24) & 0xFF000000); | 
|  | 1262 |  | 
|  | 1263 | out_be32(macstnaddr1_register, value); | 
|  | 1264 |  | 
|  | 1265 | /* MACSTNADDR2 Register: */ | 
|  | 1266 |  | 
|  | 1267 | /* 0                      7   8                      15  */ | 
|  | 1268 | /* station address byte 1     station address byte 0     */ | 
|  | 1269 | /* 16                     23  24                     31  */ | 
|  | 1270 | /*         reserved                   reserved           */ | 
|  | 1271 | value = 0; | 
|  | 1272 | value |= (u32) ((address_byte_0 << 16) & 0x00FF0000); | 
|  | 1273 | value |= (u32) ((address_byte_1 << 24) & 0xFF000000); | 
|  | 1274 |  | 
|  | 1275 | out_be32(macstnaddr2_register, value); | 
|  | 1276 |  | 
|  | 1277 | return 0; | 
|  | 1278 | } | 
|  | 1279 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1280 | static int init_check_frame_length_mode(int length_check, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1281 | u32 __iomem *maccfg2_register) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1282 | { | 
|  | 1283 | u32 value = 0; | 
|  | 1284 |  | 
|  | 1285 | value = in_be32(maccfg2_register); | 
|  | 1286 |  | 
|  | 1287 | if (length_check) | 
|  | 1288 | value |= MACCFG2_LC; | 
|  | 1289 | else | 
|  | 1290 | value &= ~MACCFG2_LC; | 
|  | 1291 |  | 
|  | 1292 | out_be32(maccfg2_register, value); | 
|  | 1293 | return 0; | 
|  | 1294 | } | 
|  | 1295 |  | 
|  | 1296 | static int init_preamble_length(u8 preamble_length, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1297 | u32 __iomem *maccfg2_register) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1298 | { | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1299 | if ((preamble_length < 3) || (preamble_length > 7)) | 
|  | 1300 | return -EINVAL; | 
|  | 1301 |  | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1302 | clrsetbits_be32(maccfg2_register, MACCFG2_PREL_MASK, | 
|  | 1303 | preamble_length << MACCFG2_PREL_SHIFT); | 
|  | 1304 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1305 | return 0; | 
|  | 1306 | } | 
|  | 1307 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1308 | static int init_rx_parameters(int reject_broadcast, | 
|  | 1309 | int receive_short_frames, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1310 | int promiscuous, u32 __iomem *upsmr_register) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1311 | { | 
|  | 1312 | u32 value = 0; | 
|  | 1313 |  | 
|  | 1314 | value = in_be32(upsmr_register); | 
|  | 1315 |  | 
|  | 1316 | if (reject_broadcast) | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1317 | value |= UCC_GETH_UPSMR_BRO; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1318 | else | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1319 | value &= ~UCC_GETH_UPSMR_BRO; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1320 |  | 
|  | 1321 | if (receive_short_frames) | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1322 | value |= UCC_GETH_UPSMR_RSH; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1323 | else | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1324 | value &= ~UCC_GETH_UPSMR_RSH; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1325 |  | 
|  | 1326 | if (promiscuous) | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1327 | value |= UCC_GETH_UPSMR_PRO; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1328 | else | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1329 | value &= ~UCC_GETH_UPSMR_PRO; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1330 |  | 
|  | 1331 | out_be32(upsmr_register, value); | 
|  | 1332 |  | 
|  | 1333 | return 0; | 
|  | 1334 | } | 
|  | 1335 |  | 
|  | 1336 | static int init_max_rx_buff_len(u16 max_rx_buf_len, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1337 | u16 __iomem *mrblr_register) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1338 | { | 
|  | 1339 | /* max_rx_buf_len value must be a multiple of 128 */ | 
|  | 1340 | if ((max_rx_buf_len == 0) | 
|  | 1341 | || (max_rx_buf_len % UCC_GETH_MRBLR_ALIGNMENT)) | 
|  | 1342 | return -EINVAL; | 
|  | 1343 |  | 
|  | 1344 | out_be16(mrblr_register, max_rx_buf_len); | 
|  | 1345 | return 0; | 
|  | 1346 | } | 
|  | 1347 |  | 
|  | 1348 | static int init_min_frame_len(u16 min_frame_length, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1349 | u16 __iomem *minflr_register, | 
|  | 1350 | u16 __iomem *mrblr_register) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1351 | { | 
|  | 1352 | u16 mrblr_value = 0; | 
|  | 1353 |  | 
|  | 1354 | mrblr_value = in_be16(mrblr_register); | 
|  | 1355 | if (min_frame_length >= (mrblr_value - 4)) | 
|  | 1356 | return -EINVAL; | 
|  | 1357 |  | 
|  | 1358 | out_be16(minflr_register, min_frame_length); | 
|  | 1359 | return 0; | 
|  | 1360 | } | 
|  | 1361 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1362 | static int adjust_enet_interface(struct ucc_geth_private *ugeth) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1363 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1364 | struct ucc_geth_info *ug_info; | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1365 | struct ucc_geth __iomem *ug_regs; | 
|  | 1366 | struct ucc_fast __iomem *uf_regs; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1367 | int ret_val; | 
|  | 1368 | u32 upsmr, maccfg2, tbiBaseAddress; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1369 | u16 value; | 
|  | 1370 |  | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 1371 | ugeth_vdbg("%s: IN", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1372 |  | 
|  | 1373 | ug_info = ugeth->ug_info; | 
|  | 1374 | ug_regs = ugeth->ug_regs; | 
|  | 1375 | uf_regs = ugeth->uccf->uf_regs; | 
|  | 1376 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1377 | /*                    Set MACCFG2                    */ | 
|  | 1378 | maccfg2 = in_be32(&ug_regs->maccfg2); | 
|  | 1379 | maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1380 | if ((ugeth->max_speed == SPEED_10) || | 
|  | 1381 | (ugeth->max_speed == SPEED_100)) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1382 | maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1383 | else if (ugeth->max_speed == SPEED_1000) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1384 | maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; | 
|  | 1385 | maccfg2 |= ug_info->padAndCrc; | 
|  | 1386 | out_be32(&ug_regs->maccfg2, maccfg2); | 
|  | 1387 |  | 
|  | 1388 | /*                    Set UPSMR                      */ | 
|  | 1389 | upsmr = in_be32(&uf_regs->upsmr); | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1390 | upsmr &= ~(UCC_GETH_UPSMR_RPM | UCC_GETH_UPSMR_R10M | | 
|  | 1391 | UCC_GETH_UPSMR_TBIM | UCC_GETH_UPSMR_RMM); | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1392 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) || | 
|  | 1393 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) || | 
|  | 1394 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) || | 
| Kim Phillips | bd0ceaa | 2007-11-26 16:17:58 -0600 | [diff] [blame] | 1395 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID) || | 
|  | 1396 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) || | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1397 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1398 | upsmr |= UCC_GETH_UPSMR_RPM; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1399 | switch (ugeth->max_speed) { | 
|  | 1400 | case SPEED_10: | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1401 | upsmr |= UCC_GETH_UPSMR_R10M; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1402 | /* FALLTHROUGH */ | 
|  | 1403 | case SPEED_100: | 
|  | 1404 | if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI) | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1405 | upsmr |= UCC_GETH_UPSMR_RMM; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1406 | } | 
|  | 1407 | } | 
|  | 1408 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) || | 
|  | 1409 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1410 | upsmr |= UCC_GETH_UPSMR_TBIM; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1411 | } | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1412 | out_be32(&uf_regs->upsmr, upsmr); | 
|  | 1413 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1414 | /* Disable autonegotiation in tbi mode, because by default it | 
|  | 1415 | comes up in autonegotiation mode. */ | 
|  | 1416 | /* Note that this depends on proper setting in utbipar register. */ | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1417 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) || | 
|  | 1418 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1419 | tbiBaseAddress = in_be32(&ug_regs->utbipar); | 
|  | 1420 | tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK; | 
|  | 1421 | tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1422 | value = ugeth->phydev->bus->read(ugeth->phydev->bus, | 
|  | 1423 | (u8) tbiBaseAddress, ENET_TBI_MII_CR); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1424 | value &= ~0x1000;	/* Turn off autonegotiation */ | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1425 | ugeth->phydev->bus->write(ugeth->phydev->bus, | 
|  | 1426 | (u8) tbiBaseAddress, ENET_TBI_MII_CR, value); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1427 | } | 
|  | 1428 |  | 
|  | 1429 | init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2); | 
|  | 1430 |  | 
|  | 1431 | ret_val = init_preamble_length(ug_info->prel, &ug_regs->maccfg2); | 
|  | 1432 | if (ret_val != 0) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 1433 | if (netif_msg_probe(ugeth)) | 
|  | 1434 | ugeth_err("%s: Preamble length must be between 3 and 7 inclusive.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 1435 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1436 | return ret_val; | 
|  | 1437 | } | 
|  | 1438 |  | 
|  | 1439 | return 0; | 
|  | 1440 | } | 
|  | 1441 |  | 
|  | 1442 | /* Called every time the controller might need to be made | 
|  | 1443 | * aware of new link state.  The PHY code conveys this | 
|  | 1444 | * information through variables in the ugeth structure, and this | 
|  | 1445 | * function converts those variables into the appropriate | 
|  | 1446 | * register values, and can bring down the device if needed. | 
|  | 1447 | */ | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1448 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1449 | static void adjust_link(struct net_device *dev) | 
|  | 1450 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1451 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1452 | struct ucc_geth __iomem *ug_regs; | 
|  | 1453 | struct ucc_fast __iomem *uf_regs; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1454 | struct phy_device *phydev = ugeth->phydev; | 
|  | 1455 | unsigned long flags; | 
|  | 1456 | int new_state = 0; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1457 |  | 
|  | 1458 | ug_regs = ugeth->ug_regs; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1459 | uf_regs = ugeth->uccf->uf_regs; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1460 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1461 | spin_lock_irqsave(&ugeth->lock, flags); | 
|  | 1462 |  | 
|  | 1463 | if (phydev->link) { | 
|  | 1464 | u32 tempval = in_be32(&ug_regs->maccfg2); | 
|  | 1465 | u32 upsmr = in_be32(&uf_regs->upsmr); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1466 | /* Now we make sure that we can be in full duplex mode. | 
|  | 1467 | * If not, we operate in half-duplex mode. */ | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1468 | if (phydev->duplex != ugeth->oldduplex) { | 
|  | 1469 | new_state = 1; | 
|  | 1470 | if (!(phydev->duplex)) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1471 | tempval &= ~(MACCFG2_FDX); | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1472 | else | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1473 | tempval |= MACCFG2_FDX; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1474 | ugeth->oldduplex = phydev->duplex; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1475 | } | 
|  | 1476 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1477 | if (phydev->speed != ugeth->oldspeed) { | 
|  | 1478 | new_state = 1; | 
|  | 1479 | switch (phydev->speed) { | 
|  | 1480 | case SPEED_1000: | 
|  | 1481 | tempval = ((tempval & | 
|  | 1482 | ~(MACCFG2_INTERFACE_MODE_MASK)) | | 
|  | 1483 | MACCFG2_INTERFACE_MODE_BYTE); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1484 | break; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1485 | case SPEED_100: | 
|  | 1486 | case SPEED_10: | 
|  | 1487 | tempval = ((tempval & | 
|  | 1488 | ~(MACCFG2_INTERFACE_MODE_MASK)) | | 
|  | 1489 | MACCFG2_INTERFACE_MODE_NIBBLE); | 
|  | 1490 | /* if reduced mode, re-set UPSMR.R10M */ | 
|  | 1491 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) || | 
|  | 1492 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) || | 
|  | 1493 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) || | 
| Kim Phillips | bd0ceaa | 2007-11-26 16:17:58 -0600 | [diff] [blame] | 1494 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID) || | 
|  | 1495 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) || | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1496 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | 
|  | 1497 | if (phydev->speed == SPEED_10) | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1498 | upsmr |= UCC_GETH_UPSMR_R10M; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1499 | else | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1500 | upsmr &= ~UCC_GETH_UPSMR_R10M; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1501 | } | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1502 | break; | 
|  | 1503 | default: | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1504 | if (netif_msg_link(ugeth)) | 
|  | 1505 | ugeth_warn( | 
|  | 1506 | "%s: Ack!  Speed (%d) is not 10/100/1000!", | 
|  | 1507 | dev->name, phydev->speed); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1508 | break; | 
|  | 1509 | } | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1510 | ugeth->oldspeed = phydev->speed; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1511 | } | 
|  | 1512 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1513 | out_be32(&ug_regs->maccfg2, tempval); | 
|  | 1514 | out_be32(&uf_regs->upsmr, upsmr); | 
|  | 1515 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1516 | if (!ugeth->oldlink) { | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1517 | new_state = 1; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1518 | ugeth->oldlink = 1; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1519 | } | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1520 | } else if (ugeth->oldlink) { | 
|  | 1521 | new_state = 1; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1522 | ugeth->oldlink = 0; | 
|  | 1523 | ugeth->oldspeed = 0; | 
|  | 1524 | ugeth->oldduplex = -1; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1525 | } | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1526 |  | 
|  | 1527 | if (new_state && netif_msg_link(ugeth)) | 
|  | 1528 | phy_print_status(phydev); | 
|  | 1529 |  | 
|  | 1530 | spin_unlock_irqrestore(&ugeth->lock, flags); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1531 | } | 
|  | 1532 |  | 
|  | 1533 | /* Configure the PHY for dev. | 
|  | 1534 | * returns 0 if success.  -1 if failure | 
|  | 1535 | */ | 
|  | 1536 | static int init_phy(struct net_device *dev) | 
|  | 1537 | { | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1538 | struct ucc_geth_private *priv = netdev_priv(dev); | 
| Anton Vorontsov | 61fa9dc | 2009-03-22 21:30:52 -0700 | [diff] [blame] | 1539 | struct ucc_geth_info *ug_info = priv->ug_info; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1540 | struct phy_device *phydev; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1541 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1542 | priv->oldlink = 0; | 
|  | 1543 | priv->oldspeed = 0; | 
|  | 1544 | priv->oldduplex = -1; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1545 |  | 
| Anton Vorontsov | 61fa9dc | 2009-03-22 21:30:52 -0700 | [diff] [blame] | 1546 | phydev = phy_connect(dev, ug_info->phy_bus_id, &adjust_link, 0, | 
|  | 1547 | priv->phy_interface); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1548 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1549 | if (IS_ERR(phydev)) { | 
|  | 1550 | printk("%s: Could not attach to PHY\n", dev->name); | 
|  | 1551 | return PTR_ERR(phydev); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1552 | } | 
|  | 1553 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1554 | phydev->supported &= (ADVERTISED_10baseT_Half | | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1555 | ADVERTISED_10baseT_Full | | 
|  | 1556 | ADVERTISED_100baseT_Half | | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1557 | ADVERTISED_100baseT_Full); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1558 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1559 | if (priv->max_speed == SPEED_1000) | 
|  | 1560 | phydev->supported |= ADVERTISED_1000baseT_Full; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1561 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1562 | phydev->advertising = phydev->supported; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1563 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1564 | priv->phydev = phydev; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1565 |  | 
|  | 1566 | return 0; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1567 | } | 
|  | 1568 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1569 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1570 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1571 | static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1572 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1573 | struct ucc_fast_private *uccf; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1574 | u32 cecr_subblock; | 
|  | 1575 | u32 temp; | 
| Anton Vorontsov | b3431c6 | 2008-12-18 08:23:22 +0000 | [diff] [blame] | 1576 | int i = 10; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1577 |  | 
|  | 1578 | uccf = ugeth->uccf; | 
|  | 1579 |  | 
|  | 1580 | /* Mask GRACEFUL STOP TX interrupt bit and clear it */ | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1581 | clrbits32(uccf->p_uccm, UCC_GETH_UCCE_GRA); | 
|  | 1582 | out_be32(uccf->p_ucce, UCC_GETH_UCCE_GRA);  /* clear by writing 1 */ | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1583 |  | 
|  | 1584 | /* Issue host command */ | 
|  | 1585 | cecr_subblock = | 
|  | 1586 | ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); | 
|  | 1587 | qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1588 | QE_CR_PROTOCOL_ETHERNET, 0); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1589 |  | 
|  | 1590 | /* Wait for command to complete */ | 
|  | 1591 | do { | 
| Anton Vorontsov | b3431c6 | 2008-12-18 08:23:22 +0000 | [diff] [blame] | 1592 | msleep(10); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1593 | temp = in_be32(uccf->p_ucce); | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1594 | } while (!(temp & UCC_GETH_UCCE_GRA) && --i); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1595 |  | 
|  | 1596 | uccf->stopped_tx = 1; | 
|  | 1597 |  | 
|  | 1598 | return 0; | 
|  | 1599 | } | 
|  | 1600 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1601 | static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1602 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1603 | struct ucc_fast_private *uccf; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1604 | u32 cecr_subblock; | 
|  | 1605 | u8 temp; | 
| Anton Vorontsov | b3431c6 | 2008-12-18 08:23:22 +0000 | [diff] [blame] | 1606 | int i = 10; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1607 |  | 
|  | 1608 | uccf = ugeth->uccf; | 
|  | 1609 |  | 
|  | 1610 | /* Clear acknowledge bit */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1611 | temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1612 | temp &= ~GRACEFUL_STOP_ACKNOWLEDGE_RX; | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1613 | out_8(&ugeth->p_rx_glbl_pram->rxgstpack, temp); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1614 |  | 
|  | 1615 | /* Keep issuing command and checking acknowledge bit until | 
|  | 1616 | it is asserted, according to spec */ | 
|  | 1617 | do { | 
|  | 1618 | /* Issue host command */ | 
|  | 1619 | cecr_subblock = | 
|  | 1620 | ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info. | 
|  | 1621 | ucc_num); | 
|  | 1622 | qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1623 | QE_CR_PROTOCOL_ETHERNET, 0); | 
| Anton Vorontsov | b3431c6 | 2008-12-18 08:23:22 +0000 | [diff] [blame] | 1624 | msleep(10); | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1625 | temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack); | 
| Anton Vorontsov | b3431c6 | 2008-12-18 08:23:22 +0000 | [diff] [blame] | 1626 | } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX) && --i); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1627 |  | 
|  | 1628 | uccf->stopped_rx = 1; | 
|  | 1629 |  | 
|  | 1630 | return 0; | 
|  | 1631 | } | 
|  | 1632 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1633 | static int ugeth_restart_tx(struct ucc_geth_private *ugeth) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1634 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1635 | struct ucc_fast_private *uccf; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1636 | u32 cecr_subblock; | 
|  | 1637 |  | 
|  | 1638 | uccf = ugeth->uccf; | 
|  | 1639 |  | 
|  | 1640 | cecr_subblock = | 
|  | 1641 | ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1642 | qe_issue_cmd(QE_RESTART_TX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, 0); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1643 | uccf->stopped_tx = 0; | 
|  | 1644 |  | 
|  | 1645 | return 0; | 
|  | 1646 | } | 
|  | 1647 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1648 | static int ugeth_restart_rx(struct ucc_geth_private *ugeth) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1649 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1650 | struct ucc_fast_private *uccf; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1651 | u32 cecr_subblock; | 
|  | 1652 |  | 
|  | 1653 | uccf = ugeth->uccf; | 
|  | 1654 |  | 
|  | 1655 | cecr_subblock = | 
|  | 1656 | ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1657 | qe_issue_cmd(QE_RESTART_RX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1658 | 0); | 
|  | 1659 | uccf->stopped_rx = 0; | 
|  | 1660 |  | 
|  | 1661 | return 0; | 
|  | 1662 | } | 
|  | 1663 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1664 | static int ugeth_enable(struct ucc_geth_private *ugeth, enum comm_dir mode) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1665 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1666 | struct ucc_fast_private *uccf; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1667 | int enabled_tx, enabled_rx; | 
|  | 1668 |  | 
|  | 1669 | uccf = ugeth->uccf; | 
|  | 1670 |  | 
|  | 1671 | /* check if the UCC number is in range. */ | 
|  | 1672 | if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 1673 | if (netif_msg_probe(ugeth)) | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 1674 | ugeth_err("%s: ucc_num out of range.", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1675 | return -EINVAL; | 
|  | 1676 | } | 
|  | 1677 |  | 
|  | 1678 | enabled_tx = uccf->enabled_tx; | 
|  | 1679 | enabled_rx = uccf->enabled_rx; | 
|  | 1680 |  | 
|  | 1681 | /* Get Tx and Rx going again, in case this channel was actively | 
|  | 1682 | disabled. */ | 
|  | 1683 | if ((mode & COMM_DIR_TX) && (!enabled_tx) && uccf->stopped_tx) | 
|  | 1684 | ugeth_restart_tx(ugeth); | 
|  | 1685 | if ((mode & COMM_DIR_RX) && (!enabled_rx) && uccf->stopped_rx) | 
|  | 1686 | ugeth_restart_rx(ugeth); | 
|  | 1687 |  | 
|  | 1688 | ucc_fast_enable(uccf, mode);	/* OK to do even if not disabled */ | 
|  | 1689 |  | 
|  | 1690 | return 0; | 
|  | 1691 |  | 
|  | 1692 | } | 
|  | 1693 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1694 | static int ugeth_disable(struct ucc_geth_private * ugeth, enum comm_dir mode) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1695 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1696 | struct ucc_fast_private *uccf; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1697 |  | 
|  | 1698 | uccf = ugeth->uccf; | 
|  | 1699 |  | 
|  | 1700 | /* check if the UCC number is in range. */ | 
|  | 1701 | if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 1702 | if (netif_msg_probe(ugeth)) | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 1703 | ugeth_err("%s: ucc_num out of range.", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1704 | return -EINVAL; | 
|  | 1705 | } | 
|  | 1706 |  | 
|  | 1707 | /* Stop any transmissions */ | 
|  | 1708 | if ((mode & COMM_DIR_TX) && uccf->enabled_tx && !uccf->stopped_tx) | 
|  | 1709 | ugeth_graceful_stop_tx(ugeth); | 
|  | 1710 |  | 
|  | 1711 | /* Stop any receptions */ | 
|  | 1712 | if ((mode & COMM_DIR_RX) && uccf->enabled_rx && !uccf->stopped_rx) | 
|  | 1713 | ugeth_graceful_stop_rx(ugeth); | 
|  | 1714 |  | 
|  | 1715 | ucc_fast_disable(ugeth->uccf, mode); /* OK to do even if not enabled */ | 
|  | 1716 |  | 
|  | 1717 | return 0; | 
|  | 1718 | } | 
|  | 1719 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1720 | static void ugeth_dump_regs(struct ucc_geth_private *ugeth) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1721 | { | 
|  | 1722 | #ifdef DEBUG | 
|  | 1723 | ucc_fast_dump_regs(ugeth->uccf); | 
|  | 1724 | dump_regs(ugeth); | 
|  | 1725 | dump_bds(ugeth); | 
|  | 1726 | #endif | 
|  | 1727 | } | 
|  | 1728 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1729 | static int ugeth_82xx_filtering_clear_all_addr_in_hash(struct ucc_geth_private * | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1730 | ugeth, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1731 | enum enet_addr_type | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1732 | enet_addr_type) | 
|  | 1733 | { | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1734 | struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt; | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1735 | struct ucc_fast_private *uccf; | 
|  | 1736 | enum comm_dir comm_dir; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1737 | struct list_head *p_lh; | 
|  | 1738 | u16 i, num; | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1739 | u32 __iomem *addr_h; | 
|  | 1740 | u32 __iomem *addr_l; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1741 | u8 *p_counter; | 
|  | 1742 |  | 
|  | 1743 | uccf = ugeth->uccf; | 
|  | 1744 |  | 
|  | 1745 | p_82xx_addr_filt = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1746 | (struct ucc_geth_82xx_address_filtering_pram __iomem *) | 
|  | 1747 | ugeth->p_rx_glbl_pram->addressfiltering; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1748 |  | 
|  | 1749 | if (enet_addr_type == ENET_ADDR_TYPE_GROUP) { | 
|  | 1750 | addr_h = &(p_82xx_addr_filt->gaddr_h); | 
|  | 1751 | addr_l = &(p_82xx_addr_filt->gaddr_l); | 
|  | 1752 | p_lh = &ugeth->group_hash_q; | 
|  | 1753 | p_counter = &(ugeth->numGroupAddrInHash); | 
|  | 1754 | } else if (enet_addr_type == ENET_ADDR_TYPE_INDIVIDUAL) { | 
|  | 1755 | addr_h = &(p_82xx_addr_filt->iaddr_h); | 
|  | 1756 | addr_l = &(p_82xx_addr_filt->iaddr_l); | 
|  | 1757 | p_lh = &ugeth->ind_hash_q; | 
|  | 1758 | p_counter = &(ugeth->numIndAddrInHash); | 
|  | 1759 | } else | 
|  | 1760 | return -EINVAL; | 
|  | 1761 |  | 
|  | 1762 | comm_dir = 0; | 
|  | 1763 | if (uccf->enabled_tx) | 
|  | 1764 | comm_dir |= COMM_DIR_TX; | 
|  | 1765 | if (uccf->enabled_rx) | 
|  | 1766 | comm_dir |= COMM_DIR_RX; | 
|  | 1767 | if (comm_dir) | 
|  | 1768 | ugeth_disable(ugeth, comm_dir); | 
|  | 1769 |  | 
|  | 1770 | /* Clear the hash table. */ | 
|  | 1771 | out_be32(addr_h, 0x00000000); | 
|  | 1772 | out_be32(addr_l, 0x00000000); | 
|  | 1773 |  | 
|  | 1774 | if (!p_lh) | 
|  | 1775 | return 0; | 
|  | 1776 |  | 
|  | 1777 | num = *p_counter; | 
|  | 1778 |  | 
|  | 1779 | /* Delete all remaining CQ elements */ | 
|  | 1780 | for (i = 0; i < num; i++) | 
|  | 1781 | put_enet_addr_container(ENET_ADDR_CONT_ENTRY(dequeue(p_lh))); | 
|  | 1782 |  | 
|  | 1783 | *p_counter = 0; | 
|  | 1784 |  | 
|  | 1785 | if (comm_dir) | 
|  | 1786 | ugeth_enable(ugeth, comm_dir); | 
|  | 1787 |  | 
|  | 1788 | return 0; | 
|  | 1789 | } | 
|  | 1790 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1791 | static int ugeth_82xx_filtering_clear_addr_in_paddr(struct ucc_geth_private *ugeth, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1792 | u8 paddr_num) | 
|  | 1793 | { | 
|  | 1794 | ugeth->indAddrRegUsed[paddr_num] = 0; /* mark this paddr as not used */ | 
|  | 1795 | return hw_clear_addr_in_paddr(ugeth, paddr_num);/* clear in hardware */ | 
|  | 1796 | } | 
|  | 1797 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1798 | static void ucc_geth_memclean(struct ucc_geth_private *ugeth) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1799 | { | 
|  | 1800 | u16 i, j; | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1801 | u8 __iomem *bd; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1802 |  | 
|  | 1803 | if (!ugeth) | 
|  | 1804 | return; | 
|  | 1805 |  | 
| Anton Vorontsov | 80a9fad | 2008-02-01 16:22:48 +0300 | [diff] [blame] | 1806 | if (ugeth->uccf) { | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1807 | ucc_fast_free(ugeth->uccf); | 
| Anton Vorontsov | 80a9fad | 2008-02-01 16:22:48 +0300 | [diff] [blame] | 1808 | ugeth->uccf = NULL; | 
|  | 1809 | } | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1810 |  | 
|  | 1811 | if (ugeth->p_thread_data_tx) { | 
|  | 1812 | qe_muram_free(ugeth->thread_dat_tx_offset); | 
|  | 1813 | ugeth->p_thread_data_tx = NULL; | 
|  | 1814 | } | 
|  | 1815 | if (ugeth->p_thread_data_rx) { | 
|  | 1816 | qe_muram_free(ugeth->thread_dat_rx_offset); | 
|  | 1817 | ugeth->p_thread_data_rx = NULL; | 
|  | 1818 | } | 
|  | 1819 | if (ugeth->p_exf_glbl_param) { | 
|  | 1820 | qe_muram_free(ugeth->exf_glbl_param_offset); | 
|  | 1821 | ugeth->p_exf_glbl_param = NULL; | 
|  | 1822 | } | 
|  | 1823 | if (ugeth->p_rx_glbl_pram) { | 
|  | 1824 | qe_muram_free(ugeth->rx_glbl_pram_offset); | 
|  | 1825 | ugeth->p_rx_glbl_pram = NULL; | 
|  | 1826 | } | 
|  | 1827 | if (ugeth->p_tx_glbl_pram) { | 
|  | 1828 | qe_muram_free(ugeth->tx_glbl_pram_offset); | 
|  | 1829 | ugeth->p_tx_glbl_pram = NULL; | 
|  | 1830 | } | 
|  | 1831 | if (ugeth->p_send_q_mem_reg) { | 
|  | 1832 | qe_muram_free(ugeth->send_q_mem_reg_offset); | 
|  | 1833 | ugeth->p_send_q_mem_reg = NULL; | 
|  | 1834 | } | 
|  | 1835 | if (ugeth->p_scheduler) { | 
|  | 1836 | qe_muram_free(ugeth->scheduler_offset); | 
|  | 1837 | ugeth->p_scheduler = NULL; | 
|  | 1838 | } | 
|  | 1839 | if (ugeth->p_tx_fw_statistics_pram) { | 
|  | 1840 | qe_muram_free(ugeth->tx_fw_statistics_pram_offset); | 
|  | 1841 | ugeth->p_tx_fw_statistics_pram = NULL; | 
|  | 1842 | } | 
|  | 1843 | if (ugeth->p_rx_fw_statistics_pram) { | 
|  | 1844 | qe_muram_free(ugeth->rx_fw_statistics_pram_offset); | 
|  | 1845 | ugeth->p_rx_fw_statistics_pram = NULL; | 
|  | 1846 | } | 
|  | 1847 | if (ugeth->p_rx_irq_coalescing_tbl) { | 
|  | 1848 | qe_muram_free(ugeth->rx_irq_coalescing_tbl_offset); | 
|  | 1849 | ugeth->p_rx_irq_coalescing_tbl = NULL; | 
|  | 1850 | } | 
|  | 1851 | if (ugeth->p_rx_bd_qs_tbl) { | 
|  | 1852 | qe_muram_free(ugeth->rx_bd_qs_tbl_offset); | 
|  | 1853 | ugeth->p_rx_bd_qs_tbl = NULL; | 
|  | 1854 | } | 
|  | 1855 | if (ugeth->p_init_enet_param_shadow) { | 
|  | 1856 | return_init_enet_entries(ugeth, | 
|  | 1857 | &(ugeth->p_init_enet_param_shadow-> | 
|  | 1858 | rxthread[0]), | 
|  | 1859 | ENET_INIT_PARAM_MAX_ENTRIES_RX, | 
|  | 1860 | ugeth->ug_info->riscRx, 1); | 
|  | 1861 | return_init_enet_entries(ugeth, | 
|  | 1862 | &(ugeth->p_init_enet_param_shadow-> | 
|  | 1863 | txthread[0]), | 
|  | 1864 | ENET_INIT_PARAM_MAX_ENTRIES_TX, | 
|  | 1865 | ugeth->ug_info->riscTx, 0); | 
|  | 1866 | kfree(ugeth->p_init_enet_param_shadow); | 
|  | 1867 | ugeth->p_init_enet_param_shadow = NULL; | 
|  | 1868 | } | 
|  | 1869 | for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { | 
|  | 1870 | bd = ugeth->p_tx_bd_ring[i]; | 
| Nicu Ioan Petru | 3a8205e | 2007-04-13 01:26:29 -0500 | [diff] [blame] | 1871 | if (!bd) | 
|  | 1872 | continue; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1873 | for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) { | 
|  | 1874 | if (ugeth->tx_skbuff[i][j]) { | 
| Andy Fleming | 7f80202 | 2008-05-15 17:00:21 -0500 | [diff] [blame] | 1875 | dma_unmap_single(&ugeth->dev->dev, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1876 | in_be32(&((struct qe_bd __iomem *)bd)->buf), | 
|  | 1877 | (in_be32((u32 __iomem *)bd) & | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1878 | BD_LENGTH_MASK), | 
|  | 1879 | DMA_TO_DEVICE); | 
|  | 1880 | dev_kfree_skb_any(ugeth->tx_skbuff[i][j]); | 
|  | 1881 | ugeth->tx_skbuff[i][j] = NULL; | 
|  | 1882 | } | 
|  | 1883 | } | 
|  | 1884 |  | 
|  | 1885 | kfree(ugeth->tx_skbuff[i]); | 
|  | 1886 |  | 
|  | 1887 | if (ugeth->p_tx_bd_ring[i]) { | 
|  | 1888 | if (ugeth->ug_info->uf_info.bd_mem_part == | 
|  | 1889 | MEM_PART_SYSTEM) | 
|  | 1890 | kfree((void *)ugeth->tx_bd_ring_offset[i]); | 
|  | 1891 | else if (ugeth->ug_info->uf_info.bd_mem_part == | 
|  | 1892 | MEM_PART_MURAM) | 
|  | 1893 | qe_muram_free(ugeth->tx_bd_ring_offset[i]); | 
|  | 1894 | ugeth->p_tx_bd_ring[i] = NULL; | 
|  | 1895 | } | 
|  | 1896 | } | 
|  | 1897 | for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) { | 
|  | 1898 | if (ugeth->p_rx_bd_ring[i]) { | 
|  | 1899 | /* Return existing data buffers in ring */ | 
|  | 1900 | bd = ugeth->p_rx_bd_ring[i]; | 
|  | 1901 | for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) { | 
|  | 1902 | if (ugeth->rx_skbuff[i][j]) { | 
| Andy Fleming | 7f80202 | 2008-05-15 17:00:21 -0500 | [diff] [blame] | 1903 | dma_unmap_single(&ugeth->dev->dev, | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1904 | in_be32(&((struct qe_bd __iomem *)bd)->buf), | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1905 | ugeth->ug_info-> | 
|  | 1906 | uf_info.max_rx_buf_length + | 
|  | 1907 | UCC_GETH_RX_DATA_BUF_ALIGNMENT, | 
|  | 1908 | DMA_FROM_DEVICE); | 
|  | 1909 | dev_kfree_skb_any( | 
|  | 1910 | ugeth->rx_skbuff[i][j]); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1911 | ugeth->rx_skbuff[i][j] = NULL; | 
|  | 1912 | } | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1913 | bd += sizeof(struct qe_bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1914 | } | 
|  | 1915 |  | 
|  | 1916 | kfree(ugeth->rx_skbuff[i]); | 
|  | 1917 |  | 
|  | 1918 | if (ugeth->ug_info->uf_info.bd_mem_part == | 
|  | 1919 | MEM_PART_SYSTEM) | 
|  | 1920 | kfree((void *)ugeth->rx_bd_ring_offset[i]); | 
|  | 1921 | else if (ugeth->ug_info->uf_info.bd_mem_part == | 
|  | 1922 | MEM_PART_MURAM) | 
|  | 1923 | qe_muram_free(ugeth->rx_bd_ring_offset[i]); | 
|  | 1924 | ugeth->p_rx_bd_ring[i] = NULL; | 
|  | 1925 | } | 
|  | 1926 | } | 
|  | 1927 | while (!list_empty(&ugeth->group_hash_q)) | 
|  | 1928 | put_enet_addr_container(ENET_ADDR_CONT_ENTRY | 
|  | 1929 | (dequeue(&ugeth->group_hash_q))); | 
|  | 1930 | while (!list_empty(&ugeth->ind_hash_q)) | 
|  | 1931 | put_enet_addr_container(ENET_ADDR_CONT_ENTRY | 
|  | 1932 | (dequeue(&ugeth->ind_hash_q))); | 
| Anton Vorontsov | 3e73fc9 | 2008-12-18 08:23:33 +0000 | [diff] [blame] | 1933 | if (ugeth->ug_regs) { | 
|  | 1934 | iounmap(ugeth->ug_regs); | 
|  | 1935 | ugeth->ug_regs = NULL; | 
|  | 1936 | } | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1937 | } | 
|  | 1938 |  | 
|  | 1939 | static void ucc_geth_set_multi(struct net_device *dev) | 
|  | 1940 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1941 | struct ucc_geth_private *ugeth; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1942 | struct dev_mc_list *dmi; | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1943 | struct ucc_fast __iomem *uf_regs; | 
|  | 1944 | struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt; | 
| Joakim Tjernlund | 9030b3d | 2007-10-17 11:05:41 +0200 | [diff] [blame] | 1945 | int i; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1946 |  | 
|  | 1947 | ugeth = netdev_priv(dev); | 
|  | 1948 |  | 
|  | 1949 | uf_regs = ugeth->uccf->uf_regs; | 
|  | 1950 |  | 
|  | 1951 | if (dev->flags & IFF_PROMISC) { | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1952 | setbits32(&uf_regs->upsmr, UCC_GETH_UPSMR_PRO); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1953 | } else { | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 1954 | clrbits32(&uf_regs->upsmr, UCC_GETH_UPSMR_PRO); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1955 |  | 
|  | 1956 | p_82xx_addr_filt = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1957 | (struct ucc_geth_82xx_address_filtering_pram __iomem *) ugeth-> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1958 | p_rx_glbl_pram->addressfiltering; | 
|  | 1959 |  | 
|  | 1960 | if (dev->flags & IFF_ALLMULTI) { | 
|  | 1961 | /* Catch all multicast addresses, so set the | 
|  | 1962 | * filter to all 1's. | 
|  | 1963 | */ | 
|  | 1964 | out_be32(&p_82xx_addr_filt->gaddr_h, 0xffffffff); | 
|  | 1965 | out_be32(&p_82xx_addr_filt->gaddr_l, 0xffffffff); | 
|  | 1966 | } else { | 
|  | 1967 | /* Clear filter and add the addresses in the list. | 
|  | 1968 | */ | 
|  | 1969 | out_be32(&p_82xx_addr_filt->gaddr_h, 0x0); | 
|  | 1970 | out_be32(&p_82xx_addr_filt->gaddr_l, 0x0); | 
|  | 1971 |  | 
|  | 1972 | dmi = dev->mc_list; | 
|  | 1973 |  | 
|  | 1974 | for (i = 0; i < dev->mc_count; i++, dmi = dmi->next) { | 
|  | 1975 |  | 
|  | 1976 | /* Only support group multicast for now. | 
|  | 1977 | */ | 
|  | 1978 | if (!(dmi->dmi_addr[0] & 1)) | 
|  | 1979 | continue; | 
|  | 1980 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1981 | /* Ask CPM to run CRC and set bit in | 
|  | 1982 | * filter mask. | 
|  | 1983 | */ | 
| Joakim Tjernlund | 9030b3d | 2007-10-17 11:05:41 +0200 | [diff] [blame] | 1984 | hw_add_addr_in_hash(ugeth, dmi->dmi_addr); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1985 | } | 
|  | 1986 | } | 
|  | 1987 | } | 
|  | 1988 | } | 
|  | 1989 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 1990 | static void ucc_geth_stop(struct ucc_geth_private *ugeth) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1991 | { | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 1992 | struct ucc_geth __iomem *ug_regs = ugeth->ug_regs; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 1993 | struct phy_device *phydev = ugeth->phydev; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1994 |  | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 1995 | ugeth_vdbg("%s: IN", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 1996 |  | 
|  | 1997 | /* Disable the controller */ | 
|  | 1998 | ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); | 
|  | 1999 |  | 
|  | 2000 | /* Tell the kernel the link is down */ | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 2001 | phy_stop(phydev); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2002 |  | 
|  | 2003 | /* Mask all interrupts */ | 
| Timur Tabi | c6f5047 | 2007-07-10 07:51:11 -0500 | [diff] [blame] | 2004 | out_be32(ugeth->uccf->p_uccm, 0x00000000); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2005 |  | 
|  | 2006 | /* Clear all interrupts */ | 
|  | 2007 | out_be32(ugeth->uccf->p_ucce, 0xffffffff); | 
|  | 2008 |  | 
|  | 2009 | /* Disable Rx and Tx */ | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 2010 | clrbits32(&ug_regs->maccfg1, MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2011 |  | 
| Anton Vorontsov | 7967590 | 2009-03-27 16:00:03 -0700 | [diff] [blame] | 2012 | phy_disconnect(ugeth->phydev); | 
|  | 2013 | ugeth->phydev = NULL; | 
|  | 2014 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2015 | ucc_geth_memclean(ugeth); | 
|  | 2016 | } | 
|  | 2017 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 2018 | static int ucc_struct_init(struct ucc_geth_private *ugeth) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2019 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2020 | struct ucc_geth_info *ug_info; | 
|  | 2021 | struct ucc_fast_info *uf_info; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 2022 | int i; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2023 |  | 
|  | 2024 | ug_info = ugeth->ug_info; | 
|  | 2025 | uf_info = &ug_info->uf_info; | 
|  | 2026 |  | 
|  | 2027 | if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) || | 
|  | 2028 | (uf_info->bd_mem_part == MEM_PART_MURAM))) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2029 | if (netif_msg_probe(ugeth)) | 
|  | 2030 | ugeth_err("%s: Bad memory partition value.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2031 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2032 | return -EINVAL; | 
|  | 2033 | } | 
|  | 2034 |  | 
|  | 2035 | /* Rx BD lengths */ | 
|  | 2036 | for (i = 0; i < ug_info->numQueuesRx; i++) { | 
|  | 2037 | if ((ug_info->bdRingLenRx[i] < UCC_GETH_RX_BD_RING_SIZE_MIN) || | 
|  | 2038 | (ug_info->bdRingLenRx[i] % | 
|  | 2039 | UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2040 | if (netif_msg_probe(ugeth)) | 
|  | 2041 | ugeth_err | 
|  | 2042 | ("%s: Rx BD ring length must be multiple of 4, no smaller than 8.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2043 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2044 | return -EINVAL; | 
|  | 2045 | } | 
|  | 2046 | } | 
|  | 2047 |  | 
|  | 2048 | /* Tx BD lengths */ | 
|  | 2049 | for (i = 0; i < ug_info->numQueuesTx; i++) { | 
|  | 2050 | if (ug_info->bdRingLenTx[i] < UCC_GETH_TX_BD_RING_SIZE_MIN) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2051 | if (netif_msg_probe(ugeth)) | 
|  | 2052 | ugeth_err | 
|  | 2053 | ("%s: Tx BD ring length must be no smaller than 2.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2054 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2055 | return -EINVAL; | 
|  | 2056 | } | 
|  | 2057 | } | 
|  | 2058 |  | 
|  | 2059 | /* mrblr */ | 
|  | 2060 | if ((uf_info->max_rx_buf_length == 0) || | 
|  | 2061 | (uf_info->max_rx_buf_length % UCC_GETH_MRBLR_ALIGNMENT)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2062 | if (netif_msg_probe(ugeth)) | 
|  | 2063 | ugeth_err | 
|  | 2064 | ("%s: max_rx_buf_length must be non-zero multiple of 128.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2065 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2066 | return -EINVAL; | 
|  | 2067 | } | 
|  | 2068 |  | 
|  | 2069 | /* num Tx queues */ | 
|  | 2070 | if (ug_info->numQueuesTx > NUM_TX_QUEUES) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2071 | if (netif_msg_probe(ugeth)) | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2072 | ugeth_err("%s: number of tx queues too large.", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2073 | return -EINVAL; | 
|  | 2074 | } | 
|  | 2075 |  | 
|  | 2076 | /* num Rx queues */ | 
|  | 2077 | if (ug_info->numQueuesRx > NUM_RX_QUEUES) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2078 | if (netif_msg_probe(ugeth)) | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2079 | ugeth_err("%s: number of rx queues too large.", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2080 | return -EINVAL; | 
|  | 2081 | } | 
|  | 2082 |  | 
|  | 2083 | /* l2qt */ | 
|  | 2084 | for (i = 0; i < UCC_GETH_VLAN_PRIORITY_MAX; i++) { | 
|  | 2085 | if (ug_info->l2qt[i] >= ug_info->numQueuesRx) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2086 | if (netif_msg_probe(ugeth)) | 
|  | 2087 | ugeth_err | 
|  | 2088 | ("%s: VLAN priority table entry must not be" | 
|  | 2089 | " larger than number of Rx queues.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2090 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2091 | return -EINVAL; | 
|  | 2092 | } | 
|  | 2093 | } | 
|  | 2094 |  | 
|  | 2095 | /* l3qt */ | 
|  | 2096 | for (i = 0; i < UCC_GETH_IP_PRIORITY_MAX; i++) { | 
|  | 2097 | if (ug_info->l3qt[i] >= ug_info->numQueuesRx) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2098 | if (netif_msg_probe(ugeth)) | 
|  | 2099 | ugeth_err | 
|  | 2100 | ("%s: IP priority table entry must not be" | 
|  | 2101 | " larger than number of Rx queues.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2102 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2103 | return -EINVAL; | 
|  | 2104 | } | 
|  | 2105 | } | 
|  | 2106 |  | 
|  | 2107 | if (ug_info->cam && !ug_info->ecamptr) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2108 | if (netif_msg_probe(ugeth)) | 
|  | 2109 | ugeth_err("%s: If cam mode is chosen, must supply cam ptr.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2110 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2111 | return -EINVAL; | 
|  | 2112 | } | 
|  | 2113 |  | 
|  | 2114 | if ((ug_info->numStationAddresses != | 
|  | 2115 | UCC_GETH_NUM_OF_STATION_ADDRESSES_1) | 
|  | 2116 | && ug_info->rxExtendedFiltering) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2117 | if (netif_msg_probe(ugeth)) | 
|  | 2118 | ugeth_err("%s: Number of station addresses greater than 1 " | 
|  | 2119 | "not allowed in extended parsing mode.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2120 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2121 | return -EINVAL; | 
|  | 2122 | } | 
|  | 2123 |  | 
|  | 2124 | /* Generate uccm_mask for receive */ | 
|  | 2125 | uf_info->uccm_mask = ug_info->eventRegMask & UCCE_OTHER;/* Errors */ | 
|  | 2126 | for (i = 0; i < ug_info->numQueuesRx; i++) | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 2127 | uf_info->uccm_mask |= (UCC_GETH_UCCE_RXF0 << i); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2128 |  | 
|  | 2129 | for (i = 0; i < ug_info->numQueuesTx; i++) | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 2130 | uf_info->uccm_mask |= (UCC_GETH_UCCE_TXB0 << i); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2131 | /* Initialize the general fast UCC block. */ | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 2132 | if (ucc_fast_init(uf_info, &ugeth->uccf)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2133 | if (netif_msg_probe(ugeth)) | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2134 | ugeth_err("%s: Failed to init uccf.", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2135 | return -ENOMEM; | 
|  | 2136 | } | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 2137 |  | 
| Anton Vorontsov | 3e73fc9 | 2008-12-18 08:23:33 +0000 | [diff] [blame] | 2138 | ugeth->ug_regs = ioremap(uf_info->regs, sizeof(*ugeth->ug_regs)); | 
|  | 2139 | if (!ugeth->ug_regs) { | 
|  | 2140 | if (netif_msg_probe(ugeth)) | 
|  | 2141 | ugeth_err("%s: Failed to ioremap regs.", __func__); | 
|  | 2142 | return -ENOMEM; | 
|  | 2143 | } | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 2144 |  | 
|  | 2145 | return 0; | 
|  | 2146 | } | 
|  | 2147 |  | 
|  | 2148 | static int ucc_geth_startup(struct ucc_geth_private *ugeth) | 
|  | 2149 | { | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2150 | struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt; | 
|  | 2151 | struct ucc_geth_init_pram __iomem *p_init_enet_pram; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 2152 | struct ucc_fast_private *uccf; | 
|  | 2153 | struct ucc_geth_info *ug_info; | 
|  | 2154 | struct ucc_fast_info *uf_info; | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2155 | struct ucc_fast __iomem *uf_regs; | 
|  | 2156 | struct ucc_geth __iomem *ug_regs; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 2157 | int ret_val = -EINVAL; | 
|  | 2158 | u32 remoder = UCC_GETH_REMODER_INIT; | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 2159 | u32 init_enet_pram_offset, cecr_subblock, command; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 2160 | u32 ifstat, i, j, size, l2qt, l3qt, length; | 
|  | 2161 | u16 temoder = UCC_GETH_TEMODER_INIT; | 
|  | 2162 | u16 test; | 
|  | 2163 | u8 function_code = 0; | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2164 | u8 __iomem *bd; | 
|  | 2165 | u8 __iomem *endOfRing; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 2166 | u8 numThreadsRxNumerical, numThreadsTxNumerical; | 
|  | 2167 |  | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2168 | ugeth_vdbg("%s: IN", __func__); | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 2169 | uccf = ugeth->uccf; | 
|  | 2170 | ug_info = ugeth->ug_info; | 
|  | 2171 | uf_info = &ug_info->uf_info; | 
|  | 2172 | uf_regs = uccf->uf_regs; | 
|  | 2173 | ug_regs = ugeth->ug_regs; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2174 |  | 
|  | 2175 | switch (ug_info->numThreadsRx) { | 
|  | 2176 | case UCC_GETH_NUM_OF_THREADS_1: | 
|  | 2177 | numThreadsRxNumerical = 1; | 
|  | 2178 | break; | 
|  | 2179 | case UCC_GETH_NUM_OF_THREADS_2: | 
|  | 2180 | numThreadsRxNumerical = 2; | 
|  | 2181 | break; | 
|  | 2182 | case UCC_GETH_NUM_OF_THREADS_4: | 
|  | 2183 | numThreadsRxNumerical = 4; | 
|  | 2184 | break; | 
|  | 2185 | case UCC_GETH_NUM_OF_THREADS_6: | 
|  | 2186 | numThreadsRxNumerical = 6; | 
|  | 2187 | break; | 
|  | 2188 | case UCC_GETH_NUM_OF_THREADS_8: | 
|  | 2189 | numThreadsRxNumerical = 8; | 
|  | 2190 | break; | 
|  | 2191 | default: | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2192 | if (netif_msg_ifup(ugeth)) | 
|  | 2193 | ugeth_err("%s: Bad number of Rx threads value.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2194 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2195 | return -EINVAL; | 
|  | 2196 | break; | 
|  | 2197 | } | 
|  | 2198 |  | 
|  | 2199 | switch (ug_info->numThreadsTx) { | 
|  | 2200 | case UCC_GETH_NUM_OF_THREADS_1: | 
|  | 2201 | numThreadsTxNumerical = 1; | 
|  | 2202 | break; | 
|  | 2203 | case UCC_GETH_NUM_OF_THREADS_2: | 
|  | 2204 | numThreadsTxNumerical = 2; | 
|  | 2205 | break; | 
|  | 2206 | case UCC_GETH_NUM_OF_THREADS_4: | 
|  | 2207 | numThreadsTxNumerical = 4; | 
|  | 2208 | break; | 
|  | 2209 | case UCC_GETH_NUM_OF_THREADS_6: | 
|  | 2210 | numThreadsTxNumerical = 6; | 
|  | 2211 | break; | 
|  | 2212 | case UCC_GETH_NUM_OF_THREADS_8: | 
|  | 2213 | numThreadsTxNumerical = 8; | 
|  | 2214 | break; | 
|  | 2215 | default: | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2216 | if (netif_msg_ifup(ugeth)) | 
|  | 2217 | ugeth_err("%s: Bad number of Tx threads value.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2218 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2219 | return -EINVAL; | 
|  | 2220 | break; | 
|  | 2221 | } | 
|  | 2222 |  | 
|  | 2223 | /* Calculate rx_extended_features */ | 
|  | 2224 | ugeth->rx_non_dynamic_extended_features = ug_info->ipCheckSumCheck || | 
|  | 2225 | ug_info->ipAddressAlignment || | 
|  | 2226 | (ug_info->numStationAddresses != | 
|  | 2227 | UCC_GETH_NUM_OF_STATION_ADDRESSES_1); | 
|  | 2228 |  | 
|  | 2229 | ugeth->rx_extended_features = ugeth->rx_non_dynamic_extended_features || | 
|  | 2230 | (ug_info->vlanOperationTagged != UCC_GETH_VLAN_OPERATION_TAGGED_NOP) | 
|  | 2231 | || (ug_info->vlanOperationNonTagged != | 
|  | 2232 | UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP); | 
|  | 2233 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2234 | init_default_reg_vals(&uf_regs->upsmr, | 
|  | 2235 | &ug_regs->maccfg1, &ug_regs->maccfg2); | 
|  | 2236 |  | 
|  | 2237 | /*                    Set UPSMR                      */ | 
|  | 2238 | /* For more details see the hardware spec.           */ | 
|  | 2239 | init_rx_parameters(ug_info->bro, | 
|  | 2240 | ug_info->rsh, ug_info->pro, &uf_regs->upsmr); | 
|  | 2241 |  | 
|  | 2242 | /* We're going to ignore other registers for now, */ | 
|  | 2243 | /* except as needed to get up and running         */ | 
|  | 2244 |  | 
|  | 2245 | /*                    Set MACCFG1                    */ | 
|  | 2246 | /* For more details see the hardware spec.           */ | 
|  | 2247 | init_flow_control_params(ug_info->aufc, | 
|  | 2248 | ug_info->receiveFlowControl, | 
| Li Yang | ac42185 | 2007-07-19 11:47:47 +0800 | [diff] [blame] | 2249 | ug_info->transmitFlowControl, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2250 | ug_info->pausePeriod, | 
|  | 2251 | ug_info->extensionField, | 
|  | 2252 | &uf_regs->upsmr, | 
|  | 2253 | &ug_regs->uempr, &ug_regs->maccfg1); | 
|  | 2254 |  | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 2255 | setbits32(&ug_regs->maccfg1, MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2256 |  | 
|  | 2257 | /*                    Set IPGIFG                     */ | 
|  | 2258 | /* For more details see the hardware spec.           */ | 
|  | 2259 | ret_val = init_inter_frame_gap_params(ug_info->nonBackToBackIfgPart1, | 
|  | 2260 | ug_info->nonBackToBackIfgPart2, | 
|  | 2261 | ug_info-> | 
|  | 2262 | miminumInterFrameGapEnforcement, | 
|  | 2263 | ug_info->backToBackInterFrameGap, | 
|  | 2264 | &ug_regs->ipgifg); | 
|  | 2265 | if (ret_val != 0) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2266 | if (netif_msg_ifup(ugeth)) | 
|  | 2267 | ugeth_err("%s: IPGIFG initialization parameter too large.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2268 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2269 | return ret_val; | 
|  | 2270 | } | 
|  | 2271 |  | 
|  | 2272 | /*                    Set HAFDUP                     */ | 
|  | 2273 | /* For more details see the hardware spec.           */ | 
|  | 2274 | ret_val = init_half_duplex_params(ug_info->altBeb, | 
|  | 2275 | ug_info->backPressureNoBackoff, | 
|  | 2276 | ug_info->noBackoff, | 
|  | 2277 | ug_info->excessDefer, | 
|  | 2278 | ug_info->altBebTruncation, | 
|  | 2279 | ug_info->maxRetransmission, | 
|  | 2280 | ug_info->collisionWindow, | 
|  | 2281 | &ug_regs->hafdup); | 
|  | 2282 | if (ret_val != 0) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2283 | if (netif_msg_ifup(ugeth)) | 
|  | 2284 | ugeth_err("%s: Half Duplex initialization parameter too large.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2285 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2286 | return ret_val; | 
|  | 2287 | } | 
|  | 2288 |  | 
|  | 2289 | /*                    Set IFSTAT                     */ | 
|  | 2290 | /* For more details see the hardware spec.           */ | 
|  | 2291 | /* Read only - resets upon read                      */ | 
|  | 2292 | ifstat = in_be32(&ug_regs->ifstat); | 
|  | 2293 |  | 
|  | 2294 | /*                    Clear UEMPR                    */ | 
|  | 2295 | /* For more details see the hardware spec.           */ | 
|  | 2296 | out_be32(&ug_regs->uempr, 0); | 
|  | 2297 |  | 
|  | 2298 | /*                    Set UESCR                      */ | 
|  | 2299 | /* For more details see the hardware spec.           */ | 
|  | 2300 | init_hw_statistics_gathering_mode((ug_info->statisticsMode & | 
|  | 2301 | UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE), | 
|  | 2302 | 0, &uf_regs->upsmr, &ug_regs->uescr); | 
|  | 2303 |  | 
|  | 2304 | /* Allocate Tx bds */ | 
|  | 2305 | for (j = 0; j < ug_info->numQueuesTx; j++) { | 
|  | 2306 | /* Allocate in multiple of | 
|  | 2307 | UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT, | 
|  | 2308 | according to spec */ | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2309 | length = ((ug_info->bdRingLenTx[j] * sizeof(struct qe_bd)) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2310 | / UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT) | 
|  | 2311 | * UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT; | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2312 | if ((ug_info->bdRingLenTx[j] * sizeof(struct qe_bd)) % | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2313 | UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT) | 
|  | 2314 | length += UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT; | 
|  | 2315 | if (uf_info->bd_mem_part == MEM_PART_SYSTEM) { | 
|  | 2316 | u32 align = 4; | 
|  | 2317 | if (UCC_GETH_TX_BD_RING_ALIGNMENT > 4) | 
|  | 2318 | align = UCC_GETH_TX_BD_RING_ALIGNMENT; | 
|  | 2319 | ugeth->tx_bd_ring_offset[j] = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2320 | (u32) kmalloc((u32) (length + align), GFP_KERNEL); | 
| Ahmed S. Darwish | 04b588d | 2007-01-27 00:00:02 -0800 | [diff] [blame] | 2321 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2322 | if (ugeth->tx_bd_ring_offset[j] != 0) | 
|  | 2323 | ugeth->p_tx_bd_ring[j] = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2324 | (u8 __iomem *)((ugeth->tx_bd_ring_offset[j] + | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2325 | align) & ~(align - 1)); | 
|  | 2326 | } else if (uf_info->bd_mem_part == MEM_PART_MURAM) { | 
|  | 2327 | ugeth->tx_bd_ring_offset[j] = | 
|  | 2328 | qe_muram_alloc(length, | 
|  | 2329 | UCC_GETH_TX_BD_RING_ALIGNMENT); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 2330 | if (!IS_ERR_VALUE(ugeth->tx_bd_ring_offset[j])) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2331 | ugeth->p_tx_bd_ring[j] = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2332 | (u8 __iomem *) qe_muram_addr(ugeth-> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2333 | tx_bd_ring_offset[j]); | 
|  | 2334 | } | 
|  | 2335 | if (!ugeth->p_tx_bd_ring[j]) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2336 | if (netif_msg_ifup(ugeth)) | 
|  | 2337 | ugeth_err | 
|  | 2338 | ("%s: Can not allocate memory for Tx bd rings.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2339 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2340 | return -ENOMEM; | 
|  | 2341 | } | 
|  | 2342 | /* Zero unused end of bd ring, according to spec */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2343 | memset_io((void __iomem *)(ugeth->p_tx_bd_ring[j] + | 
|  | 2344 | ug_info->bdRingLenTx[j] * sizeof(struct qe_bd)), 0, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2345 | length - ug_info->bdRingLenTx[j] * sizeof(struct qe_bd)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2346 | } | 
|  | 2347 |  | 
|  | 2348 | /* Allocate Rx bds */ | 
|  | 2349 | for (j = 0; j < ug_info->numQueuesRx; j++) { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2350 | length = ug_info->bdRingLenRx[j] * sizeof(struct qe_bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2351 | if (uf_info->bd_mem_part == MEM_PART_SYSTEM) { | 
|  | 2352 | u32 align = 4; | 
|  | 2353 | if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4) | 
|  | 2354 | align = UCC_GETH_RX_BD_RING_ALIGNMENT; | 
|  | 2355 | ugeth->rx_bd_ring_offset[j] = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2356 | (u32) kmalloc((u32) (length + align), GFP_KERNEL); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2357 | if (ugeth->rx_bd_ring_offset[j] != 0) | 
|  | 2358 | ugeth->p_rx_bd_ring[j] = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2359 | (u8 __iomem *)((ugeth->rx_bd_ring_offset[j] + | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2360 | align) & ~(align - 1)); | 
|  | 2361 | } else if (uf_info->bd_mem_part == MEM_PART_MURAM) { | 
|  | 2362 | ugeth->rx_bd_ring_offset[j] = | 
|  | 2363 | qe_muram_alloc(length, | 
|  | 2364 | UCC_GETH_RX_BD_RING_ALIGNMENT); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 2365 | if (!IS_ERR_VALUE(ugeth->rx_bd_ring_offset[j])) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2366 | ugeth->p_rx_bd_ring[j] = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2367 | (u8 __iomem *) qe_muram_addr(ugeth-> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2368 | rx_bd_ring_offset[j]); | 
|  | 2369 | } | 
|  | 2370 | if (!ugeth->p_rx_bd_ring[j]) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2371 | if (netif_msg_ifup(ugeth)) | 
|  | 2372 | ugeth_err | 
|  | 2373 | ("%s: Can not allocate memory for Rx bd rings.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2374 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2375 | return -ENOMEM; | 
|  | 2376 | } | 
|  | 2377 | } | 
|  | 2378 |  | 
|  | 2379 | /* Init Tx bds */ | 
|  | 2380 | for (j = 0; j < ug_info->numQueuesTx; j++) { | 
|  | 2381 | /* Setup the skbuff rings */ | 
| Ahmed S. Darwish | 04b588d | 2007-01-27 00:00:02 -0800 | [diff] [blame] | 2382 | ugeth->tx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) * | 
|  | 2383 | ugeth->ug_info->bdRingLenTx[j], | 
|  | 2384 | GFP_KERNEL); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2385 |  | 
|  | 2386 | if (ugeth->tx_skbuff[j] == NULL) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2387 | if (netif_msg_ifup(ugeth)) | 
|  | 2388 | ugeth_err("%s: Could not allocate tx_skbuff", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2389 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2390 | return -ENOMEM; | 
|  | 2391 | } | 
|  | 2392 |  | 
|  | 2393 | for (i = 0; i < ugeth->ug_info->bdRingLenTx[j]; i++) | 
|  | 2394 | ugeth->tx_skbuff[j][i] = NULL; | 
|  | 2395 |  | 
|  | 2396 | ugeth->skb_curtx[j] = ugeth->skb_dirtytx[j] = 0; | 
|  | 2397 | bd = ugeth->confBd[j] = ugeth->txBd[j] = ugeth->p_tx_bd_ring[j]; | 
|  | 2398 | for (i = 0; i < ug_info->bdRingLenTx[j]; i++) { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2399 | /* clear bd buffer */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2400 | out_be32(&((struct qe_bd __iomem *)bd)->buf, 0); | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2401 | /* set bd status and length */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2402 | out_be32((u32 __iomem *)bd, 0); | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2403 | bd += sizeof(struct qe_bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2404 | } | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2405 | bd -= sizeof(struct qe_bd); | 
|  | 2406 | /* set bd status and length */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2407 | out_be32((u32 __iomem *)bd, T_W); /* for last BD set Wrap bit */ | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2408 | } | 
|  | 2409 |  | 
|  | 2410 | /* Init Rx bds */ | 
|  | 2411 | for (j = 0; j < ug_info->numQueuesRx; j++) { | 
|  | 2412 | /* Setup the skbuff rings */ | 
| Ahmed S. Darwish | 04b588d | 2007-01-27 00:00:02 -0800 | [diff] [blame] | 2413 | ugeth->rx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) * | 
|  | 2414 | ugeth->ug_info->bdRingLenRx[j], | 
|  | 2415 | GFP_KERNEL); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2416 |  | 
|  | 2417 | if (ugeth->rx_skbuff[j] == NULL) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2418 | if (netif_msg_ifup(ugeth)) | 
|  | 2419 | ugeth_err("%s: Could not allocate rx_skbuff", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2420 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2421 | return -ENOMEM; | 
|  | 2422 | } | 
|  | 2423 |  | 
|  | 2424 | for (i = 0; i < ugeth->ug_info->bdRingLenRx[j]; i++) | 
|  | 2425 | ugeth->rx_skbuff[j][i] = NULL; | 
|  | 2426 |  | 
|  | 2427 | ugeth->skb_currx[j] = 0; | 
|  | 2428 | bd = ugeth->rxBd[j] = ugeth->p_rx_bd_ring[j]; | 
|  | 2429 | for (i = 0; i < ug_info->bdRingLenRx[j]; i++) { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2430 | /* set bd status and length */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2431 | out_be32((u32 __iomem *)bd, R_I); | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2432 | /* clear bd buffer */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2433 | out_be32(&((struct qe_bd __iomem *)bd)->buf, 0); | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2434 | bd += sizeof(struct qe_bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2435 | } | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2436 | bd -= sizeof(struct qe_bd); | 
|  | 2437 | /* set bd status and length */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2438 | out_be32((u32 __iomem *)bd, R_W); /* for last BD set Wrap bit */ | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2439 | } | 
|  | 2440 |  | 
|  | 2441 | /* | 
|  | 2442 | * Global PRAM | 
|  | 2443 | */ | 
|  | 2444 | /* Tx global PRAM */ | 
|  | 2445 | /* Allocate global tx parameter RAM page */ | 
|  | 2446 | ugeth->tx_glbl_pram_offset = | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2447 | qe_muram_alloc(sizeof(struct ucc_geth_tx_global_pram), | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2448 | UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 2449 | if (IS_ERR_VALUE(ugeth->tx_glbl_pram_offset)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2450 | if (netif_msg_ifup(ugeth)) | 
|  | 2451 | ugeth_err | 
|  | 2452 | ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2453 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2454 | return -ENOMEM; | 
|  | 2455 | } | 
|  | 2456 | ugeth->p_tx_glbl_pram = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2457 | (struct ucc_geth_tx_global_pram __iomem *) qe_muram_addr(ugeth-> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2458 | tx_glbl_pram_offset); | 
|  | 2459 | /* Zero out p_tx_glbl_pram */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2460 | memset_io((void __iomem *)ugeth->p_tx_glbl_pram, 0, sizeof(struct ucc_geth_tx_global_pram)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2461 |  | 
|  | 2462 | /* Fill global PRAM */ | 
|  | 2463 |  | 
|  | 2464 | /* TQPTR */ | 
|  | 2465 | /* Size varies with number of Tx threads */ | 
|  | 2466 | ugeth->thread_dat_tx_offset = | 
|  | 2467 | qe_muram_alloc(numThreadsTxNumerical * | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2468 | sizeof(struct ucc_geth_thread_data_tx) + | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2469 | 32 * (numThreadsTxNumerical == 1), | 
|  | 2470 | UCC_GETH_THREAD_DATA_ALIGNMENT); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 2471 | if (IS_ERR_VALUE(ugeth->thread_dat_tx_offset)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2472 | if (netif_msg_ifup(ugeth)) | 
|  | 2473 | ugeth_err | 
|  | 2474 | ("%s: Can not allocate DPRAM memory for p_thread_data_tx.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2475 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2476 | return -ENOMEM; | 
|  | 2477 | } | 
|  | 2478 |  | 
|  | 2479 | ugeth->p_thread_data_tx = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2480 | (struct ucc_geth_thread_data_tx __iomem *) qe_muram_addr(ugeth-> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2481 | thread_dat_tx_offset); | 
|  | 2482 | out_be32(&ugeth->p_tx_glbl_pram->tqptr, ugeth->thread_dat_tx_offset); | 
|  | 2483 |  | 
|  | 2484 | /* vtagtable */ | 
|  | 2485 | for (i = 0; i < UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX; i++) | 
|  | 2486 | out_be32(&ugeth->p_tx_glbl_pram->vtagtable[i], | 
|  | 2487 | ug_info->vtagtable[i]); | 
|  | 2488 |  | 
|  | 2489 | /* iphoffset */ | 
|  | 2490 | for (i = 0; i < TX_IP_OFFSET_ENTRY_MAX; i++) | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2491 | out_8(&ugeth->p_tx_glbl_pram->iphoffset[i], | 
|  | 2492 | ug_info->iphoffset[i]); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2493 |  | 
|  | 2494 | /* SQPTR */ | 
|  | 2495 | /* Size varies with number of Tx queues */ | 
|  | 2496 | ugeth->send_q_mem_reg_offset = | 
|  | 2497 | qe_muram_alloc(ug_info->numQueuesTx * | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2498 | sizeof(struct ucc_geth_send_queue_qd), | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2499 | UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 2500 | if (IS_ERR_VALUE(ugeth->send_q_mem_reg_offset)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2501 | if (netif_msg_ifup(ugeth)) | 
|  | 2502 | ugeth_err | 
|  | 2503 | ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2504 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2505 | return -ENOMEM; | 
|  | 2506 | } | 
|  | 2507 |  | 
|  | 2508 | ugeth->p_send_q_mem_reg = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2509 | (struct ucc_geth_send_queue_mem_region __iomem *) qe_muram_addr(ugeth-> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2510 | send_q_mem_reg_offset); | 
|  | 2511 | out_be32(&ugeth->p_tx_glbl_pram->sqptr, ugeth->send_q_mem_reg_offset); | 
|  | 2512 |  | 
|  | 2513 | /* Setup the table */ | 
|  | 2514 | /* Assume BD rings are already established */ | 
|  | 2515 | for (i = 0; i < ug_info->numQueuesTx; i++) { | 
|  | 2516 | endOfRing = | 
|  | 2517 | ugeth->p_tx_bd_ring[i] + (ug_info->bdRingLenTx[i] - | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2518 | 1) * sizeof(struct qe_bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2519 | if (ugeth->ug_info->uf_info.bd_mem_part == MEM_PART_SYSTEM) { | 
|  | 2520 | out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base, | 
|  | 2521 | (u32) virt_to_phys(ugeth->p_tx_bd_ring[i])); | 
|  | 2522 | out_be32(&ugeth->p_send_q_mem_reg->sqqd[i]. | 
|  | 2523 | last_bd_completed_address, | 
|  | 2524 | (u32) virt_to_phys(endOfRing)); | 
|  | 2525 | } else if (ugeth->ug_info->uf_info.bd_mem_part == | 
|  | 2526 | MEM_PART_MURAM) { | 
|  | 2527 | out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base, | 
|  | 2528 | (u32) immrbar_virt_to_phys(ugeth-> | 
|  | 2529 | p_tx_bd_ring[i])); | 
|  | 2530 | out_be32(&ugeth->p_send_q_mem_reg->sqqd[i]. | 
|  | 2531 | last_bd_completed_address, | 
|  | 2532 | (u32) immrbar_virt_to_phys(endOfRing)); | 
|  | 2533 | } | 
|  | 2534 | } | 
|  | 2535 |  | 
|  | 2536 | /* schedulerbasepointer */ | 
|  | 2537 |  | 
|  | 2538 | if (ug_info->numQueuesTx > 1) { | 
|  | 2539 | /* scheduler exists only if more than 1 tx queue */ | 
|  | 2540 | ugeth->scheduler_offset = | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2541 | qe_muram_alloc(sizeof(struct ucc_geth_scheduler), | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2542 | UCC_GETH_SCHEDULER_ALIGNMENT); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 2543 | if (IS_ERR_VALUE(ugeth->scheduler_offset)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2544 | if (netif_msg_ifup(ugeth)) | 
|  | 2545 | ugeth_err | 
|  | 2546 | ("%s: Can not allocate DPRAM memory for p_scheduler.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2547 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2548 | return -ENOMEM; | 
|  | 2549 | } | 
|  | 2550 |  | 
|  | 2551 | ugeth->p_scheduler = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2552 | (struct ucc_geth_scheduler __iomem *) qe_muram_addr(ugeth-> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2553 | scheduler_offset); | 
|  | 2554 | out_be32(&ugeth->p_tx_glbl_pram->schedulerbasepointer, | 
|  | 2555 | ugeth->scheduler_offset); | 
|  | 2556 | /* Zero out p_scheduler */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2557 | memset_io((void __iomem *)ugeth->p_scheduler, 0, sizeof(struct ucc_geth_scheduler)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2558 |  | 
|  | 2559 | /* Set values in scheduler */ | 
|  | 2560 | out_be32(&ugeth->p_scheduler->mblinterval, | 
|  | 2561 | ug_info->mblinterval); | 
|  | 2562 | out_be16(&ugeth->p_scheduler->nortsrbytetime, | 
|  | 2563 | ug_info->nortsrbytetime); | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2564 | out_8(&ugeth->p_scheduler->fracsiz, ug_info->fracsiz); | 
|  | 2565 | out_8(&ugeth->p_scheduler->strictpriorityq, | 
|  | 2566 | ug_info->strictpriorityq); | 
|  | 2567 | out_8(&ugeth->p_scheduler->txasap, ug_info->txasap); | 
|  | 2568 | out_8(&ugeth->p_scheduler->extrabw, ug_info->extrabw); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2569 | for (i = 0; i < NUM_TX_QUEUES; i++) | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2570 | out_8(&ugeth->p_scheduler->weightfactor[i], | 
|  | 2571 | ug_info->weightfactor[i]); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2572 |  | 
|  | 2573 | /* Set pointers to cpucount registers in scheduler */ | 
|  | 2574 | ugeth->p_cpucount[0] = &(ugeth->p_scheduler->cpucount0); | 
|  | 2575 | ugeth->p_cpucount[1] = &(ugeth->p_scheduler->cpucount1); | 
|  | 2576 | ugeth->p_cpucount[2] = &(ugeth->p_scheduler->cpucount2); | 
|  | 2577 | ugeth->p_cpucount[3] = &(ugeth->p_scheduler->cpucount3); | 
|  | 2578 | ugeth->p_cpucount[4] = &(ugeth->p_scheduler->cpucount4); | 
|  | 2579 | ugeth->p_cpucount[5] = &(ugeth->p_scheduler->cpucount5); | 
|  | 2580 | ugeth->p_cpucount[6] = &(ugeth->p_scheduler->cpucount6); | 
|  | 2581 | ugeth->p_cpucount[7] = &(ugeth->p_scheduler->cpucount7); | 
|  | 2582 | } | 
|  | 2583 |  | 
|  | 2584 | /* schedulerbasepointer */ | 
|  | 2585 | /* TxRMON_PTR (statistics) */ | 
|  | 2586 | if (ug_info-> | 
|  | 2587 | statisticsMode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) { | 
|  | 2588 | ugeth->tx_fw_statistics_pram_offset = | 
|  | 2589 | qe_muram_alloc(sizeof | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2590 | (struct ucc_geth_tx_firmware_statistics_pram), | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2591 | UCC_GETH_TX_STATISTICS_ALIGNMENT); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 2592 | if (IS_ERR_VALUE(ugeth->tx_fw_statistics_pram_offset)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2593 | if (netif_msg_ifup(ugeth)) | 
|  | 2594 | ugeth_err | 
|  | 2595 | ("%s: Can not allocate DPRAM memory for" | 
|  | 2596 | " p_tx_fw_statistics_pram.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2597 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2598 | return -ENOMEM; | 
|  | 2599 | } | 
|  | 2600 | ugeth->p_tx_fw_statistics_pram = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2601 | (struct ucc_geth_tx_firmware_statistics_pram __iomem *) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2602 | qe_muram_addr(ugeth->tx_fw_statistics_pram_offset); | 
|  | 2603 | /* Zero out p_tx_fw_statistics_pram */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2604 | memset_io((void __iomem *)ugeth->p_tx_fw_statistics_pram, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2605 | 0, sizeof(struct ucc_geth_tx_firmware_statistics_pram)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2606 | } | 
|  | 2607 |  | 
|  | 2608 | /* temoder */ | 
|  | 2609 | /* Already has speed set */ | 
|  | 2610 |  | 
|  | 2611 | if (ug_info->numQueuesTx > 1) | 
|  | 2612 | temoder |= TEMODER_SCHEDULER_ENABLE; | 
|  | 2613 | if (ug_info->ipCheckSumGenerate) | 
|  | 2614 | temoder |= TEMODER_IP_CHECKSUM_GENERATE; | 
|  | 2615 | temoder |= ((ug_info->numQueuesTx - 1) << TEMODER_NUM_OF_QUEUES_SHIFT); | 
|  | 2616 | out_be16(&ugeth->p_tx_glbl_pram->temoder, temoder); | 
|  | 2617 |  | 
|  | 2618 | test = in_be16(&ugeth->p_tx_glbl_pram->temoder); | 
|  | 2619 |  | 
|  | 2620 | /* Function code register value to be used later */ | 
| Timur Tabi | 6b0b594 | 2007-10-03 11:34:59 -0500 | [diff] [blame] | 2621 | function_code = UCC_BMR_BO_BE | UCC_BMR_GBL; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2622 | /* Required for QE */ | 
|  | 2623 |  | 
|  | 2624 | /* function code register */ | 
|  | 2625 | out_be32(&ugeth->p_tx_glbl_pram->tstate, ((u32) function_code) << 24); | 
|  | 2626 |  | 
|  | 2627 | /* Rx global PRAM */ | 
|  | 2628 | /* Allocate global rx parameter RAM page */ | 
|  | 2629 | ugeth->rx_glbl_pram_offset = | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2630 | qe_muram_alloc(sizeof(struct ucc_geth_rx_global_pram), | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2631 | UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 2632 | if (IS_ERR_VALUE(ugeth->rx_glbl_pram_offset)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2633 | if (netif_msg_ifup(ugeth)) | 
|  | 2634 | ugeth_err | 
|  | 2635 | ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2636 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2637 | return -ENOMEM; | 
|  | 2638 | } | 
|  | 2639 | ugeth->p_rx_glbl_pram = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2640 | (struct ucc_geth_rx_global_pram __iomem *) qe_muram_addr(ugeth-> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2641 | rx_glbl_pram_offset); | 
|  | 2642 | /* Zero out p_rx_glbl_pram */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2643 | memset_io((void __iomem *)ugeth->p_rx_glbl_pram, 0, sizeof(struct ucc_geth_rx_global_pram)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2644 |  | 
|  | 2645 | /* Fill global PRAM */ | 
|  | 2646 |  | 
|  | 2647 | /* RQPTR */ | 
|  | 2648 | /* Size varies with number of Rx threads */ | 
|  | 2649 | ugeth->thread_dat_rx_offset = | 
|  | 2650 | qe_muram_alloc(numThreadsRxNumerical * | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2651 | sizeof(struct ucc_geth_thread_data_rx), | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2652 | UCC_GETH_THREAD_DATA_ALIGNMENT); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 2653 | if (IS_ERR_VALUE(ugeth->thread_dat_rx_offset)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2654 | if (netif_msg_ifup(ugeth)) | 
|  | 2655 | ugeth_err | 
|  | 2656 | ("%s: Can not allocate DPRAM memory for p_thread_data_rx.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2657 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2658 | return -ENOMEM; | 
|  | 2659 | } | 
|  | 2660 |  | 
|  | 2661 | ugeth->p_thread_data_rx = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2662 | (struct ucc_geth_thread_data_rx __iomem *) qe_muram_addr(ugeth-> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2663 | thread_dat_rx_offset); | 
|  | 2664 | out_be32(&ugeth->p_rx_glbl_pram->rqptr, ugeth->thread_dat_rx_offset); | 
|  | 2665 |  | 
|  | 2666 | /* typeorlen */ | 
|  | 2667 | out_be16(&ugeth->p_rx_glbl_pram->typeorlen, ug_info->typeorlen); | 
|  | 2668 |  | 
|  | 2669 | /* rxrmonbaseptr (statistics) */ | 
|  | 2670 | if (ug_info-> | 
|  | 2671 | statisticsMode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) { | 
|  | 2672 | ugeth->rx_fw_statistics_pram_offset = | 
|  | 2673 | qe_muram_alloc(sizeof | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2674 | (struct ucc_geth_rx_firmware_statistics_pram), | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2675 | UCC_GETH_RX_STATISTICS_ALIGNMENT); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 2676 | if (IS_ERR_VALUE(ugeth->rx_fw_statistics_pram_offset)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2677 | if (netif_msg_ifup(ugeth)) | 
|  | 2678 | ugeth_err | 
|  | 2679 | ("%s: Can not allocate DPRAM memory for" | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2680 | " p_rx_fw_statistics_pram.", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2681 | return -ENOMEM; | 
|  | 2682 | } | 
|  | 2683 | ugeth->p_rx_fw_statistics_pram = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2684 | (struct ucc_geth_rx_firmware_statistics_pram __iomem *) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2685 | qe_muram_addr(ugeth->rx_fw_statistics_pram_offset); | 
|  | 2686 | /* Zero out p_rx_fw_statistics_pram */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2687 | memset_io((void __iomem *)ugeth->p_rx_fw_statistics_pram, 0, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2688 | sizeof(struct ucc_geth_rx_firmware_statistics_pram)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2689 | } | 
|  | 2690 |  | 
|  | 2691 | /* intCoalescingPtr */ | 
|  | 2692 |  | 
|  | 2693 | /* Size varies with number of Rx queues */ | 
|  | 2694 | ugeth->rx_irq_coalescing_tbl_offset = | 
|  | 2695 | qe_muram_alloc(ug_info->numQueuesRx * | 
| Michael Barkowski | 7563907 | 2007-04-13 01:26:15 -0500 | [diff] [blame] | 2696 | sizeof(struct ucc_geth_rx_interrupt_coalescing_entry) | 
|  | 2697 | + 4, UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 2698 | if (IS_ERR_VALUE(ugeth->rx_irq_coalescing_tbl_offset)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2699 | if (netif_msg_ifup(ugeth)) | 
|  | 2700 | ugeth_err | 
|  | 2701 | ("%s: Can not allocate DPRAM memory for" | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2702 | " p_rx_irq_coalescing_tbl.", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2703 | return -ENOMEM; | 
|  | 2704 | } | 
|  | 2705 |  | 
|  | 2706 | ugeth->p_rx_irq_coalescing_tbl = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2707 | (struct ucc_geth_rx_interrupt_coalescing_table __iomem *) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2708 | qe_muram_addr(ugeth->rx_irq_coalescing_tbl_offset); | 
|  | 2709 | out_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr, | 
|  | 2710 | ugeth->rx_irq_coalescing_tbl_offset); | 
|  | 2711 |  | 
|  | 2712 | /* Fill interrupt coalescing table */ | 
|  | 2713 | for (i = 0; i < ug_info->numQueuesRx; i++) { | 
|  | 2714 | out_be32(&ugeth->p_rx_irq_coalescing_tbl->coalescingentry[i]. | 
|  | 2715 | interruptcoalescingmaxvalue, | 
|  | 2716 | ug_info->interruptcoalescingmaxvalue[i]); | 
|  | 2717 | out_be32(&ugeth->p_rx_irq_coalescing_tbl->coalescingentry[i]. | 
|  | 2718 | interruptcoalescingcounter, | 
|  | 2719 | ug_info->interruptcoalescingmaxvalue[i]); | 
|  | 2720 | } | 
|  | 2721 |  | 
|  | 2722 | /* MRBLR */ | 
|  | 2723 | init_max_rx_buff_len(uf_info->max_rx_buf_length, | 
|  | 2724 | &ugeth->p_rx_glbl_pram->mrblr); | 
|  | 2725 | /* MFLR */ | 
|  | 2726 | out_be16(&ugeth->p_rx_glbl_pram->mflr, ug_info->maxFrameLength); | 
|  | 2727 | /* MINFLR */ | 
|  | 2728 | init_min_frame_len(ug_info->minFrameLength, | 
|  | 2729 | &ugeth->p_rx_glbl_pram->minflr, | 
|  | 2730 | &ugeth->p_rx_glbl_pram->mrblr); | 
|  | 2731 | /* MAXD1 */ | 
|  | 2732 | out_be16(&ugeth->p_rx_glbl_pram->maxd1, ug_info->maxD1Length); | 
|  | 2733 | /* MAXD2 */ | 
|  | 2734 | out_be16(&ugeth->p_rx_glbl_pram->maxd2, ug_info->maxD2Length); | 
|  | 2735 |  | 
|  | 2736 | /* l2qt */ | 
|  | 2737 | l2qt = 0; | 
|  | 2738 | for (i = 0; i < UCC_GETH_VLAN_PRIORITY_MAX; i++) | 
|  | 2739 | l2qt |= (ug_info->l2qt[i] << (28 - 4 * i)); | 
|  | 2740 | out_be32(&ugeth->p_rx_glbl_pram->l2qt, l2qt); | 
|  | 2741 |  | 
|  | 2742 | /* l3qt */ | 
|  | 2743 | for (j = 0; j < UCC_GETH_IP_PRIORITY_MAX; j += 8) { | 
|  | 2744 | l3qt = 0; | 
|  | 2745 | for (i = 0; i < 8; i++) | 
|  | 2746 | l3qt |= (ug_info->l3qt[j + i] << (28 - 4 * i)); | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2747 | out_be32(&ugeth->p_rx_glbl_pram->l3qt[j/8], l3qt); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2748 | } | 
|  | 2749 |  | 
|  | 2750 | /* vlantype */ | 
|  | 2751 | out_be16(&ugeth->p_rx_glbl_pram->vlantype, ug_info->vlantype); | 
|  | 2752 |  | 
|  | 2753 | /* vlantci */ | 
|  | 2754 | out_be16(&ugeth->p_rx_glbl_pram->vlantci, ug_info->vlantci); | 
|  | 2755 |  | 
|  | 2756 | /* ecamptr */ | 
|  | 2757 | out_be32(&ugeth->p_rx_glbl_pram->ecamptr, ug_info->ecamptr); | 
|  | 2758 |  | 
|  | 2759 | /* RBDQPTR */ | 
|  | 2760 | /* Size varies with number of Rx queues */ | 
|  | 2761 | ugeth->rx_bd_qs_tbl_offset = | 
|  | 2762 | qe_muram_alloc(ug_info->numQueuesRx * | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2763 | (sizeof(struct ucc_geth_rx_bd_queues_entry) + | 
|  | 2764 | sizeof(struct ucc_geth_rx_prefetched_bds)), | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2765 | UCC_GETH_RX_BD_QUEUES_ALIGNMENT); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 2766 | if (IS_ERR_VALUE(ugeth->rx_bd_qs_tbl_offset)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2767 | if (netif_msg_ifup(ugeth)) | 
|  | 2768 | ugeth_err | 
|  | 2769 | ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2770 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2771 | return -ENOMEM; | 
|  | 2772 | } | 
|  | 2773 |  | 
|  | 2774 | ugeth->p_rx_bd_qs_tbl = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2775 | (struct ucc_geth_rx_bd_queues_entry __iomem *) qe_muram_addr(ugeth-> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2776 | rx_bd_qs_tbl_offset); | 
|  | 2777 | out_be32(&ugeth->p_rx_glbl_pram->rbdqptr, ugeth->rx_bd_qs_tbl_offset); | 
|  | 2778 | /* Zero out p_rx_bd_qs_tbl */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2779 | memset_io((void __iomem *)ugeth->p_rx_bd_qs_tbl, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2780 | 0, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2781 | ug_info->numQueuesRx * (sizeof(struct ucc_geth_rx_bd_queues_entry) + | 
|  | 2782 | sizeof(struct ucc_geth_rx_prefetched_bds))); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2783 |  | 
|  | 2784 | /* Setup the table */ | 
|  | 2785 | /* Assume BD rings are already established */ | 
|  | 2786 | for (i = 0; i < ug_info->numQueuesRx; i++) { | 
|  | 2787 | if (ugeth->ug_info->uf_info.bd_mem_part == MEM_PART_SYSTEM) { | 
|  | 2788 | out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr, | 
|  | 2789 | (u32) virt_to_phys(ugeth->p_rx_bd_ring[i])); | 
|  | 2790 | } else if (ugeth->ug_info->uf_info.bd_mem_part == | 
|  | 2791 | MEM_PART_MURAM) { | 
|  | 2792 | out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr, | 
|  | 2793 | (u32) immrbar_virt_to_phys(ugeth-> | 
|  | 2794 | p_rx_bd_ring[i])); | 
|  | 2795 | } | 
|  | 2796 | /* rest of fields handled by QE */ | 
|  | 2797 | } | 
|  | 2798 |  | 
|  | 2799 | /* remoder */ | 
|  | 2800 | /* Already has speed set */ | 
|  | 2801 |  | 
|  | 2802 | if (ugeth->rx_extended_features) | 
|  | 2803 | remoder |= REMODER_RX_EXTENDED_FEATURES; | 
|  | 2804 | if (ug_info->rxExtendedFiltering) | 
|  | 2805 | remoder |= REMODER_RX_EXTENDED_FILTERING; | 
|  | 2806 | if (ug_info->dynamicMaxFrameLength) | 
|  | 2807 | remoder |= REMODER_DYNAMIC_MAX_FRAME_LENGTH; | 
|  | 2808 | if (ug_info->dynamicMinFrameLength) | 
|  | 2809 | remoder |= REMODER_DYNAMIC_MIN_FRAME_LENGTH; | 
|  | 2810 | remoder |= | 
|  | 2811 | ug_info->vlanOperationTagged << REMODER_VLAN_OPERATION_TAGGED_SHIFT; | 
|  | 2812 | remoder |= | 
|  | 2813 | ug_info-> | 
|  | 2814 | vlanOperationNonTagged << REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT; | 
|  | 2815 | remoder |= ug_info->rxQoSMode << REMODER_RX_QOS_MODE_SHIFT; | 
|  | 2816 | remoder |= ((ug_info->numQueuesRx - 1) << REMODER_NUM_OF_QUEUES_SHIFT); | 
|  | 2817 | if (ug_info->ipCheckSumCheck) | 
|  | 2818 | remoder |= REMODER_IP_CHECKSUM_CHECK; | 
|  | 2819 | if (ug_info->ipAddressAlignment) | 
|  | 2820 | remoder |= REMODER_IP_ADDRESS_ALIGNMENT; | 
|  | 2821 | out_be32(&ugeth->p_rx_glbl_pram->remoder, remoder); | 
|  | 2822 |  | 
|  | 2823 | /* Note that this function must be called */ | 
|  | 2824 | /* ONLY AFTER p_tx_fw_statistics_pram */ | 
|  | 2825 | /* andp_UccGethRxFirmwareStatisticsPram are allocated ! */ | 
|  | 2826 | init_firmware_statistics_gathering_mode((ug_info-> | 
|  | 2827 | statisticsMode & | 
|  | 2828 | UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX), | 
|  | 2829 | (ug_info->statisticsMode & | 
|  | 2830 | UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX), | 
|  | 2831 | &ugeth->p_tx_glbl_pram->txrmonbaseptr, | 
|  | 2832 | ugeth->tx_fw_statistics_pram_offset, | 
|  | 2833 | &ugeth->p_rx_glbl_pram->rxrmonbaseptr, | 
|  | 2834 | ugeth->rx_fw_statistics_pram_offset, | 
|  | 2835 | &ugeth->p_tx_glbl_pram->temoder, | 
|  | 2836 | &ugeth->p_rx_glbl_pram->remoder); | 
|  | 2837 |  | 
|  | 2838 | /* function code register */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2839 | out_8(&ugeth->p_rx_glbl_pram->rstate, function_code); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2840 |  | 
|  | 2841 | /* initialize extended filtering */ | 
|  | 2842 | if (ug_info->rxExtendedFiltering) { | 
|  | 2843 | if (!ug_info->extendedFilteringChainPointer) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2844 | if (netif_msg_ifup(ugeth)) | 
|  | 2845 | ugeth_err("%s: Null Extended Filtering Chain Pointer.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2846 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2847 | return -EINVAL; | 
|  | 2848 | } | 
|  | 2849 |  | 
|  | 2850 | /* Allocate memory for extended filtering Mode Global | 
|  | 2851 | Parameters */ | 
|  | 2852 | ugeth->exf_glbl_param_offset = | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2853 | qe_muram_alloc(sizeof(struct ucc_geth_exf_global_pram), | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2854 | UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 2855 | if (IS_ERR_VALUE(ugeth->exf_glbl_param_offset)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2856 | if (netif_msg_ifup(ugeth)) | 
|  | 2857 | ugeth_err | 
|  | 2858 | ("%s: Can not allocate DPRAM memory for" | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2859 | " p_exf_glbl_param.", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2860 | return -ENOMEM; | 
|  | 2861 | } | 
|  | 2862 |  | 
|  | 2863 | ugeth->p_exf_glbl_param = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2864 | (struct ucc_geth_exf_global_pram __iomem *) qe_muram_addr(ugeth-> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2865 | exf_glbl_param_offset); | 
|  | 2866 | out_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam, | 
|  | 2867 | ugeth->exf_glbl_param_offset); | 
|  | 2868 | out_be32(&ugeth->p_exf_glbl_param->l2pcdptr, | 
|  | 2869 | (u32) ug_info->extendedFilteringChainPointer); | 
|  | 2870 |  | 
|  | 2871 | } else {		/* initialize 82xx style address filtering */ | 
|  | 2872 |  | 
|  | 2873 | /* Init individual address recognition registers to disabled */ | 
|  | 2874 |  | 
|  | 2875 | for (j = 0; j < NUM_OF_PADDRS; j++) | 
|  | 2876 | ugeth_82xx_filtering_clear_addr_in_paddr(ugeth, (u8) j); | 
|  | 2877 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2878 | p_82xx_addr_filt = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 2879 | (struct ucc_geth_82xx_address_filtering_pram __iomem *) ugeth-> | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2880 | p_rx_glbl_pram->addressfiltering; | 
|  | 2881 |  | 
|  | 2882 | ugeth_82xx_filtering_clear_all_addr_in_hash(ugeth, | 
|  | 2883 | ENET_ADDR_TYPE_GROUP); | 
|  | 2884 | ugeth_82xx_filtering_clear_all_addr_in_hash(ugeth, | 
|  | 2885 | ENET_ADDR_TYPE_INDIVIDUAL); | 
|  | 2886 | } | 
|  | 2887 |  | 
|  | 2888 | /* | 
|  | 2889 | * Initialize UCC at QE level | 
|  | 2890 | */ | 
|  | 2891 |  | 
|  | 2892 | command = QE_INIT_TX_RX; | 
|  | 2893 |  | 
|  | 2894 | /* Allocate shadow InitEnet command parameter structure. | 
|  | 2895 | * This is needed because after the InitEnet command is executed, | 
|  | 2896 | * the structure in DPRAM is released, because DPRAM is a premium | 
|  | 2897 | * resource. | 
|  | 2898 | * This shadow structure keeps a copy of what was done so that the | 
|  | 2899 | * allocated resources can be released when the channel is freed. | 
|  | 2900 | */ | 
|  | 2901 | if (!(ugeth->p_init_enet_param_shadow = | 
| Ahmed S. Darwish | 04b588d | 2007-01-27 00:00:02 -0800 | [diff] [blame] | 2902 | kmalloc(sizeof(struct ucc_geth_init_pram), GFP_KERNEL))) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2903 | if (netif_msg_ifup(ugeth)) | 
|  | 2904 | ugeth_err | 
|  | 2905 | ("%s: Can not allocate memory for" | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2906 | " p_UccInitEnetParamShadows.", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2907 | return -ENOMEM; | 
|  | 2908 | } | 
|  | 2909 | /* Zero out *p_init_enet_param_shadow */ | 
|  | 2910 | memset((char *)ugeth->p_init_enet_param_shadow, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2911 | 0, sizeof(struct ucc_geth_init_pram)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2912 |  | 
|  | 2913 | /* Fill shadow InitEnet command parameter structure */ | 
|  | 2914 |  | 
|  | 2915 | ugeth->p_init_enet_param_shadow->resinit1 = | 
|  | 2916 | ENET_INIT_PARAM_MAGIC_RES_INIT1; | 
|  | 2917 | ugeth->p_init_enet_param_shadow->resinit2 = | 
|  | 2918 | ENET_INIT_PARAM_MAGIC_RES_INIT2; | 
|  | 2919 | ugeth->p_init_enet_param_shadow->resinit3 = | 
|  | 2920 | ENET_INIT_PARAM_MAGIC_RES_INIT3; | 
|  | 2921 | ugeth->p_init_enet_param_shadow->resinit4 = | 
|  | 2922 | ENET_INIT_PARAM_MAGIC_RES_INIT4; | 
|  | 2923 | ugeth->p_init_enet_param_shadow->resinit5 = | 
|  | 2924 | ENET_INIT_PARAM_MAGIC_RES_INIT5; | 
|  | 2925 | ugeth->p_init_enet_param_shadow->rgftgfrxglobal |= | 
|  | 2926 | ((u32) ug_info->numThreadsRx) << ENET_INIT_PARAM_RGF_SHIFT; | 
|  | 2927 | ugeth->p_init_enet_param_shadow->rgftgfrxglobal |= | 
|  | 2928 | ((u32) ug_info->numThreadsTx) << ENET_INIT_PARAM_TGF_SHIFT; | 
|  | 2929 |  | 
|  | 2930 | ugeth->p_init_enet_param_shadow->rgftgfrxglobal |= | 
|  | 2931 | ugeth->rx_glbl_pram_offset | ug_info->riscRx; | 
|  | 2932 | if ((ug_info->largestexternallookupkeysize != | 
|  | 2933 | QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE) | 
|  | 2934 | && (ug_info->largestexternallookupkeysize != | 
|  | 2935 | QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES) | 
|  | 2936 | && (ug_info->largestexternallookupkeysize != | 
|  | 2937 | QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2938 | if (netif_msg_ifup(ugeth)) | 
|  | 2939 | ugeth_err("%s: Invalid largest External Lookup Key Size.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2940 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2941 | return -EINVAL; | 
|  | 2942 | } | 
|  | 2943 | ugeth->p_init_enet_param_shadow->largestexternallookupkeysize = | 
|  | 2944 | ug_info->largestexternallookupkeysize; | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2945 | size = sizeof(struct ucc_geth_thread_rx_pram); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2946 | if (ug_info->rxExtendedFiltering) { | 
|  | 2947 | size += THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING; | 
|  | 2948 | if (ug_info->largestexternallookupkeysize == | 
|  | 2949 | QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES) | 
|  | 2950 | size += | 
|  | 2951 | THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8; | 
|  | 2952 | if (ug_info->largestexternallookupkeysize == | 
|  | 2953 | QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES) | 
|  | 2954 | size += | 
|  | 2955 | THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16; | 
|  | 2956 | } | 
|  | 2957 |  | 
|  | 2958 | if ((ret_val = fill_init_enet_entries(ugeth, &(ugeth-> | 
|  | 2959 | p_init_enet_param_shadow->rxthread[0]), | 
|  | 2960 | (u8) (numThreadsRxNumerical + 1) | 
|  | 2961 | /* Rx needs one extra for terminator */ | 
|  | 2962 | , size, UCC_GETH_THREAD_RX_PRAM_ALIGNMENT, | 
|  | 2963 | ug_info->riscRx, 1)) != 0) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2964 | if (netif_msg_ifup(ugeth)) | 
|  | 2965 | ugeth_err("%s: Can not fill p_init_enet_param_shadow.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2966 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2967 | return ret_val; | 
|  | 2968 | } | 
|  | 2969 |  | 
|  | 2970 | ugeth->p_init_enet_param_shadow->txglobal = | 
|  | 2971 | ugeth->tx_glbl_pram_offset | ug_info->riscTx; | 
|  | 2972 | if ((ret_val = | 
|  | 2973 | fill_init_enet_entries(ugeth, | 
|  | 2974 | &(ugeth->p_init_enet_param_shadow-> | 
|  | 2975 | txthread[0]), numThreadsTxNumerical, | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2976 | sizeof(struct ucc_geth_thread_tx_pram), | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2977 | UCC_GETH_THREAD_TX_PRAM_ALIGNMENT, | 
|  | 2978 | ug_info->riscTx, 0)) != 0) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2979 | if (netif_msg_ifup(ugeth)) | 
|  | 2980 | ugeth_err("%s: Can not fill p_init_enet_param_shadow.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2981 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2982 | return ret_val; | 
|  | 2983 | } | 
|  | 2984 |  | 
|  | 2985 | /* Load Rx bds with buffers */ | 
|  | 2986 | for (i = 0; i < ug_info->numQueuesRx; i++) { | 
|  | 2987 | if ((ret_val = rx_bd_buffer_set(ugeth, (u8) i)) != 0) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2988 | if (netif_msg_ifup(ugeth)) | 
|  | 2989 | ugeth_err("%s: Can not fill Rx bds with buffers.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 2990 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 2991 | return ret_val; | 
|  | 2992 | } | 
|  | 2993 | } | 
|  | 2994 |  | 
|  | 2995 | /* Allocate InitEnet command parameter structure */ | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 2996 | init_enet_pram_offset = qe_muram_alloc(sizeof(struct ucc_geth_init_pram), 4); | 
| Timur Tabi | 4c35630 | 2007-05-08 14:46:36 -0500 | [diff] [blame] | 2997 | if (IS_ERR_VALUE(init_enet_pram_offset)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 2998 | if (netif_msg_ifup(ugeth)) | 
|  | 2999 | ugeth_err | 
|  | 3000 | ("%s: Can not allocate DPRAM memory for p_init_enet_pram.", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 3001 | __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3002 | return -ENOMEM; | 
|  | 3003 | } | 
|  | 3004 | p_init_enet_pram = | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 3005 | (struct ucc_geth_init_pram __iomem *) qe_muram_addr(init_enet_pram_offset); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3006 |  | 
|  | 3007 | /* Copy shadow InitEnet command parameter structure into PRAM */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 3008 | out_8(&p_init_enet_pram->resinit1, | 
|  | 3009 | ugeth->p_init_enet_param_shadow->resinit1); | 
|  | 3010 | out_8(&p_init_enet_pram->resinit2, | 
|  | 3011 | ugeth->p_init_enet_param_shadow->resinit2); | 
|  | 3012 | out_8(&p_init_enet_pram->resinit3, | 
|  | 3013 | ugeth->p_init_enet_param_shadow->resinit3); | 
|  | 3014 | out_8(&p_init_enet_pram->resinit4, | 
|  | 3015 | ugeth->p_init_enet_param_shadow->resinit4); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3016 | out_be16(&p_init_enet_pram->resinit5, | 
|  | 3017 | ugeth->p_init_enet_param_shadow->resinit5); | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 3018 | out_8(&p_init_enet_pram->largestexternallookupkeysize, | 
|  | 3019 | ugeth->p_init_enet_param_shadow->largestexternallookupkeysize); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3020 | out_be32(&p_init_enet_pram->rgftgfrxglobal, | 
|  | 3021 | ugeth->p_init_enet_param_shadow->rgftgfrxglobal); | 
|  | 3022 | for (i = 0; i < ENET_INIT_PARAM_MAX_ENTRIES_RX; i++) | 
|  | 3023 | out_be32(&p_init_enet_pram->rxthread[i], | 
|  | 3024 | ugeth->p_init_enet_param_shadow->rxthread[i]); | 
|  | 3025 | out_be32(&p_init_enet_pram->txglobal, | 
|  | 3026 | ugeth->p_init_enet_param_shadow->txglobal); | 
|  | 3027 | for (i = 0; i < ENET_INIT_PARAM_MAX_ENTRIES_TX; i++) | 
|  | 3028 | out_be32(&p_init_enet_pram->txthread[i], | 
|  | 3029 | ugeth->p_init_enet_param_shadow->txthread[i]); | 
|  | 3030 |  | 
|  | 3031 | /* Issue QE command */ | 
|  | 3032 | cecr_subblock = | 
|  | 3033 | ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3034 | qe_issue_cmd(command, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3035 | init_enet_pram_offset); | 
|  | 3036 |  | 
|  | 3037 | /* Free InitEnet command parameter */ | 
|  | 3038 | qe_muram_free(init_enet_pram_offset); | 
|  | 3039 |  | 
|  | 3040 | return 0; | 
|  | 3041 | } | 
|  | 3042 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3043 | /* This is called by the kernel when a frame is ready for transmission. */ | 
|  | 3044 | /* It is pointed to by the dev->hard_start_xmit function pointer */ | 
|  | 3045 | static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) | 
|  | 3046 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3047 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 
| Michael Reiss | d5b9049 | 2007-04-13 01:26:19 -0500 | [diff] [blame] | 3048 | #ifdef CONFIG_UGETH_TX_ON_DEMAND | 
|  | 3049 | struct ucc_fast_private *uccf; | 
|  | 3050 | #endif | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 3051 | u8 __iomem *bd;			/* BD pointer */ | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3052 | u32 bd_status; | 
|  | 3053 | u8 txQ = 0; | 
|  | 3054 |  | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 3055 | ugeth_vdbg("%s: IN", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3056 |  | 
|  | 3057 | spin_lock_irq(&ugeth->lock); | 
|  | 3058 |  | 
| Jeff Garzik | 09f75cd | 2007-10-03 17:41:50 -0700 | [diff] [blame] | 3059 | dev->stats.tx_bytes += skb->len; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3060 |  | 
|  | 3061 | /* Start from the next BD that should be filled */ | 
|  | 3062 | bd = ugeth->txBd[txQ]; | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 3063 | bd_status = in_be32((u32 __iomem *)bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3064 | /* Save the skb pointer so we can free it later */ | 
|  | 3065 | ugeth->tx_skbuff[txQ][ugeth->skb_curtx[txQ]] = skb; | 
|  | 3066 |  | 
|  | 3067 | /* Update the current skb pointer (wrapping if this was the last) */ | 
|  | 3068 | ugeth->skb_curtx[txQ] = | 
|  | 3069 | (ugeth->skb_curtx[txQ] + | 
|  | 3070 | 1) & TX_RING_MOD_MASK(ugeth->ug_info->bdRingLenTx[txQ]); | 
|  | 3071 |  | 
|  | 3072 | /* set up the buffer descriptor */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 3073 | out_be32(&((struct qe_bd __iomem *)bd)->buf, | 
| Andy Fleming | 7f80202 | 2008-05-15 17:00:21 -0500 | [diff] [blame] | 3074 | dma_map_single(&ugeth->dev->dev, skb->data, | 
|  | 3075 | skb->len, DMA_TO_DEVICE)); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3076 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3077 | /* printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data); */ | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3078 |  | 
|  | 3079 | bd_status = (bd_status & T_W) | T_R | T_I | T_L | skb->len; | 
|  | 3080 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3081 | /* set bd status and length */ | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 3082 | out_be32((u32 __iomem *)bd, bd_status); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3083 |  | 
|  | 3084 | dev->trans_start = jiffies; | 
|  | 3085 |  | 
|  | 3086 | /* Move to next BD in the ring */ | 
|  | 3087 | if (!(bd_status & T_W)) | 
| Li Yang | a394f01 | 2007-03-06 16:53:46 +0800 | [diff] [blame] | 3088 | bd += sizeof(struct qe_bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3089 | else | 
| Li Yang | a394f01 | 2007-03-06 16:53:46 +0800 | [diff] [blame] | 3090 | bd = ugeth->p_tx_bd_ring[txQ]; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3091 |  | 
|  | 3092 | /* If the next BD still needs to be cleaned up, then the bds | 
|  | 3093 | are full.  We need to tell the kernel to stop sending us stuff. */ | 
|  | 3094 | if (bd == ugeth->confBd[txQ]) { | 
|  | 3095 | if (!netif_queue_stopped(dev)) | 
|  | 3096 | netif_stop_queue(dev); | 
|  | 3097 | } | 
|  | 3098 |  | 
| Li Yang | a394f01 | 2007-03-06 16:53:46 +0800 | [diff] [blame] | 3099 | ugeth->txBd[txQ] = bd; | 
|  | 3100 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3101 | if (ugeth->p_scheduler) { | 
|  | 3102 | ugeth->cpucount[txQ]++; | 
|  | 3103 | /* Indicate to QE that there are more Tx bds ready for | 
|  | 3104 | transmission */ | 
|  | 3105 | /* This is done by writing a running counter of the bd | 
|  | 3106 | count to the scheduler PRAM. */ | 
|  | 3107 | out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]); | 
|  | 3108 | } | 
|  | 3109 |  | 
| Michael Reiss | d5b9049 | 2007-04-13 01:26:19 -0500 | [diff] [blame] | 3110 | #ifdef CONFIG_UGETH_TX_ON_DEMAND | 
|  | 3111 | uccf = ugeth->uccf; | 
|  | 3112 | out_be16(uccf->p_utodr, UCC_FAST_TOD); | 
|  | 3113 | #endif | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3114 | spin_unlock_irq(&ugeth->lock); | 
|  | 3115 |  | 
| Li Yang | 6f6881b | 2007-03-19 11:58:02 +0800 | [diff] [blame] | 3116 | return 0; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3117 | } | 
|  | 3118 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3119 | static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3120 | { | 
|  | 3121 | struct sk_buff *skb; | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 3122 | u8 __iomem *bd; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3123 | u16 length, howmany = 0; | 
|  | 3124 | u32 bd_status; | 
|  | 3125 | u8 *bdBuffer; | 
| Andrew Morton | 4b8fdef | 2007-12-13 16:02:55 -0800 | [diff] [blame] | 3126 | struct net_device *dev; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3127 |  | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 3128 | ugeth_vdbg("%s: IN", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3129 |  | 
| Emil Medve | 88a15f2 | 2007-10-15 08:43:50 -0500 | [diff] [blame] | 3130 | dev = ugeth->dev; | 
|  | 3131 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3132 | /* collect received buffers */ | 
|  | 3133 | bd = ugeth->rxBd[rxQ]; | 
|  | 3134 |  | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 3135 | bd_status = in_be32((u32 __iomem *)bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3136 |  | 
|  | 3137 | /* while there are received buffers and BD is full (~R_E) */ | 
|  | 3138 | while (!((bd_status & (R_E)) || (--rx_work_limit < 0))) { | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 3139 | bdBuffer = (u8 *) in_be32(&((struct qe_bd __iomem *)bd)->buf); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3140 | length = (u16) ((bd_status & BD_LENGTH_MASK) - 4); | 
|  | 3141 | skb = ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]]; | 
|  | 3142 |  | 
|  | 3143 | /* determine whether buffer is first, last, first and last | 
|  | 3144 | (single buffer frame) or middle (not first and not last) */ | 
|  | 3145 | if (!skb || | 
|  | 3146 | (!(bd_status & (R_F | R_L))) || | 
|  | 3147 | (bd_status & R_ERRORS_FATAL)) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 3148 | if (netif_msg_rx_err(ugeth)) | 
|  | 3149 | ugeth_err("%s, %d: ERROR!!! skb - 0x%08x", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 3150 | __func__, __LINE__, (u32) skb); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3151 | if (skb) | 
|  | 3152 | dev_kfree_skb_any(skb); | 
|  | 3153 |  | 
|  | 3154 | ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL; | 
| Jeff Garzik | 09f75cd | 2007-10-03 17:41:50 -0700 | [diff] [blame] | 3155 | dev->stats.rx_dropped++; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3156 | } else { | 
| Jeff Garzik | 09f75cd | 2007-10-03 17:41:50 -0700 | [diff] [blame] | 3157 | dev->stats.rx_packets++; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3158 | howmany++; | 
|  | 3159 |  | 
|  | 3160 | /* Prep the skb for the packet */ | 
|  | 3161 | skb_put(skb, length); | 
|  | 3162 |  | 
|  | 3163 | /* Tell the skb what kind of packet this is */ | 
|  | 3164 | skb->protocol = eth_type_trans(skb, ugeth->dev); | 
|  | 3165 |  | 
| Jeff Garzik | 09f75cd | 2007-10-03 17:41:50 -0700 | [diff] [blame] | 3166 | dev->stats.rx_bytes += length; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3167 | /* Send the packet up the stack */ | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3168 | netif_receive_skb(skb); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3169 | } | 
|  | 3170 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3171 | skb = get_new_skb(ugeth, bd); | 
|  | 3172 | if (!skb) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 3173 | if (netif_msg_rx_err(ugeth)) | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 3174 | ugeth_warn("%s: No Rx Data Buffer", __func__); | 
| Jeff Garzik | 09f75cd | 2007-10-03 17:41:50 -0700 | [diff] [blame] | 3175 | dev->stats.rx_dropped++; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3176 | break; | 
|  | 3177 | } | 
|  | 3178 |  | 
|  | 3179 | ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = skb; | 
|  | 3180 |  | 
|  | 3181 | /* update to point at the next skb */ | 
|  | 3182 | ugeth->skb_currx[rxQ] = | 
|  | 3183 | (ugeth->skb_currx[rxQ] + | 
|  | 3184 | 1) & RX_RING_MOD_MASK(ugeth->ug_info->bdRingLenRx[rxQ]); | 
|  | 3185 |  | 
|  | 3186 | if (bd_status & R_W) | 
|  | 3187 | bd = ugeth->p_rx_bd_ring[rxQ]; | 
|  | 3188 | else | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3189 | bd += sizeof(struct qe_bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3190 |  | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 3191 | bd_status = in_be32((u32 __iomem *)bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3192 | } | 
|  | 3193 |  | 
|  | 3194 | ugeth->rxBd[rxQ] = bd; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3195 | return howmany; | 
|  | 3196 | } | 
|  | 3197 |  | 
|  | 3198 | static int ucc_geth_tx(struct net_device *dev, u8 txQ) | 
|  | 3199 | { | 
|  | 3200 | /* Start from the next BD that should be filled */ | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3201 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 3202 | u8 __iomem *bd;		/* BD pointer */ | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3203 | u32 bd_status; | 
|  | 3204 |  | 
|  | 3205 | bd = ugeth->confBd[txQ]; | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 3206 | bd_status = in_be32((u32 __iomem *)bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3207 |  | 
|  | 3208 | /* Normal processing. */ | 
|  | 3209 | while ((bd_status & T_R) == 0) { | 
|  | 3210 | /* BD contains already transmitted buffer.   */ | 
|  | 3211 | /* Handle the transmitted buffer and release */ | 
|  | 3212 | /* the BD to be used with the current frame  */ | 
|  | 3213 |  | 
| Li Yang | a394f01 | 2007-03-06 16:53:46 +0800 | [diff] [blame] | 3214 | if ((bd == ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0)) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3215 | break; | 
|  | 3216 |  | 
| Jeff Garzik | 09f75cd | 2007-10-03 17:41:50 -0700 | [diff] [blame] | 3217 | dev->stats.tx_packets++; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3218 |  | 
|  | 3219 | /* Free the sk buffer associated with this TxBD */ | 
|  | 3220 | dev_kfree_skb_irq(ugeth-> | 
|  | 3221 | tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]); | 
|  | 3222 | ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL; | 
|  | 3223 | ugeth->skb_dirtytx[txQ] = | 
|  | 3224 | (ugeth->skb_dirtytx[txQ] + | 
|  | 3225 | 1) & TX_RING_MOD_MASK(ugeth->ug_info->bdRingLenTx[txQ]); | 
|  | 3226 |  | 
|  | 3227 | /* We freed a buffer, so now we can restart transmission */ | 
|  | 3228 | if (netif_queue_stopped(dev)) | 
|  | 3229 | netif_wake_queue(dev); | 
|  | 3230 |  | 
|  | 3231 | /* Advance the confirmation BD pointer */ | 
|  | 3232 | if (!(bd_status & T_W)) | 
| Li Yang | a394f01 | 2007-03-06 16:53:46 +0800 | [diff] [blame] | 3233 | bd += sizeof(struct qe_bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3234 | else | 
| Li Yang | a394f01 | 2007-03-06 16:53:46 +0800 | [diff] [blame] | 3235 | bd = ugeth->p_tx_bd_ring[txQ]; | 
| Andy Fleming | 6fee40e | 2008-05-02 13:01:23 -0500 | [diff] [blame] | 3236 | bd_status = in_be32((u32 __iomem *)bd); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3237 | } | 
| Li Yang | a394f01 | 2007-03-06 16:53:46 +0800 | [diff] [blame] | 3238 | ugeth->confBd[txQ] = bd; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3239 | return 0; | 
|  | 3240 | } | 
|  | 3241 |  | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3242 | static int ucc_geth_poll(struct napi_struct *napi, int budget) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3243 | { | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3244 | struct ucc_geth_private *ugeth = container_of(napi, struct ucc_geth_private, napi); | 
| Michael Reiss | 702ff12 | 2007-04-13 01:26:11 -0500 | [diff] [blame] | 3245 | struct ucc_geth_info *ug_info; | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3246 | int howmany, i; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3247 |  | 
| Michael Reiss | 702ff12 | 2007-04-13 01:26:11 -0500 | [diff] [blame] | 3248 | ug_info = ugeth->ug_info; | 
|  | 3249 |  | 
| Michael Reiss | 702ff12 | 2007-04-13 01:26:11 -0500 | [diff] [blame] | 3250 | howmany = 0; | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3251 | for (i = 0; i < ug_info->numQueuesRx; i++) | 
|  | 3252 | howmany += ucc_geth_rx(ugeth, i, budget - howmany); | 
| Michael Reiss | 702ff12 | 2007-04-13 01:26:11 -0500 | [diff] [blame] | 3253 |  | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3254 | if (howmany < budget) { | 
| Ben Hutchings | 288379f | 2009-01-19 16:43:59 -0800 | [diff] [blame] | 3255 | napi_complete(napi); | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 3256 | setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS); | 
| Michael Reiss | 702ff12 | 2007-04-13 01:26:11 -0500 | [diff] [blame] | 3257 | } | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3258 |  | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3259 | return howmany; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3260 | } | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3261 |  | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 3262 | static irqreturn_t ucc_geth_irq_handler(int irq, void *info) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3263 | { | 
| Jeff Garzik | 06efcad | 2007-10-19 03:10:11 -0400 | [diff] [blame] | 3264 | struct net_device *dev = info; | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3265 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 
|  | 3266 | struct ucc_fast_private *uccf; | 
|  | 3267 | struct ucc_geth_info *ug_info; | 
| Michael Reiss | 702ff12 | 2007-04-13 01:26:11 -0500 | [diff] [blame] | 3268 | register u32 ucce; | 
|  | 3269 | register u32 uccm; | 
| Michael Reiss | 702ff12 | 2007-04-13 01:26:11 -0500 | [diff] [blame] | 3270 | register u32 tx_mask; | 
|  | 3271 | u8 i; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3272 |  | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 3273 | ugeth_vdbg("%s: IN", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3274 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3275 | uccf = ugeth->uccf; | 
|  | 3276 | ug_info = ugeth->ug_info; | 
|  | 3277 |  | 
| Michael Reiss | 702ff12 | 2007-04-13 01:26:11 -0500 | [diff] [blame] | 3278 | /* read and clear events */ | 
|  | 3279 | ucce = (u32) in_be32(uccf->p_ucce); | 
|  | 3280 | uccm = (u32) in_be32(uccf->p_uccm); | 
|  | 3281 | ucce &= uccm; | 
|  | 3282 | out_be32(uccf->p_ucce, ucce); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3283 |  | 
| Michael Reiss | 702ff12 | 2007-04-13 01:26:11 -0500 | [diff] [blame] | 3284 | /* check for receive events that require processing */ | 
|  | 3285 | if (ucce & UCCE_RX_EVENTS) { | 
| Ben Hutchings | 288379f | 2009-01-19 16:43:59 -0800 | [diff] [blame] | 3286 | if (napi_schedule_prep(&ugeth->napi)) { | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3287 | uccm &= ~UCCE_RX_EVENTS; | 
| Michael Reiss | 702ff12 | 2007-04-13 01:26:11 -0500 | [diff] [blame] | 3288 | out_be32(uccf->p_uccm, uccm); | 
| Ben Hutchings | 288379f | 2009-01-19 16:43:59 -0800 | [diff] [blame] | 3289 | __napi_schedule(&ugeth->napi); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3290 | } | 
| Michael Reiss | 702ff12 | 2007-04-13 01:26:11 -0500 | [diff] [blame] | 3291 | } | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3292 |  | 
| Michael Reiss | 702ff12 | 2007-04-13 01:26:11 -0500 | [diff] [blame] | 3293 | /* Tx event processing */ | 
|  | 3294 | if (ucce & UCCE_TX_EVENTS) { | 
|  | 3295 | spin_lock(&ugeth->lock); | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 3296 | tx_mask = UCC_GETH_UCCE_TXB0; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3297 | for (i = 0; i < ug_info->numQueuesTx; i++) { | 
|  | 3298 | if (ucce & tx_mask) | 
|  | 3299 | ucc_geth_tx(dev, i); | 
|  | 3300 | ucce &= ~tx_mask; | 
|  | 3301 | tx_mask <<= 1; | 
|  | 3302 | } | 
| Michael Reiss | 702ff12 | 2007-04-13 01:26:11 -0500 | [diff] [blame] | 3303 | spin_unlock(&ugeth->lock); | 
|  | 3304 | } | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3305 |  | 
| Michael Reiss | 702ff12 | 2007-04-13 01:26:11 -0500 | [diff] [blame] | 3306 | /* Errors and other events */ | 
|  | 3307 | if (ucce & UCCE_OTHER) { | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 3308 | if (ucce & UCC_GETH_UCCE_BSY) | 
| Jeff Garzik | 09f75cd | 2007-10-03 17:41:50 -0700 | [diff] [blame] | 3309 | dev->stats.rx_errors++; | 
| Timur Tabi | 3bc5342 | 2009-01-11 00:25:21 -0800 | [diff] [blame] | 3310 | if (ucce & UCC_GETH_UCCE_TXE) | 
| Jeff Garzik | 09f75cd | 2007-10-03 17:41:50 -0700 | [diff] [blame] | 3311 | dev->stats.tx_errors++; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3312 | } | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3313 |  | 
|  | 3314 | return IRQ_HANDLED; | 
|  | 3315 | } | 
|  | 3316 |  | 
| Anton Vorontsov | 26d29ea | 2008-02-01 16:22:54 +0300 | [diff] [blame] | 3317 | #ifdef CONFIG_NET_POLL_CONTROLLER | 
|  | 3318 | /* | 
|  | 3319 | * Polling 'interrupt' - used by things like netconsole to send skbs | 
|  | 3320 | * without having to re-enable interrupts. It's not called while | 
|  | 3321 | * the interrupt routine is executing. | 
|  | 3322 | */ | 
|  | 3323 | static void ucc_netpoll(struct net_device *dev) | 
|  | 3324 | { | 
|  | 3325 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 
|  | 3326 | int irq = ugeth->ug_info->uf_info.irq; | 
|  | 3327 |  | 
|  | 3328 | disable_irq(irq); | 
|  | 3329 | ucc_geth_irq_handler(irq, dev); | 
|  | 3330 | enable_irq(irq); | 
|  | 3331 | } | 
|  | 3332 | #endif /* CONFIG_NET_POLL_CONTROLLER */ | 
|  | 3333 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3334 | /* Called when something needs to use the ethernet device */ | 
|  | 3335 | /* Returns 0 for success. */ | 
|  | 3336 | static int ucc_geth_open(struct net_device *dev) | 
|  | 3337 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3338 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3339 | int err; | 
|  | 3340 |  | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 3341 | ugeth_vdbg("%s: IN", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3342 |  | 
|  | 3343 | /* Test station address */ | 
|  | 3344 | if (dev->dev_addr[0] & ENET_GROUP_ADDR) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 3345 | if (netif_msg_ifup(ugeth)) | 
|  | 3346 | ugeth_err("%s: Multicast address used for station address" | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 3347 | " - is this what you wanted?", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3348 | return -EINVAL; | 
|  | 3349 | } | 
|  | 3350 |  | 
| Anton Vorontsov | 7967590 | 2009-03-27 16:00:03 -0700 | [diff] [blame] | 3351 | err = init_phy(dev); | 
|  | 3352 | if (err) { | 
|  | 3353 | if (netif_msg_ifup(ugeth)) | 
|  | 3354 | ugeth_err("%s: Cannot initialize PHY, aborting.", | 
|  | 3355 | dev->name); | 
|  | 3356 | return err; | 
|  | 3357 | } | 
|  | 3358 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3359 | err = ucc_struct_init(ugeth); | 
|  | 3360 | if (err) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 3361 | if (netif_msg_ifup(ugeth)) | 
|  | 3362 | ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name); | 
| Anton Vorontsov | 3e73fc9 | 2008-12-18 08:23:33 +0000 | [diff] [blame] | 3363 | goto out_err_stop; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3364 | } | 
|  | 3365 |  | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3366 | napi_enable(&ugeth->napi); | 
| Francois Romieu | 1a342d2 | 2008-07-11 00:34:40 +0200 | [diff] [blame] | 3367 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3368 | err = ucc_geth_startup(ugeth); | 
|  | 3369 | if (err) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 3370 | if (netif_msg_ifup(ugeth)) | 
|  | 3371 | ugeth_err("%s: Cannot configure net device, aborting.", | 
|  | 3372 | dev->name); | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3373 | goto out_err; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3374 | } | 
|  | 3375 |  | 
|  | 3376 | err = adjust_enet_interface(ugeth); | 
|  | 3377 | if (err) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 3378 | if (netif_msg_ifup(ugeth)) | 
|  | 3379 | ugeth_err("%s: Cannot configure net device, aborting.", | 
|  | 3380 | dev->name); | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3381 | goto out_err; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3382 | } | 
|  | 3383 |  | 
|  | 3384 | /*       Set MACSTNADDR1, MACSTNADDR2                */ | 
|  | 3385 | /* For more details see the hardware spec.           */ | 
|  | 3386 | init_mac_station_addr_regs(dev->dev_addr[0], | 
|  | 3387 | dev->dev_addr[1], | 
|  | 3388 | dev->dev_addr[2], | 
|  | 3389 | dev->dev_addr[3], | 
|  | 3390 | dev->dev_addr[4], | 
|  | 3391 | dev->dev_addr[5], | 
|  | 3392 | &ugeth->ug_regs->macstnaddr1, | 
|  | 3393 | &ugeth->ug_regs->macstnaddr2); | 
|  | 3394 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3395 | phy_start(ugeth->phydev); | 
|  | 3396 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3397 | err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); | 
|  | 3398 | if (err) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 3399 | if (netif_msg_ifup(ugeth)) | 
|  | 3400 | ugeth_err("%s: Cannot enable net device, aborting.", dev->name); | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3401 | goto out_err; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3402 | } | 
|  | 3403 |  | 
| Anton Vorontsov | 67c2fb8 | 2008-12-18 08:23:29 +0000 | [diff] [blame] | 3404 | err = request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, | 
|  | 3405 | 0, "UCC Geth", dev); | 
|  | 3406 | if (err) { | 
|  | 3407 | if (netif_msg_ifup(ugeth)) | 
|  | 3408 | ugeth_err("%s: Cannot get IRQ for net device, aborting.", | 
|  | 3409 | dev->name); | 
| Anton Vorontsov | 67c2fb8 | 2008-12-18 08:23:29 +0000 | [diff] [blame] | 3410 | goto out_err; | 
|  | 3411 | } | 
|  | 3412 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3413 | netif_start_queue(dev); | 
|  | 3414 |  | 
|  | 3415 | return err; | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3416 |  | 
|  | 3417 | out_err: | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3418 | napi_disable(&ugeth->napi); | 
| Anton Vorontsov | 3e73fc9 | 2008-12-18 08:23:33 +0000 | [diff] [blame] | 3419 | out_err_stop: | 
| Anton Vorontsov | ba57469 | 2008-12-18 08:23:31 +0000 | [diff] [blame] | 3420 | ucc_geth_stop(ugeth); | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3421 | return err; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3422 | } | 
|  | 3423 |  | 
|  | 3424 | /* Stops the kernel queue, and halts the controller */ | 
|  | 3425 | static int ucc_geth_close(struct net_device *dev) | 
|  | 3426 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3427 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3428 |  | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 3429 | ugeth_vdbg("%s: IN", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3430 |  | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3431 | napi_disable(&ugeth->napi); | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3432 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3433 | ucc_geth_stop(ugeth); | 
|  | 3434 |  | 
| Anton Vorontsov | 67c2fb8 | 2008-12-18 08:23:29 +0000 | [diff] [blame] | 3435 | free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); | 
|  | 3436 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3437 | netif_stop_queue(dev); | 
|  | 3438 |  | 
|  | 3439 | return 0; | 
|  | 3440 | } | 
|  | 3441 |  | 
| Anton Vorontsov | fdb614c | 2008-12-23 06:59:25 +0000 | [diff] [blame] | 3442 | /* Reopen device. This will reset the MAC and PHY. */ | 
|  | 3443 | static void ucc_geth_timeout_work(struct work_struct *work) | 
|  | 3444 | { | 
|  | 3445 | struct ucc_geth_private *ugeth; | 
|  | 3446 | struct net_device *dev; | 
|  | 3447 |  | 
|  | 3448 | ugeth = container_of(work, struct ucc_geth_private, timeout_work); | 
|  | 3449 | dev = ugeth->dev; | 
|  | 3450 |  | 
|  | 3451 | ugeth_vdbg("%s: IN", __func__); | 
|  | 3452 |  | 
|  | 3453 | dev->stats.tx_errors++; | 
|  | 3454 |  | 
|  | 3455 | ugeth_dump_regs(ugeth); | 
|  | 3456 |  | 
|  | 3457 | if (dev->flags & IFF_UP) { | 
|  | 3458 | /* | 
|  | 3459 | * Must reset MAC *and* PHY. This is done by reopening | 
|  | 3460 | * the device. | 
|  | 3461 | */ | 
|  | 3462 | ucc_geth_close(dev); | 
|  | 3463 | ucc_geth_open(dev); | 
|  | 3464 | } | 
|  | 3465 |  | 
|  | 3466 | netif_tx_schedule_all(dev); | 
|  | 3467 | } | 
|  | 3468 |  | 
|  | 3469 | /* | 
|  | 3470 | * ucc_geth_timeout gets called when a packet has not been | 
|  | 3471 | * transmitted after a set amount of time. | 
|  | 3472 | */ | 
|  | 3473 | static void ucc_geth_timeout(struct net_device *dev) | 
|  | 3474 | { | 
|  | 3475 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 
|  | 3476 |  | 
|  | 3477 | netif_carrier_off(dev); | 
|  | 3478 | schedule_work(&ugeth->timeout_work); | 
|  | 3479 | } | 
|  | 3480 |  | 
| Kim Phillips | 4e19b5c | 2007-05-11 18:25:07 -0500 | [diff] [blame] | 3481 | static phy_interface_t to_phy_interface(const char *phy_connection_type) | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3482 | { | 
| Kim Phillips | 4e19b5c | 2007-05-11 18:25:07 -0500 | [diff] [blame] | 3483 | if (strcasecmp(phy_connection_type, "mii") == 0) | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3484 | return PHY_INTERFACE_MODE_MII; | 
| Kim Phillips | 4e19b5c | 2007-05-11 18:25:07 -0500 | [diff] [blame] | 3485 | if (strcasecmp(phy_connection_type, "gmii") == 0) | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3486 | return PHY_INTERFACE_MODE_GMII; | 
| Kim Phillips | 4e19b5c | 2007-05-11 18:25:07 -0500 | [diff] [blame] | 3487 | if (strcasecmp(phy_connection_type, "tbi") == 0) | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3488 | return PHY_INTERFACE_MODE_TBI; | 
| Kim Phillips | 4e19b5c | 2007-05-11 18:25:07 -0500 | [diff] [blame] | 3489 | if (strcasecmp(phy_connection_type, "rmii") == 0) | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3490 | return PHY_INTERFACE_MODE_RMII; | 
| Kim Phillips | 4e19b5c | 2007-05-11 18:25:07 -0500 | [diff] [blame] | 3491 | if (strcasecmp(phy_connection_type, "rgmii") == 0) | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3492 | return PHY_INTERFACE_MODE_RGMII; | 
| Kim Phillips | 4e19b5c | 2007-05-11 18:25:07 -0500 | [diff] [blame] | 3493 | if (strcasecmp(phy_connection_type, "rgmii-id") == 0) | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3494 | return PHY_INTERFACE_MODE_RGMII_ID; | 
| Kim Phillips | bd0ceaa | 2007-11-26 16:17:58 -0600 | [diff] [blame] | 3495 | if (strcasecmp(phy_connection_type, "rgmii-txid") == 0) | 
|  | 3496 | return PHY_INTERFACE_MODE_RGMII_TXID; | 
|  | 3497 | if (strcasecmp(phy_connection_type, "rgmii-rxid") == 0) | 
|  | 3498 | return PHY_INTERFACE_MODE_RGMII_RXID; | 
| Kim Phillips | 4e19b5c | 2007-05-11 18:25:07 -0500 | [diff] [blame] | 3499 | if (strcasecmp(phy_connection_type, "rtbi") == 0) | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3500 | return PHY_INTERFACE_MODE_RTBI; | 
|  | 3501 |  | 
|  | 3502 | return PHY_INTERFACE_MODE_MII; | 
|  | 3503 | } | 
|  | 3504 |  | 
| Joakim Tjernlund | a9dbae7 | 2009-03-20 21:09:14 +0100 | [diff] [blame] | 3505 | static const struct net_device_ops ucc_geth_netdev_ops = { | 
|  | 3506 | .ndo_open		= ucc_geth_open, | 
|  | 3507 | .ndo_stop		= ucc_geth_close, | 
|  | 3508 | .ndo_start_xmit		= ucc_geth_start_xmit, | 
|  | 3509 | .ndo_validate_addr	= eth_validate_addr, | 
|  | 3510 | .ndo_set_mac_address	= eth_mac_addr, | 
|  | 3511 | .ndo_change_mtu		= eth_change_mtu, | 
|  | 3512 | .ndo_set_multicast_list	= ucc_geth_set_multi, | 
|  | 3513 | .ndo_tx_timeout		= ucc_geth_timeout, | 
|  | 3514 | #ifdef CONFIG_NET_POLL_CONTROLLER | 
|  | 3515 | .ndo_poll_controller	= ucc_netpoll, | 
|  | 3516 | #endif | 
|  | 3517 | }; | 
|  | 3518 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3519 | static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3520 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3521 | struct device *device = &ofdev->dev; | 
|  | 3522 | struct device_node *np = ofdev->node; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3523 | struct device_node *mdio; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3524 | struct net_device *dev = NULL; | 
|  | 3525 | struct ucc_geth_private *ugeth = NULL; | 
|  | 3526 | struct ucc_geth_info *ug_info; | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3527 | struct resource res; | 
|  | 3528 | struct device_node *phy; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3529 | int err, ucc_num, max_speed = 0; | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3530 | const phandle *ph; | 
| Joakim Tjernlund | 3d137fd | 2008-04-11 00:54:43 +0200 | [diff] [blame] | 3531 | const u32 *fixed_link; | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3532 | const unsigned int *prop; | 
| Timur Tabi | 9fb1e35 | 2007-12-03 15:17:59 -0600 | [diff] [blame] | 3533 | const char *sprop; | 
| Li Yang | 9b4c7a4 | 2007-02-08 17:35:54 +0800 | [diff] [blame] | 3534 | const void *mac_addr; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3535 | phy_interface_t phy_interface; | 
|  | 3536 | static const int enet_to_speed[] = { | 
|  | 3537 | SPEED_10, SPEED_10, SPEED_10, | 
|  | 3538 | SPEED_100, SPEED_100, SPEED_100, | 
|  | 3539 | SPEED_1000, SPEED_1000, SPEED_1000, SPEED_1000, | 
|  | 3540 | }; | 
|  | 3541 | static const phy_interface_t enet_to_phy_interface[] = { | 
|  | 3542 | PHY_INTERFACE_MODE_MII, PHY_INTERFACE_MODE_RMII, | 
|  | 3543 | PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_MII, | 
|  | 3544 | PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII, | 
|  | 3545 | PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII, | 
|  | 3546 | PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI, | 
|  | 3547 | }; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3548 |  | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 3549 | ugeth_vdbg("%s: IN", __func__); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3550 |  | 
| Anton Vorontsov | 56626f3 | 2008-04-11 20:06:54 +0400 | [diff] [blame] | 3551 | prop = of_get_property(np, "cell-index", NULL); | 
|  | 3552 | if (!prop) { | 
|  | 3553 | prop = of_get_property(np, "device-id", NULL); | 
|  | 3554 | if (!prop) | 
|  | 3555 | return -ENODEV; | 
|  | 3556 | } | 
|  | 3557 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3558 | ucc_num = *prop - 1; | 
|  | 3559 | if ((ucc_num < 0) || (ucc_num > 7)) | 
|  | 3560 | return -ENODEV; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3561 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3562 | ug_info = &ugeth_info[ucc_num]; | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 3563 | if (ug_info == NULL) { | 
|  | 3564 | if (netif_msg_probe(&debug)) | 
|  | 3565 | ugeth_err("%s: [%d] Missing additional data!", | 
| Harvey Harrison | b39d66a | 2008-08-20 16:52:04 -0700 | [diff] [blame] | 3566 | __func__, ucc_num); | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 3567 | return -ENODEV; | 
|  | 3568 | } | 
|  | 3569 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3570 | ug_info->uf_info.ucc_num = ucc_num; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3571 |  | 
| Timur Tabi | 9fb1e35 | 2007-12-03 15:17:59 -0600 | [diff] [blame] | 3572 | sprop = of_get_property(np, "rx-clock-name", NULL); | 
|  | 3573 | if (sprop) { | 
|  | 3574 | ug_info->uf_info.rx_clock = qe_clock_source(sprop); | 
|  | 3575 | if ((ug_info->uf_info.rx_clock < QE_CLK_NONE) || | 
|  | 3576 | (ug_info->uf_info.rx_clock > QE_CLK24)) { | 
|  | 3577 | printk(KERN_ERR | 
|  | 3578 | "ucc_geth: invalid rx-clock-name property\n"); | 
|  | 3579 | return -EINVAL; | 
|  | 3580 | } | 
|  | 3581 | } else { | 
|  | 3582 | prop = of_get_property(np, "rx-clock", NULL); | 
|  | 3583 | if (!prop) { | 
|  | 3584 | /* If both rx-clock-name and rx-clock are missing, | 
|  | 3585 | we want to tell people to use rx-clock-name. */ | 
|  | 3586 | printk(KERN_ERR | 
|  | 3587 | "ucc_geth: missing rx-clock-name property\n"); | 
|  | 3588 | return -EINVAL; | 
|  | 3589 | } | 
|  | 3590 | if ((*prop < QE_CLK_NONE) || (*prop > QE_CLK24)) { | 
|  | 3591 | printk(KERN_ERR | 
|  | 3592 | "ucc_geth: invalid rx-clock propperty\n"); | 
|  | 3593 | return -EINVAL; | 
|  | 3594 | } | 
|  | 3595 | ug_info->uf_info.rx_clock = *prop; | 
|  | 3596 | } | 
|  | 3597 |  | 
|  | 3598 | sprop = of_get_property(np, "tx-clock-name", NULL); | 
|  | 3599 | if (sprop) { | 
|  | 3600 | ug_info->uf_info.tx_clock = qe_clock_source(sprop); | 
|  | 3601 | if ((ug_info->uf_info.tx_clock < QE_CLK_NONE) || | 
|  | 3602 | (ug_info->uf_info.tx_clock > QE_CLK24)) { | 
|  | 3603 | printk(KERN_ERR | 
|  | 3604 | "ucc_geth: invalid tx-clock-name property\n"); | 
|  | 3605 | return -EINVAL; | 
|  | 3606 | } | 
|  | 3607 | } else { | 
| Joakim Tjernlund | e410553 | 2008-04-29 13:03:57 +0200 | [diff] [blame] | 3608 | prop = of_get_property(np, "tx-clock", NULL); | 
| Timur Tabi | 9fb1e35 | 2007-12-03 15:17:59 -0600 | [diff] [blame] | 3609 | if (!prop) { | 
|  | 3610 | printk(KERN_ERR | 
|  | 3611 | "ucc_geth: mising tx-clock-name property\n"); | 
|  | 3612 | return -EINVAL; | 
|  | 3613 | } | 
|  | 3614 | if ((*prop < QE_CLK_NONE) || (*prop > QE_CLK24)) { | 
|  | 3615 | printk(KERN_ERR | 
|  | 3616 | "ucc_geth: invalid tx-clock property\n"); | 
|  | 3617 | return -EINVAL; | 
|  | 3618 | } | 
|  | 3619 | ug_info->uf_info.tx_clock = *prop; | 
|  | 3620 | } | 
|  | 3621 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3622 | err = of_address_to_resource(np, 0, &res); | 
|  | 3623 | if (err) | 
|  | 3624 | return -EINVAL; | 
|  | 3625 |  | 
|  | 3626 | ug_info->uf_info.regs = res.start; | 
|  | 3627 | ug_info->uf_info.irq = irq_of_parse_and_map(np, 0); | 
| Joakim Tjernlund | 3d137fd | 2008-04-11 00:54:43 +0200 | [diff] [blame] | 3628 | fixed_link = of_get_property(np, "fixed-link", NULL); | 
|  | 3629 | if (fixed_link) { | 
| Anton Vorontsov | 61fa9dc | 2009-03-22 21:30:52 -0700 | [diff] [blame] | 3630 | snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id), | 
|  | 3631 | PHY_ID_FMT, "0", fixed_link[0]); | 
| Joakim Tjernlund | 3d137fd | 2008-04-11 00:54:43 +0200 | [diff] [blame] | 3632 | phy = NULL; | 
|  | 3633 | } else { | 
| Anton Vorontsov | 61fa9dc | 2009-03-22 21:30:52 -0700 | [diff] [blame] | 3634 | char bus_name[MII_BUS_ID_SIZE]; | 
|  | 3635 |  | 
| Joakim Tjernlund | 3d137fd | 2008-04-11 00:54:43 +0200 | [diff] [blame] | 3636 | ph = of_get_property(np, "phy-handle", NULL); | 
|  | 3637 | phy = of_find_node_by_phandle(*ph); | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3638 |  | 
| Joakim Tjernlund | 3d137fd | 2008-04-11 00:54:43 +0200 | [diff] [blame] | 3639 | if (phy == NULL) | 
|  | 3640 | return -ENODEV; | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3641 |  | 
| Joakim Tjernlund | 3d137fd | 2008-04-11 00:54:43 +0200 | [diff] [blame] | 3642 | /* set the PHY address */ | 
|  | 3643 | prop = of_get_property(phy, "reg", NULL); | 
|  | 3644 | if (prop == NULL) | 
|  | 3645 | return -1; | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3646 |  | 
| Joakim Tjernlund | 3d137fd | 2008-04-11 00:54:43 +0200 | [diff] [blame] | 3647 | /* Set the bus id */ | 
|  | 3648 | mdio = of_get_parent(phy); | 
|  | 3649 |  | 
|  | 3650 | if (mdio == NULL) | 
|  | 3651 | return -1; | 
|  | 3652 |  | 
|  | 3653 | err = of_address_to_resource(mdio, 0, &res); | 
|  | 3654 | of_node_put(mdio); | 
|  | 3655 |  | 
|  | 3656 | if (err) | 
|  | 3657 | return -1; | 
|  | 3658 |  | 
| Anton Vorontsov | bb4f92b | 2009-03-24 12:06:46 -0700 | [diff] [blame] | 3659 | fsl_pq_mdio_bus_name(bus_name, mdio); | 
| Anton Vorontsov | 61fa9dc | 2009-03-22 21:30:52 -0700 | [diff] [blame] | 3660 | snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id), | 
|  | 3661 | "%s:%02x", bus_name, *prop); | 
| Joakim Tjernlund | 3d137fd | 2008-04-11 00:54:43 +0200 | [diff] [blame] | 3662 | } | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3663 |  | 
|  | 3664 | /* get the phy interface type, or default to MII */ | 
| Kim Phillips | 4e19b5c | 2007-05-11 18:25:07 -0500 | [diff] [blame] | 3665 | prop = of_get_property(np, "phy-connection-type", NULL); | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3666 | if (!prop) { | 
|  | 3667 | /* handle interface property present in old trees */ | 
| Stephen Rothwell | 40cd3a4 | 2007-05-01 13:54:02 +1000 | [diff] [blame] | 3668 | prop = of_get_property(phy, "interface", NULL); | 
| Kim Phillips | 4e19b5c | 2007-05-11 18:25:07 -0500 | [diff] [blame] | 3669 | if (prop != NULL) { | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3670 | phy_interface = enet_to_phy_interface[*prop]; | 
| Kim Phillips | 4e19b5c | 2007-05-11 18:25:07 -0500 | [diff] [blame] | 3671 | max_speed = enet_to_speed[*prop]; | 
|  | 3672 | } else | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3673 | phy_interface = PHY_INTERFACE_MODE_MII; | 
|  | 3674 | } else { | 
|  | 3675 | phy_interface = to_phy_interface((const char *)prop); | 
|  | 3676 | } | 
|  | 3677 |  | 
| Kim Phillips | 4e19b5c | 2007-05-11 18:25:07 -0500 | [diff] [blame] | 3678 | /* get speed, or derive from PHY interface */ | 
|  | 3679 | if (max_speed == 0) | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3680 | switch (phy_interface) { | 
|  | 3681 | case PHY_INTERFACE_MODE_GMII: | 
|  | 3682 | case PHY_INTERFACE_MODE_RGMII: | 
|  | 3683 | case PHY_INTERFACE_MODE_RGMII_ID: | 
| Kim Phillips | bd0ceaa | 2007-11-26 16:17:58 -0600 | [diff] [blame] | 3684 | case PHY_INTERFACE_MODE_RGMII_RXID: | 
|  | 3685 | case PHY_INTERFACE_MODE_RGMII_TXID: | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3686 | case PHY_INTERFACE_MODE_TBI: | 
|  | 3687 | case PHY_INTERFACE_MODE_RTBI: | 
|  | 3688 | max_speed = SPEED_1000; | 
|  | 3689 | break; | 
|  | 3690 | default: | 
|  | 3691 | max_speed = SPEED_100; | 
|  | 3692 | break; | 
|  | 3693 | } | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3694 |  | 
|  | 3695 | if (max_speed == SPEED_1000) { | 
| Kim Phillips | 4e19b5c | 2007-05-11 18:25:07 -0500 | [diff] [blame] | 3696 | /* configure muram FIFOs for gigabit operation */ | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3697 | ug_info->uf_info.urfs = UCC_GETH_URFS_GIGA_INIT; | 
|  | 3698 | ug_info->uf_info.urfet = UCC_GETH_URFET_GIGA_INIT; | 
|  | 3699 | ug_info->uf_info.urfset = UCC_GETH_URFSET_GIGA_INIT; | 
|  | 3700 | ug_info->uf_info.utfs = UCC_GETH_UTFS_GIGA_INIT; | 
|  | 3701 | ug_info->uf_info.utfet = UCC_GETH_UTFET_GIGA_INIT; | 
|  | 3702 | ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT; | 
| Joakim Tjernlund | ffea31e | 2008-03-06 18:48:46 +0800 | [diff] [blame] | 3703 | ug_info->numThreadsTx = UCC_GETH_NUM_OF_THREADS_4; | 
|  | 3704 | ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_4; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3705 | } | 
|  | 3706 |  | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 3707 | if (netif_msg_probe(&debug)) | 
|  | 3708 | printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n", | 
|  | 3709 | ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs, | 
|  | 3710 | ug_info->uf_info.irq); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3711 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3712 | /* Create an ethernet device instance */ | 
|  | 3713 | dev = alloc_etherdev(sizeof(*ugeth)); | 
|  | 3714 |  | 
|  | 3715 | if (dev == NULL) | 
|  | 3716 | return -ENOMEM; | 
|  | 3717 |  | 
|  | 3718 | ugeth = netdev_priv(dev); | 
|  | 3719 | spin_lock_init(&ugeth->lock); | 
|  | 3720 |  | 
| Anton Vorontsov | 80a9fad | 2008-02-01 16:22:48 +0300 | [diff] [blame] | 3721 | /* Create CQs for hash tables */ | 
|  | 3722 | INIT_LIST_HEAD(&ugeth->group_hash_q); | 
|  | 3723 | INIT_LIST_HEAD(&ugeth->ind_hash_q); | 
|  | 3724 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3725 | dev_set_drvdata(device, dev); | 
|  | 3726 |  | 
|  | 3727 | /* Set the dev->base_addr to the gfar reg region */ | 
|  | 3728 | dev->base_addr = (unsigned long)(ug_info->uf_info.regs); | 
|  | 3729 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3730 | SET_NETDEV_DEV(dev, device); | 
|  | 3731 |  | 
|  | 3732 | /* Fill in the dev structure */ | 
| Li Yang | ac42185 | 2007-07-19 11:47:47 +0800 | [diff] [blame] | 3733 | uec_set_ethtool_ops(dev); | 
| Joakim Tjernlund | a9dbae7 | 2009-03-20 21:09:14 +0100 | [diff] [blame] | 3734 | dev->netdev_ops = &ucc_geth_netdev_ops; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3735 | dev->watchdog_timeo = TX_TIMEOUT; | 
| Anton Vorontsov | 1762a29 | 2008-12-18 08:23:26 +0000 | [diff] [blame] | 3736 | INIT_WORK(&ugeth->timeout_work, ucc_geth_timeout_work); | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 3737 | netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3738 | dev->mtu = 1500; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3739 |  | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 3740 | ugeth->msg_enable = netif_msg_init(debug.msg_enable, UGETH_MSG_DEFAULT); | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3741 | ugeth->phy_interface = phy_interface; | 
|  | 3742 | ugeth->max_speed = max_speed; | 
|  | 3743 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3744 | err = register_netdev(dev); | 
|  | 3745 | if (err) { | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 3746 | if (netif_msg_probe(ugeth)) | 
|  | 3747 | ugeth_err("%s: Cannot register net device, aborting.", | 
|  | 3748 | dev->name); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3749 | free_netdev(dev); | 
|  | 3750 | return err; | 
|  | 3751 | } | 
|  | 3752 |  | 
| Timur Tabi | e9eb70c | 2007-02-21 14:40:12 -0600 | [diff] [blame] | 3753 | mac_addr = of_get_mac_address(np); | 
| Li Yang | 9b4c7a4 | 2007-02-08 17:35:54 +0800 | [diff] [blame] | 3754 | if (mac_addr) | 
|  | 3755 | memcpy(dev->dev_addr, mac_addr, 6); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3756 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3757 | ugeth->ug_info = ug_info; | 
|  | 3758 | ugeth->dev = dev; | 
| Haiying Wang | b1c4a9d | 2009-01-29 17:28:04 -0800 | [diff] [blame] | 3759 | ugeth->node = np; | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3760 |  | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3761 | return 0; | 
|  | 3762 | } | 
|  | 3763 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3764 | static int ucc_geth_remove(struct of_device* ofdev) | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3765 | { | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3766 | struct device *device = &ofdev->dev; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3767 | struct net_device *dev = dev_get_drvdata(device); | 
|  | 3768 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 
|  | 3769 |  | 
| Anton Vorontsov | 80a9fad | 2008-02-01 16:22:48 +0300 | [diff] [blame] | 3770 | unregister_netdev(dev); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3771 | free_netdev(dev); | 
| Anton Vorontsov | 80a9fad | 2008-02-01 16:22:48 +0300 | [diff] [blame] | 3772 | ucc_geth_memclean(ugeth); | 
|  | 3773 | dev_set_drvdata(device, NULL); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3774 |  | 
|  | 3775 | return 0; | 
|  | 3776 | } | 
|  | 3777 |  | 
| Li Yang | 18a8e86 | 2006-10-19 21:07:34 -0500 | [diff] [blame] | 3778 | static struct of_device_id ucc_geth_match[] = { | 
|  | 3779 | { | 
|  | 3780 | .type = "network", | 
|  | 3781 | .compatible = "ucc_geth", | 
|  | 3782 | }, | 
|  | 3783 | {}, | 
|  | 3784 | }; | 
|  | 3785 |  | 
|  | 3786 | MODULE_DEVICE_TABLE(of, ucc_geth_match); | 
|  | 3787 |  | 
|  | 3788 | static struct of_platform_driver ucc_geth_driver = { | 
|  | 3789 | .name		= DRV_NAME, | 
|  | 3790 | .match_table	= ucc_geth_match, | 
|  | 3791 | .probe		= ucc_geth_probe, | 
|  | 3792 | .remove		= ucc_geth_remove, | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3793 | }; | 
|  | 3794 |  | 
|  | 3795 | static int __init ucc_geth_init(void) | 
|  | 3796 | { | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3797 | int i, ret; | 
|  | 3798 |  | 
| Li Yang | 890de95 | 2007-07-19 11:48:29 +0800 | [diff] [blame] | 3799 | if (netif_msg_drv(&debug)) | 
|  | 3800 | printk(KERN_INFO "ucc_geth: " DRV_DESC "\n"); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3801 | for (i = 0; i < 8; i++) | 
|  | 3802 | memcpy(&(ugeth_info[i]), &ugeth_primary_info, | 
|  | 3803 | sizeof(ugeth_primary_info)); | 
|  | 3804 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3805 | ret = of_register_platform_driver(&ucc_geth_driver); | 
|  | 3806 |  | 
| Kim Phillips | 728de4c9 | 2007-04-13 01:26:03 -0500 | [diff] [blame] | 3807 | return ret; | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3808 | } | 
|  | 3809 |  | 
|  | 3810 | static void __exit ucc_geth_exit(void) | 
|  | 3811 | { | 
| Kim Phillips | a4f0c2c | 2006-11-15 12:29:35 -0600 | [diff] [blame] | 3812 | of_unregister_platform_driver(&ucc_geth_driver); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3813 | } | 
|  | 3814 |  | 
|  | 3815 | module_init(ucc_geth_init); | 
|  | 3816 | module_exit(ucc_geth_exit); | 
|  | 3817 |  | 
|  | 3818 | MODULE_AUTHOR("Freescale Semiconductor, Inc"); | 
|  | 3819 | MODULE_DESCRIPTION(DRV_DESC); | 
| Kim Phillips | c2bcf00 | 2007-04-13 01:26:36 -0500 | [diff] [blame] | 3820 | MODULE_VERSION(DRV_VERSION); | 
| Li Yang | ce973b1 | 2006-08-14 23:00:11 -0700 | [diff] [blame] | 3821 | MODULE_LICENSE("GPL"); |