📄 405gp_enet.c.svn-base
字号:
/*-----------------------------------------------------------------------------+ * * This source code has been made available to you by IBM on an AS-IS * basis. Anyone receiving this source is licensed under IBM * copyrights to use it in any way he or she deems fit, including * copying it, modifying it, compiling it, and redistributing it either * with or without modifications. No license under IBM patents or * patent applications is to be implied by the copyright license. * * Any user of this software should understand that IBM cannot provide * technical support for this software and will not be responsible for * any consequences resulting from the use of this software. * * Any person who transfers this source code or any derivative work * must include the IBM copyright notice, this paragraph, and the * preceding two paragraphs in the transferred software. * * COPYRIGHT I B M CORPORATION 1995 * LICENSED MATERIAL - PROGRAM PROPERTY OF I B M *-----------------------------------------------------------------------------*//*-----------------------------------------------------------------------------+ * * File Name: enetemac.c * * Function: Device driver for the ethernet EMAC3 macro on the 405GP. * * Author: Mark Wisner * * Change Activity- * * Date Description of Change BY * --------- --------------------- --- * 05-May-99 Created MKW * 27-Jun-99 Clean up JWB * 16-Jul-99 Added MAL error recovery and better IP packet handling MKW * 29-Jul-99 Added Full duplex support MKW * 06-Aug-99 Changed names for Mal CR reg MKW * 23-Aug-99 Turned off SYE when running at 10Mbs MKW * 24-Aug-99 Marked descriptor empty after call_xlc MKW * 07-Sep-99 Set MAL RX buffer size reg to ENET_MAX_MTU_ALIGNED / 16 MCG * to avoid chaining maximum sized packets. Push starting * RX descriptor address up to the next cache line boundary. * 16-Jan-00 Added support for booting with IP of 0x0 MKW * 15-Mar-00 Updated enetInit() to enable broadcast addresses in the * EMAC_RXM register. JWB * 12-Mar-01 anne-sophie.harnois@nextream.fr * - Variables are compatible with those already defined in * include/net.h * - Receive buffer descriptor ring is used to send buffers * to the user * - Info print about send/received/handled packet number if * INFO_405_ENET is set * 17-Apr-01 stefan.roese@esd-electronics.com * - MAL reset in "eth_halt" included * - Enet speed and duplex output now in one line * 08-May-01 stefan.roese@esd-electronics.com * - MAL error handling added (eth_init called again) * 13-Nov-01 stefan.roese@esd-electronics.com * - Set IST bit in EMAC_M1 reg upon 100MBit or full duplex * 04-Jan-02 stefan.roese@esd-electronics.com * - Wait for PHY auto negotiation to complete added * 06-Feb-02 stefan.roese@esd-electronics.com * - Bug fixed in waiting for auto negotiation to complete * 26-Feb-02 stefan.roese@esd-electronics.com * - rx and tx buffer descriptors now allocated (no fixed address * used anymore) * 17-Jun-02 stefan.roese@esd-electronics.com * - MAL error debug printf 'M' removed (rx de interrupt may * occur upon many incoming packets with only 4 rx buffers). * 21-Nov-03 pavel.bartusek@sysgo.com * - set ZMII bridge speed on 440 * *-----------------------------------------------------------------------------*/#include <common.h>#include <asm/processor.h>#include <ppc4xx.h>#include <commproc.h>#include <405gp_enet.h>#include <405_mal.h>#include <miiphy.h>#include <net.h>#include <malloc.h>#include "vecnum.h"#if defined(CONFIG_405GP) || defined(CONFIG_405EP) || \ ( defined(CONFIG_440) && !defined(CONFIG_NET_MULTI))#define EMAC_RESET_TIMEOUT 1000 /* 1000 ms reset timeout */#define PHY_AUTONEGOTIATE_TIMEOUT 4000 /* 4000 ms autonegotiate timeout */#define NUM_TX_BUFF 1/* AS.HARNOIS * Use PKTBUFSRX (include/net.h) instead of setting NUM_RX_BUFF again * These both variables are used to define the same thing! * #define NUM_RX_BUFF 4 */#define NUM_RX_BUFF PKTBUFSRX/* Ethernet Transmit and Receive Buffers *//* AS.HARNOIS * In the same way ENET_MAX_MTU and ENET_MAX_MTU_ALIGNED are set from * PKTSIZE and PKTSIZE_ALIGN (include/net.h) */#define ENET_MAX_MTU PKTSIZE#define ENET_MAX_MTU_ALIGNED PKTSIZE_ALIGNstatic char *txbuf_ptr;/* define the number of channels implemented */#define EMAC_RXCHL 1#define EMAC_TXCHL 1/*-----------------------------------------------------------------------------+ * Defines for MAL/EMAC interrupt conditions as reported in the UIC (Universal * Interrupt Controller). *-----------------------------------------------------------------------------*/#define MAL_UIC_ERR ( UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE)#define MAL_UIC_DEF (UIC_MAL_RXEOB | MAL_UIC_ERR)#define EMAC_UIC_DEF UIC_ENET/*-----------------------------------------------------------------------------+ * Global variables. TX and RX descriptors and buffers. *-----------------------------------------------------------------------------*/static volatile mal_desc_t *tx;static volatile mal_desc_t *rx;static mal_desc_t *alloc_tx_buf = NULL;static mal_desc_t *alloc_rx_buf = NULL;/* IER globals */static unsigned long emac_ier;static unsigned long mal_ier;/* Statistic Areas */#define MAX_ERR_LOG 10struct emac_stats { int data_len_err; int rx_frames; int rx; int rx_prot_err;};static struct stats { /* Statistic Block */ struct emac_stats emac; int int_err; short tx_err_log[MAX_ERR_LOG]; short rx_err_log[MAX_ERR_LOG];} stats;static int first_init = 0;static int tx_err_index = 0; /* Transmit Error Index for tx_err_log */static int rx_err_index = 0; /* Receive Error Index for rx_err_log */static int rx_slot = 0; /* MAL Receive Slot */static int rx_i_index = 0; /* Receive Interrupt Queue Index */static int rx_u_index = 0; /* Receive User Queue Index */static int rx_ready[NUM_RX_BUFF]; /* Receive Ready Queue */static int tx_slot = 0; /* MAL Transmit Slot */static int tx_i_index = 0; /* Transmit Interrupt Queue Index */static int tx_u_index = 0; /* Transmit User Queue Index */static int tx_run[NUM_TX_BUFF]; /* Transmit Running Queue */#undef INFO_405_ENET#ifdef INFO_405_ENETstatic int packetSent = 0;static int packetReceived = 0;static int packetHandled = 0;#endifstatic char emac_hwd_addr[ENET_ADDR_LENGTH];static bd_t *bis_save = NULL; /* for eth_init upon mal error */static int is_receiving = 0; /* sync with eth interrupt */static int print_speed = 1; /* print speed message upon start *//*-----------------------------------------------------------------------------+ * Prototypes and externals. *-----------------------------------------------------------------------------*/static void enet_rcv (unsigned long malisr);static int enetInt(void);static void mal_err (unsigned long isr, unsigned long uic, unsigned long mal_def, unsigned long mal_errr);static void emac_err (unsigned long isr);static void ppc_4xx_eth_halt (struct eth_device *dev){ mtdcr (malier, 0x00000000); /* disable mal interrupts */ out32 (EMAC_IER, 0x00000000); /* disable emac interrupts */ /* 1st reset MAL */ mtdcr (malmcr, MAL_CR_MMSR); /* wait for reset */ while (mfdcr (malmcr) & MAL_CR_MMSR) { }; /* EMAC RESET */ out32 (EMAC_M0, EMAC_M0_SRST); print_speed = 1; /* print speed message again next time */}static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis){ int i; unsigned long reg; unsigned long msr; unsigned long speed; unsigned long duplex; unsigned mode_reg; unsigned short reg_short; msr = mfmsr (); mtmsr (msr & ~(MSR_EE)); /* disable interrupts */#ifdef INFO_405_ENET /* AS.HARNOIS * We should have : * packetHandled <= packetReceived <= packetHandled+PKTBUFSRX * In the most cases packetHandled = packetReceived, but it * is possible that new packets (without relationship with * current transfer) have got the time to arrived before * netloop calls eth_halt */ printf ("About preceeding transfer:\n" "- Sent packet number %d\n" "- Received packet number %d\n" "- Handled packet number %d\n", packetSent, packetReceived, packetHandled); packetSent = 0; packetReceived = 0; packetHandled = 0;#endif /* MAL RESET */ mtdcr (malmcr, MAL_CR_MMSR); /* wait for reset */ while (mfdcr (malmcr) & MAL_CR_MMSR) { }; tx_err_index = 0; /* Transmit Error Index for tx_err_log */ rx_err_index = 0; /* Receive Error Index for rx_err_log */ rx_slot = 0; /* MAL Receive Slot */ rx_i_index = 0; /* Receive Interrupt Queue Index */ rx_u_index = 0; /* Receive User Queue Index */ tx_slot = 0; /* MAL Transmit Slot */ tx_i_index = 0; /* Transmit Interrupt Queue Index */ tx_u_index = 0; /* Transmit User Queue Index */#if defined(CONFIG_440) /* set RMII mode */ out32 (ZMII_FER, ZMII_RMII | ZMII_MDI0);#endif /* CONFIG_440 */ /* EMAC RESET */ out32 (EMAC_M0, EMAC_M0_SRST); /* wait for PHY to complete auto negotiation */ reg_short = 0;#ifndef CONFIG_CS8952_PHY miiphy_read (CONFIG_PHY_ADDR, PHY_BMSR, ®_short); /* * Wait if PHY is able of autonegotiation and autonegotiation is not complete */ if ((reg_short & PHY_BMSR_AUTN_ABLE) && !(reg_short & PHY_BMSR_AUTN_COMP)) { puts ("Waiting for PHY auto negotiation to complete"); i = 0; while (!(reg_short & PHY_BMSR_AUTN_COMP)) { /* * Timeout reached ? */ if (i > PHY_AUTONEGOTIATE_TIMEOUT) { puts (" TIMEOUT !\n"); break; } if ((i++ % 1000) == 0) putc ('.'); udelay (1000); /* 1 ms */ miiphy_read (CONFIG_PHY_ADDR, PHY_BMSR, ®_short); } puts (" done\n"); udelay (500000); /* another 500 ms (results in faster booting) */ }#endif speed = miiphy_speed (CONFIG_PHY_ADDR); duplex = miiphy_duplex (CONFIG_PHY_ADDR); if (print_speed) { print_speed = 0; printf ("ENET Speed is %d Mbps - %s duplex connection\n", (int) speed, (duplex == HALF) ? "HALF" : "FULL"); } /* set the Mal configuration reg */#if defined(CONFIG_440) /* Errata 1.12: MAL_1 -- Disable MAL bursting */ if( get_pvr() == PVR_440GP_RB ) mtdcr (malmcr, MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT); else#else mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT);#endif /* Free "old" buffers */ if (alloc_tx_buf) free(alloc_tx_buf); if (alloc_rx_buf) free(alloc_rx_buf); /* * Malloc MAL buffer desciptors, make sure they are * aligned on cache line boundary size * (401/403/IOP480 = 16, 405 = 32) * and doesn't cross cache block boundaries. */ alloc_tx_buf = (mal_desc_t *)malloc((sizeof(mal_desc_t) * NUM_TX_BUFF) + ((2 * CFG_CACHELINE_SIZE) - 2)); if (((int)alloc_tx_buf & CACHELINE_MASK) != 0) { tx = (mal_desc_t *)((int)alloc_tx_buf + CFG_CACHELINE_SIZE - ((int)alloc_tx_buf & CACHELINE_MASK)); } else { tx = alloc_tx_buf; } alloc_rx_buf = (mal_desc_t *)malloc((sizeof(mal_desc_t) * NUM_RX_BUFF) + ((2 * CFG_CACHELINE_SIZE) - 2)); if (((int)alloc_rx_buf & CACHELINE_MASK) != 0) { rx = (mal_desc_t *)((int)alloc_rx_buf + CFG_CACHELINE_SIZE - ((int)alloc_rx_buf & CACHELINE_MASK)); } else { rx = alloc_rx_buf; } for (i = 0; i < NUM_TX_BUFF; i++) { tx[i].ctrl = 0; tx[i].data_len = 0; if (first_init == 0) txbuf_ptr = (char *) malloc (ENET_MAX_MTU_ALIGNED); tx[i].data_ptr = txbuf_ptr; if ((NUM_TX_BUFF - 1) == i) tx[i].ctrl |= MAL_TX_CTRL_WRAP; tx_run[i] = -1;#if 0 printf ("TX_BUFF %d @ 0x%08lx\n", i, (ulong) tx[i].data_ptr);#endif } for (i = 0; i < NUM_RX_BUFF; i++) { rx[i].ctrl = 0; rx[i].data_len = 0; /* rx[i].data_ptr = (char *) &rx_buff[i]; */ rx[i].data_ptr = (char *) NetRxPackets[i]; if ((NUM_RX_BUFF - 1) == i) rx[i].ctrl |= MAL_RX_CTRL_WRAP; rx[i].ctrl |= MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR; rx_ready[i] = -1;#if 0 printf ("RX_BUFF %d @ 0x%08lx\n", i, (ulong) rx[i].data_ptr);#endif } memcpy (emac_hwd_addr, bis->bi_enetaddr, ENET_ADDR_LENGTH); reg = 0x00000000; reg |= emac_hwd_addr[0]; /* set high address */ reg = reg << 8; reg |= emac_hwd_addr[1]; out32 (EMAC_IAH, reg); reg = 0x00000000; reg |= emac_hwd_addr[2]; /* set low address */ reg = reg << 8; reg |= emac_hwd_addr[3]; reg = reg << 8; reg |= emac_hwd_addr[4]; reg = reg << 8; reg |= emac_hwd_addr[5]; out32 (EMAC_IAL, reg); /* setup MAL tx & rx channel pointers */ mtdcr (maltxctp0r, tx); mtdcr (malrxctp0r, rx); /* Reset transmit and receive channels */ mtdcr (malrxcarr, 0x80000000); /* 2 channels */ mtdcr (maltxcarr, 0x80000000); /* 2 channels */ /* Enable MAL transmit and receive channels */ mtdcr (maltxcasr, 0x80000000); /* 1 channel */ mtdcr (malrxcasr, 0x80000000); /* 1 channel */ /* set RX buffer size */ mtdcr (malrcbs0, ENET_MAX_MTU_ALIGNED / 16); /* set transmit enable & receive enable */ out32 (EMAC_M0, EMAC_M0_TXE | EMAC_M0_RXE); /* set receive fifo to 4k and tx fifo to 2k */ mode_reg = EMAC_M1_RFS_4K | EMAC_M1_TX_FIFO_2K; /* set speed */ if (speed == _100BASET) mode_reg = mode_reg | EMAC_M1_MF_100MBPS | EMAC_M1_IST; else mode_reg = mode_reg & ~0x00C00000; /* 10 MBPS */ if (duplex == FULL) mode_reg = mode_reg | 0x80000000 | EMAC_M1_IST; out32 (EMAC_M1, mode_reg);#if defined(CONFIG_440) /* set speed in the ZMII bridge */ if (speed == _100BASET) out32(ZMII_SSR, in32(ZMII_SSR) | 0x10000000); else out32(ZMII_SSR, in32(ZMII_SSR) & ~0x10000000);#endif /* Enable broadcast and indvidual address */ out32 (EMAC_RXM, EMAC_RMR_BAE | EMAC_RMR_IAE /*| EMAC_RMR_ARRP| EMAC_RMR_SFCS | EMAC_RMR_SP */ ); /* we probably need to set the tx mode1 reg? maybe at tx time */ /* set transmit request threshold register */ out32 (EMAC_TRTR, 0x18000000); /* 256 byte threshold */ /* set receive low/high water mark register */#if defined(CONFIG_440) /* 440GP has a 64 byte burst length */ out32 (EMAC_RX_HI_LO_WMARK, 0x80009000); out32 (EMAC_TXM1, 0xf8640000);#else /* CONFIG_440 */ /* 405s have a 16 byte burst length */ out32 (EMAC_RX_HI_LO_WMARK, 0x0f002000);#endif /* CONFIG_440 */ /* Frame gap set */ out32 (EMAC_I_FRAME_GAP_REG, 0x00000008); if (first_init == 0) { /* * Connect interrupt service routines */ irq_install_handler (VECNUM_EWU0, (interrupt_handler_t *) enetInt, NULL); irq_install_handler (VECNUM_MS, (interrupt_handler_t *) enetInt, NULL); irq_install_handler (VECNUM_MTE, (interrupt_handler_t *) enetInt, NULL); irq_install_handler (VECNUM_MRE, (interrupt_handler_t *) enetInt, NULL); irq_install_handler (VECNUM_TXDE, (interrupt_handler_t *) enetInt, NULL); irq_install_handler (VECNUM_RXDE, (interrupt_handler_t *) enetInt, NULL); irq_install_handler (VECNUM_ETH0, (interrupt_handler_t *) enetInt, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -