📄 ucc_geth.c
字号:
/* * Copyright (C) 2006-2007 Freescale Semicondutor, Inc. All rights reserved. * * Author: Shlomi Gridish <gridish@freescale.com> * Li Yang <leoli@freescale.com> * * Description: * QE UCC Gigabit Ethernet Driver * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */#include <linux/kernel.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/stddef.h>#include <linux/interrupt.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/spinlock.h>#include <linux/mm.h>#include <linux/dma-mapping.h>#include <linux/fsl_devices.h>#include <linux/mii.h>#include <linux/phy.h>#include <linux/workqueue.h>#include <asm/of_platform.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/immap_qe.h>#include <asm/qe.h>#include <asm/ucc.h>#include <asm/ucc_fast.h>#include "ucc_geth.h"#include "ucc_geth_mii.h"#undef DEBUG#define ugeth_printk(level, format, arg...) \ printk(level format "\n", ## arg)#define ugeth_dbg(format, arg...) \ ugeth_printk(KERN_DEBUG , format , ## arg)#define ugeth_err(format, arg...) \ ugeth_printk(KERN_ERR , format , ## arg)#define ugeth_info(format, arg...) \ ugeth_printk(KERN_INFO , format , ## arg)#define ugeth_warn(format, arg...) \ ugeth_printk(KERN_WARNING , format , ## arg)#ifdef UGETH_VERBOSE_DEBUG#define ugeth_vdbg ugeth_dbg#else#define ugeth_vdbg(fmt, args...) do { } while (0)#endif /* UGETH_VERBOSE_DEBUG */#define UGETH_MSG_DEFAULT (NETIF_MSG_IFUP << 1 ) - 1void uec_set_ethtool_ops(struct net_device *netdev);static DEFINE_SPINLOCK(ugeth_lock);static struct { u32 msg_enable;} debug = { -1 };module_param_named(debug, debug.msg_enable, int, 0);MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 0xffff=all)");static struct ucc_geth_info ugeth_primary_info = { .uf_info = { .bd_mem_part = MEM_PART_SYSTEM, .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES, .max_rx_buf_length = 1536, /* adjusted at startup if max-speed 1000 */ .urfs = UCC_GETH_URFS_INIT, .urfet = UCC_GETH_URFET_INIT, .urfset = UCC_GETH_URFSET_INIT, .utfs = UCC_GETH_UTFS_INIT, .utfet = UCC_GETH_UTFET_INIT, .utftt = UCC_GETH_UTFTT_INIT, .ufpt = 256, .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET, .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL, .tenc = UCC_FAST_TX_ENCODING_NRZ, .renc = UCC_FAST_RX_ENCODING_NRZ, .tcrc = UCC_FAST_16_BIT_CRC, .synl = UCC_FAST_SYNC_LEN_NOT_USED, }, .numQueuesTx = 1, .numQueuesRx = 1, .extendedFilteringChainPointer = ((uint32_t) NULL), .typeorlen = 3072 /*1536 */ , .nonBackToBackIfgPart1 = 0x40, .nonBackToBackIfgPart2 = 0x60, .miminumInterFrameGapEnforcement = 0x50, .backToBackInterFrameGap = 0x60, .mblinterval = 128, .nortsrbytetime = 5, .fracsiz = 1, .strictpriorityq = 0xff, .altBebTruncation = 0xa, .excessDefer = 1, .maxRetransmission = 0xf, .collisionWindow = 0x37, .receiveFlowControl = 1, .transmitFlowControl = 1, .maxGroupAddrInHash = 4, .maxIndAddrInHash = 4, .prel = 7, .maxFrameLength = 1518, .minFrameLength = 64, .maxD1Length = 1520, .maxD2Length = 1520, .vlantype = 0x8100, .ecamptr = ((uint32_t) NULL), .eventRegMask = UCCE_OTHER, .pausePeriod = 0xf000, .interruptcoalescingmaxvalue = {1, 1, 1, 1, 1, 1, 1, 1}, .bdRingLenTx = { TX_BD_RING_LEN, TX_BD_RING_LEN, TX_BD_RING_LEN, TX_BD_RING_LEN, TX_BD_RING_LEN, TX_BD_RING_LEN, TX_BD_RING_LEN, TX_BD_RING_LEN}, .bdRingLenRx = { RX_BD_RING_LEN, RX_BD_RING_LEN, RX_BD_RING_LEN, RX_BD_RING_LEN, RX_BD_RING_LEN, RX_BD_RING_LEN, RX_BD_RING_LEN, RX_BD_RING_LEN}, .numStationAddresses = UCC_GETH_NUM_OF_STATION_ADDRESSES_1, .largestexternallookupkeysize = QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE, .statisticsMode = UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE | UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX | UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX, .vlanOperationTagged = UCC_GETH_VLAN_OPERATION_TAGGED_NOP, .vlanOperationNonTagged = UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP, .rxQoSMode = UCC_GETH_QOS_MODE_DEFAULT, .aufc = UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_NONE, .padAndCrc = MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC, .numThreadsTx = UCC_GETH_NUM_OF_THREADS_4, .numThreadsRx = UCC_GETH_NUM_OF_THREADS_4, .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,};static struct ucc_geth_info ugeth_info[8];#ifdef DEBUGstatic void mem_disp(u8 *addr, int size){ u8 *i; int size16Aling = (size >> 4) << 4; int size4Aling = (size >> 2) << 2; int notAlign = 0; if (size % 16) notAlign = 1; for (i = addr; (u32) i < (u32) addr + size16Aling; i += 16) printk("0x%08x: %08x %08x %08x %08x\r\n", (u32) i, *((u32 *) (i)), *((u32 *) (i + 4)), *((u32 *) (i + 8)), *((u32 *) (i + 12))); if (notAlign == 1) printk("0x%08x: ", (u32) i); for (; (u32) i < (u32) addr + size4Aling; i += 4) printk("%08x ", *((u32 *) (i))); for (; (u32) i < (u32) addr + size; i++) printk("%02x", *((u8 *) (i))); if (notAlign == 1) printk("\r\n");}#endif /* DEBUG */#ifdef CONFIG_UGETH_FILTERINGstatic void enqueue(struct list_head *node, struct list_head *lh){ unsigned long flags; spin_lock_irqsave(&ugeth_lock, flags); list_add_tail(node, lh); spin_unlock_irqrestore(&ugeth_lock, flags);}#endif /* CONFIG_UGETH_FILTERING */static struct list_head *dequeue(struct list_head *lh){ unsigned long flags; spin_lock_irqsave(&ugeth_lock, flags); if (!list_empty(lh)) { struct list_head *node = lh->next; list_del(node); spin_unlock_irqrestore(&ugeth_lock, flags); return node; } else { spin_unlock_irqrestore(&ugeth_lock, flags); return NULL; }}static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd){ struct sk_buff *skb = NULL; skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length + UCC_GETH_RX_DATA_BUF_ALIGNMENT); if (skb == NULL) return NULL; /* We need the data buffer to be aligned properly. We will reserve * as many bytes as needed to align the data properly */ skb_reserve(skb, UCC_GETH_RX_DATA_BUF_ALIGNMENT - (((unsigned)skb->data) & (UCC_GETH_RX_DATA_BUF_ALIGNMENT - 1))); skb->dev = ugeth->dev; out_be32(&((struct qe_bd *)bd)->buf, dma_map_single(NULL, skb->data, ugeth->ug_info->uf_info.max_rx_buf_length + UCC_GETH_RX_DATA_BUF_ALIGNMENT, DMA_FROM_DEVICE)); out_be32((u32 *)bd, (R_E | R_I | (in_be32((u32 *)bd) & R_W))); return skb;}static int rx_bd_buffer_set(struct ucc_geth_private *ugeth, u8 rxQ){ u8 *bd; u32 bd_status; struct sk_buff *skb; int i; bd = ugeth->p_rx_bd_ring[rxQ]; i = 0; do { bd_status = in_be32((u32*)bd); skb = get_new_skb(ugeth, bd); if (!skb) /* If can not allocate data buffer, abort. Cleanup will be elsewhere */ return -ENOMEM; ugeth->rx_skbuff[rxQ][i] = skb; /* advance the BD pointer */ bd += sizeof(struct qe_bd); i++; } while (!(bd_status & R_W)); return 0;}static int fill_init_enet_entries(struct ucc_geth_private *ugeth, volatile u32 *p_start, u8 num_entries, u32 thread_size, u32 thread_alignment, enum qe_risc_allocation risc, int skip_page_for_first_entry){ u32 init_enet_offset; u8 i; int snum; for (i = 0; i < num_entries; i++) { if ((snum = qe_get_snum()) < 0) { if (netif_msg_ifup(ugeth)) ugeth_err("fill_init_enet_entries: Can not get SNUM."); return snum; } if ((i == 0) && skip_page_for_first_entry) /* First entry of Rx does not have page */ init_enet_offset = 0; else { init_enet_offset = qe_muram_alloc(thread_size, thread_alignment); if (IS_ERR_VALUE(init_enet_offset)) { if (netif_msg_ifup(ugeth)) ugeth_err("fill_init_enet_entries: Can not allocate DPRAM memory."); qe_put_snum((u8) snum); return -ENOMEM; } } *(p_start++) = ((u8) snum << ENET_INIT_PARAM_SNUM_SHIFT) | init_enet_offset | risc; } return 0;}static int return_init_enet_entries(struct ucc_geth_private *ugeth, volatile u32 *p_start, u8 num_entries, enum qe_risc_allocation risc, int skip_page_for_first_entry){ u32 init_enet_offset; u8 i; int snum; for (i = 0; i < num_entries; i++) { /* Check that this entry was actually valid -- needed in case failed in allocations */ if ((*p_start & ENET_INIT_PARAM_RISC_MASK) == risc) { snum = (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK) >> ENET_INIT_PARAM_SNUM_SHIFT; qe_put_snum((u8) snum); if (!((i == 0) && skip_page_for_first_entry)) { /* First entry of Rx does not have page */ init_enet_offset = (in_be32(p_start) & ENET_INIT_PARAM_PTR_MASK); qe_muram_free(init_enet_offset); } *(p_start++) = 0; /* Just for cosmetics */ } } return 0;}#ifdef DEBUGstatic int dump_init_enet_entries(struct ucc_geth_private *ugeth, volatile u32 *p_start, u8 num_entries, u32 thread_size, enum qe_risc_allocation risc, int skip_page_for_first_entry){ u32 init_enet_offset; u8 i; int snum; for (i = 0; i < num_entries; i++) { /* Check that this entry was actually valid -- needed in case failed in allocations */ if ((*p_start & ENET_INIT_PARAM_RISC_MASK) == risc) { snum = (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK) >> ENET_INIT_PARAM_SNUM_SHIFT; qe_put_snum((u8) snum); if (!((i == 0) && skip_page_for_first_entry)) { /* First entry of Rx does not have page */ init_enet_offset = (in_be32(p_start) & ENET_INIT_PARAM_PTR_MASK); ugeth_info("Init enet entry %d:", i); ugeth_info("Base address: 0x%08x", (u32) qe_muram_addr(init_enet_offset)); mem_disp(qe_muram_addr(init_enet_offset), thread_size); } p_start++; } } return 0;}#endif#ifdef CONFIG_UGETH_FILTERINGstatic struct enet_addr_container *get_enet_addr_container(void){ struct enet_addr_container *enet_addr_cont; /* allocate memory */ enet_addr_cont = kmalloc(sizeof(struct enet_addr_container), GFP_KERNEL); if (!enet_addr_cont) { ugeth_err("%s: No memory for enet_addr_container object.", __FUNCTION__); return NULL; } return enet_addr_cont;}#endif /* CONFIG_UGETH_FILTERING */static void put_enet_addr_container(struct enet_addr_container *enet_addr_cont){ kfree(enet_addr_cont);}static void set_mac_addr(__be16 __iomem *reg, u8 *mac){ out_be16(®[0], ((u16)mac[5] << 8) | mac[4]); out_be16(®[1], ((u16)mac[3] << 8) | mac[2]); out_be16(®[2], ((u16)mac[1] << 8) | mac[0]);}#ifdef CONFIG_UGETH_FILTERINGstatic int hw_add_addr_in_paddr(struct ucc_geth_private *ugeth, u8 *p_enet_addr, u8 paddr_num){ struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -