diff options
author | Vijay Kumar Banerjee <vijay@rtems.org> | 2021-02-24 19:09:56 -0700 |
---|---|---|
committer | Vijay Kumar Banerjee <vijay@rtems.org> | 2021-04-07 16:15:38 -0600 |
commit | c90fa83041f1467ac9795c489b7151db3a041ab5 (patch) | |
tree | ee3ebcd4af33202b34f89133a301d268609e355c /bsps/powerpc/shared/net/tsec.c | |
parent | cpukit/libfs: Remove nfsclient (diff) | |
download | rtems-c90fa83041f1467ac9795c489b7151db3a041ab5.tar.bz2 |
bsps: Remove networking drivers
Update #3850
Diffstat (limited to 'bsps/powerpc/shared/net/tsec.c')
-rw-r--r-- | bsps/powerpc/shared/net/tsec.c | 1936 |
1 files changed, 0 insertions, 1936 deletions
diff --git a/bsps/powerpc/shared/net/tsec.c b/bsps/powerpc/shared/net/tsec.c deleted file mode 100644 index c51d47c619..0000000000 --- a/bsps/powerpc/shared/net/tsec.c +++ /dev/null @@ -1,1936 +0,0 @@ -/*===============================================================*\ -| Project: RTEMS support for MPC83xx | -+-----------------------------------------------------------------+ -| Copyright (c) 2007 | -| Embedded Brains GmbH | -| Obere Lagerstr. 30 | -| D-82178 Puchheim | -| Germany | -| rtems@embedded-brains.de | -+-----------------------------------------------------------------+ -| The license and distribution terms for this file may be | -| found in the file LICENSE in this distribution or at | -| | -| http://www.rtems.org/license/LICENSE. | -| | -+-----------------------------------------------------------------+ -| this file contains the MPC83xx TSEC networking driver | -\*===============================================================*/ - -#include <machine/rtems-bsd-kernel-space.h> - -#include <stdlib.h> -#include <bsp.h> -#include <bsp/irq.h> -#include <bsp/tsec.h> -#include <rtems/error.h> -#include <rtems/bspIo.h> -#include <rtems/rtems_bsdnet.h> -#include <rtems/rtems_mii_ioctl.h> -#include <errno.h> - -#include <sys/param.h> -#include <sys/socket.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> -#include <net/if.h> -#include <net/if_arp.h> -#include <netinet/in.h> -#include <netinet/if_ether.h> -#include <stdio.h> - -#define CLREVENT_IN_IRQ - -#define TSEC_WATCHDOG_TIMEOUT 5 /* check media every 5 seconds */ - -#ifdef DEBUG - #define PF(fmt, ...) printk("%s: " fmt, __func__, ##__VA_ARGS__) -#else - #define PF(...) -#endif - -/* - * Device data - */ -struct tsec_struct { - struct arpcom arpcom; - int acceptBroadcast; - - /* - * HW links: (filled from rtems_bsdnet_ifconfig - */ - volatile tsec_registers *reg_ptr; /* pointer to TSEC register block */ - volatile tsec_registers *mdio_ptr; /* pointer to TSEC register block which is responsible for MDIO communication */ - rtems_irq_number irq_num_tx; - rtems_irq_number irq_num_rx; - rtems_irq_number irq_num_err; - - rtems_interrupt_lock lock; - - /* - * BD management - */ - int rxBdCount; - int txBdCount; - PQBufferDescriptor_t *Rx_Frst_BD; - PQBufferDescriptor_t *Rx_Last_BD; - PQBufferDescriptor_t *Rx_NxtUsed_BD; /* First BD, which is in Use */ - PQBufferDescriptor_t *Rx_NxtFill_BD; /* BD to be filled next */ - struct mbuf **Rx_mBuf_Ptr; /* Storage for mbufs */ - - PQBufferDescriptor_t *Tx_Frst_BD; - PQBufferDescriptor_t *Tx_Last_BD; - PQBufferDescriptor_t *Tx_NxtUsed_BD; /* First BD, which is in Use */ - PQBufferDescriptor_t *Tx_NxtFill_BD; /* BD to be filled next */ - struct mbuf **Tx_mBuf_Ptr; /* Storage for mbufs */ - /* - * Daemon IDs - */ - rtems_id rxDaemonTid; - rtems_id txDaemonTid; - - /* - * MDIO/Phy info - */ - struct rtems_mdio_info mdio_info; - int phy_default; - int media_state; /* (last detected) state of media */ - /* - * statistic counters Rx - */ - unsigned long rxInterrupts; - unsigned long rxErrors; - /* - * statistic counters Tx - */ - unsigned long txInterrupts; - unsigned long txErrors; - }; - -static struct tsec_struct tsec_driver[TSEC_COUNT]; - -/* - * default numbers for buffers - */ -#define RX_BUF_COUNT 64 -#define TX_BUF_COUNT 64 - -/* - * mask for all Tx interrupts - */ -#define IEVENT_TXALL (TSEC_IEVENT_GTSC \ - | TSEC_IEVENT_TXC \ - /*| TSEC_IEVENT_TXB*/ \ - | TSEC_IEVENT_TXF ) - -/* - * mask for all Rx interrupts - */ -#define IEVENT_RXALL (TSEC_IEVENT_RXC \ - /* | TSEC_IEVENT_RXB */ \ - | TSEC_IEVENT_GRSC \ - | TSEC_IEVENT_RXF ) - -/* - * mask for all Error interrupts - */ -#define IEVENT_ERRALL (TSEC_IEVENT_BABR \ - | TSEC_IEVENT_BSY \ - | TSEC_IEVENT_EBERR \ - | TSEC_IEVENT_MSRO \ - | TSEC_IEVENT_BABT \ - | TSEC_IEVENT_TXE \ - | TSEC_IEVENT_LC \ - | TSEC_IEVENT_CRL_XDA \ - | TSEC_IEVENT_XFUN ) - -static void TSEC_IMASK_SET(struct tsec_struct *sc, uint32_t mask, uint32_t val) -{ - volatile uint32_t *reg = &sc->reg_ptr->imask; - rtems_interrupt_lock_context lock_context; - - rtems_interrupt_lock_acquire(&sc->lock, &lock_context); - *reg = (*reg & ~mask) | (val & mask); - rtems_interrupt_lock_release(&sc->lock, &lock_context); -} - -#define TSEC_ALIGN_BUFFER(buf,align) \ - ((void *)( (((uint32_t)(buf))+(align)-1) \ - -(((uint32_t)(buf))+(align)-1)%align)) - -/* - * RTEMS event used by interrupt handler to signal daemons. - * This must *not* be the same event used by the TCP/IP task synchronization. - */ -#define INTERRUPT_EVENT RTEMS_EVENT_1 -#define FATAL_INT_EVENT RTEMS_EVENT_3 - -/* - * RTEMS event used to start transmit daemon. - * This must not be the same as INTERRUPT_EVENT. - */ -#define START_TRANSMIT_EVENT RTEMS_EVENT_2 - -static int tsec_ioctl -( - struct ifnet *ifp, /* interface information */ - ioctl_command_t command, /* ioctl command code */ - caddr_t data /* optional data */ - ); - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_hwinit -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| initialize hardware register | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct tsec_struct *sc /* control structure */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - volatile tsec_registers *reg_ptr = sc->reg_ptr; /* pointer to TSEC registers*/ - uint8_t *mac_addr; - size_t i; - - /* Clear interrupt mask and all pending events */ - reg_ptr->imask = 0; - reg_ptr->ievent = 0xffffffff; - - /* - * init ECNTL register - * - clear statistics counters - * - enable statistics - * NOTE: do not clear bits set in BSP init function - */ - reg_ptr->ecntrl = ((reg_ptr->ecntrl & ~TSEC_ECNTRL_AUTOZ) - | TSEC_ECNTRL_CLRCNT - | TSEC_ECNTRL_STEN - | TSEC_ECNTRL_R100M); - - /* - * init DMA control register: - * - enable snooping - * - write BD status before interrupt request - * - do not poll TxBD, but wait for TSTAT[THLT] to be written - */ - reg_ptr->dmactrl = (TSEC_DMACTL_TDSEN - | TSEC_DMACTL_TBDSEN - | TSEC_DMACTL_WWR - | TSEC_DMACTL_WOP); - - /* - * init Attribute register: - * - enable read snooping for data and BD - */ - reg_ptr->attr = (TSEC_ATTR_RDSEN - | TSEC_ATTR_RBDSEN); - - - reg_ptr->mrblr = MCLBYTES-64; /* take care of buffer size lost - * due to alignment */ - - /* - * init EDIS register: disable all error reportings - */ - reg_ptr->edis = (TSEC_EDIS_BSYDIS | - TSEC_EDIS_EBERRDIS | - TSEC_EDIS_TXEDIS | - TSEC_EDIS_LCDIS | - TSEC_EDIS_CRLXDADIS | - TSEC_EDIS_FUNDIS); - /* - * init minimum frame length register - */ - reg_ptr->minflr = 64; - /* - * init maximum frame length register - */ - reg_ptr->maxfrm = 1536; - /* - * define physical address of TBI - */ - reg_ptr->tbipa = 0x1e; - /* - * init transmit interrupt coalescing register - */ - reg_ptr->txic = (TSEC_TXIC_ICEN - | TSEC_TXIC_ICFCT(2) - | TSEC_TXIC_ICTT(32)); - /* - * init receive interrupt coalescing register - */ -#if 0 - reg_ptr->rxic = (TSEC_RXIC_ICEN - | TSEC_RXIC_ICFCT(2) - | TSEC_RXIC_ICTT(32)); -#else - reg_ptr->rxic = 0; -#endif - /* - * init MACCFG1 register - */ - reg_ptr->maccfg1 = (TSEC_MACCFG1_RX_FLOW - | TSEC_MACCFG1_TX_FLOW); - - /* - * init MACCFG2 register - */ - reg_ptr->maccfg2 = ((reg_ptr->maccfg2 & TSEC_MACCFG2_IFMODE_MSK) - | TSEC_MACCFG2_IFMODE_BYT - | TSEC_MACCFG2_PRELEN( 7) - | TSEC_MACCFG2_FULLDUPLEX); - - /* - * init station address register - */ - mac_addr = sc->arpcom.ac_enaddr; - - reg_ptr->macstnaddr[0] = ((mac_addr[5] << 24) - | (mac_addr[4] << 16) - | (mac_addr[3] << 8) - | (mac_addr[2] << 0)); - reg_ptr->macstnaddr[1] = ((mac_addr[1] << 24) - | (mac_addr[0] << 16)); - /* - * clear hash filters - */ - for (i = 0; - i < sizeof(reg_ptr->iaddr)/sizeof(reg_ptr->iaddr[0]); - i++) { - reg_ptr->iaddr[i] = 0; - } - for (i = 0; - i < sizeof(reg_ptr->gaddr)/sizeof(reg_ptr->gaddr[0]); - i++) { - reg_ptr->gaddr[i] = 0; - } -} - -/***************************************************************************\ -| MII Management access functions | -\***************************************************************************/ - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_mdio_init -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| initialize the MIIM interface | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct tsec_struct *sc /* control structure */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - static const uint8_t divider [] = { 32, 32, 48, 64, 80, 112, 160, 224 }; - size_t n = sizeof(divider) / sizeof(divider [0]); - size_t i = 0; - uint32_t mii_clock = UINT32_MAX; - uint32_t tsec_system_clock = BSP_bus_frequency / 2; - - /* Set TSEC registers for MDIO communication */ - - /* - * set clock divider - */ - for (i = 0; i < n && mii_clock > 2500000; ++i) { - mii_clock = tsec_system_clock / divider [i]; - } - - sc->mdio_ptr->miimcfg = i; -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static int tsec_mdio_read -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| read register of a phy | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - int phy, /* PHY number to access or -1 */ - void *uarg, /* unit argument */ - unsigned reg, /* register address */ - uint32_t *pval /* ptr to read buffer */ - ) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| 0, if ok, else error | -\*=========================================================================*/ -{ - struct tsec_struct *sc = uarg;/* control structure */ - - /* pointer to TSEC registers */ - volatile tsec_registers *reg_ptr = sc->mdio_ptr; - PF("%u\n", reg); - - /* - * make sure we work with a valid phy - */ - if (phy == -1) { - phy = sc->phy_default; - } - if ( (phy < 0) || (phy > 31)) { - /* - * invalid phy number - */ - return EINVAL; - } - /* - * set PHY/reg address - */ - reg_ptr->miimadd = (TSEC_MIIMADD_PHY(phy) - | TSEC_MIIMADD_REGADDR(reg)); - /* - * start read cycle - */ - reg_ptr->miimcom = 0; - reg_ptr->miimcom = TSEC_MIIMCOM_READ; - - /* - * wait for cycle to terminate - */ - do { - rtems_task_wake_after(2); - } while (0 != (reg_ptr->miimind & TSEC_MIIMIND_BUSY)); - reg_ptr->miimcom = 0; - /* - * fetch read data, if available - */ - if (pval != NULL) { - *pval = reg_ptr->miimstat; - } - return 0; -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static int tsec_mdio_write -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| write register of a phy | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - int phy, /* PHY number to access or -1 */ - void *uarg, /* unit argument */ - unsigned reg, /* register address */ - uint32_t val /* write value */ - ) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| 0, if ok, else error | -\*=========================================================================*/ -{ - struct tsec_struct *sc = uarg;/* control structure */ - - /* pointer to TSEC registers */ - volatile tsec_registers *reg_ptr = sc->mdio_ptr; - PF("%u\n", reg); - - /* - * make sure we work with a valid phy - */ - if (phy == -1) { - /* - * set default phy number: 0 for TSEC1, 1 for TSEC2 - */ - phy = sc->phy_default; - } - if ( (phy < 0) || (phy > 31)) { - /* - * invalid phy number - */ - return EINVAL; - } - /* - * set PHY/reg address - */ - reg_ptr->miimadd = (TSEC_MIIMADD_PHY(phy) - | TSEC_MIIMADD_REGADDR(reg)); - /* - * start write cycle - */ - reg_ptr->miimcon = val; - - /* - * wait for cycle to terminate - */ - do { - rtems_task_wake_after(2); - } while (0 != (reg_ptr->miimind & TSEC_MIIMIND_BUSY)); - reg_ptr->miimcom = 0; - return 0; -} - - -/***************************************************************************\ -| RX receive functions | -\***************************************************************************/ - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static rtems_event_set tsec_rx_wait_for_events -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| handle all rx events | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct tsec_struct *sc, /* control structure */ - rtems_event_set event_mask /* events to wait for */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| event set received | -\*=========================================================================*/ -{ - rtems_event_set events; /* events received */ - /* - * enable Rx interrupts, make sure this is not interrupted :-) - */ - TSEC_IMASK_SET(sc,IEVENT_RXALL,~0); - - /* - * wait for events to come in - */ - rtems_bsdnet_event_receive(event_mask, - RTEMS_EVENT_ANY | RTEMS_WAIT, - RTEMS_NO_TIMEOUT, - &events); - return events; -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void mpc83xx_rxbd_alloc_clear -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| allocate space for Rx BDs, clear them | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct tsec_struct *sc /* control structure */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - char *alloc_ptr; - PQBufferDescriptor_t *BD_ptr; - /* - * allocate proper space for Rx BDs - */ - alloc_ptr = calloc((sc->rxBdCount+1),sizeof(PQBufferDescriptor_t)); - if (alloc_ptr == NULL) { - rtems_panic("TSEC: cannot allocate space for Rx BDs"); - } - alloc_ptr = (void *)((uint32_t )((alloc_ptr + (sizeof(PQBufferDescriptor_t)-1))) - & ~(sizeof(PQBufferDescriptor_t)-1)); - /* - * store pointers to certain positions in BD chain - */ - sc->Rx_Last_BD = ((PQBufferDescriptor_t *)alloc_ptr)+sc->rxBdCount-1; - sc->Rx_Frst_BD = (PQBufferDescriptor_t *)alloc_ptr; - sc->Rx_NxtUsed_BD = sc->Rx_Frst_BD; - sc->Rx_NxtFill_BD = sc->Rx_Frst_BD; - - /* - * clear all BDs - */ - for (BD_ptr = sc->Rx_Frst_BD; - BD_ptr <= sc->Rx_Last_BD; - BD_ptr++) { - BD_ptr->status = 0; - } - /* - * Init BD chain registers - */ - sc->reg_ptr->rbase = (uint32_t) (sc->Rx_Frst_BD); -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_receive_packets -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| process any received packets | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct tsec_struct *sc /* control structure */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - PQBufferDescriptor_t *BD_ptr; - struct mbuf *m,*n; - bool finished = false; - uint16_t status; - struct ether_header *eh; - int bd_idx; - - BD_ptr = sc->Rx_NxtUsed_BD; - - while ((0 == ((status = BD_ptr->status) & BD_EMPTY)) && - !finished && - (BD_ptr->buffer != NULL)) { - /* - * get mbuf associated with BD - */ - bd_idx = BD_ptr - sc->Rx_Frst_BD; - m = sc->Rx_mBuf_Ptr[bd_idx]; - sc->Rx_mBuf_Ptr[bd_idx] = NULL; - - /* - * Check that packet is valid - */ - if ((status & (BD_LAST | - BD_FIRST_IN_FRAME | - BD_LONG | - BD_NONALIGNED | - BD_CRC_ERROR | - BD_OVERRUN )) - == (BD_LAST | - BD_FIRST_IN_FRAME ) ) { - /* - * send mbuf of this buffer to ether_input() - */ - m->m_len = m->m_pkthdr.len = (BD_ptr->length - - sizeof(uint32_t) - - sizeof(struct ether_header)); - eh = mtod(m, struct ether_header *); - m->m_data += sizeof(struct ether_header); - PF("RX[%08x] (%i)\n", BD_ptr, m->m_len); - ether_input(&sc->arpcom.ac_if,eh,m); - } - else { - /* - * throw away mbuf - */ - MFREE(m,n); - (void) n; - } - /* - * mark buffer as non-allocated (for refill) - */ - BD_ptr->buffer = NULL; - /* - * Advance BD_ptr to next BD - */ - BD_ptr = ((BD_ptr == sc->Rx_Last_BD) - ? sc->Rx_Frst_BD - : BD_ptr+1); - } - sc->Rx_NxtUsed_BD = BD_ptr; -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_refill_rxbds -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| link new buffers to rx BDs | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct tsec_struct *sc /* control structure */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - PQBufferDescriptor_t *BD_ptr; - struct mbuf *m,*n; - bool finished = false; - int bd_idx; - - BD_ptr = sc->Rx_NxtFill_BD; - while ((BD_ptr->buffer == NULL) && - !finished) { - /* - * get new mbuf and attach a cluster - */ - MGETHDR(m,M_DONTWAIT,MT_DATA); - if (m != NULL) { - MCLGET(m,M_DONTWAIT); - if ((m->m_flags & M_EXT) == 0) { - MFREE(m,n); - (void) n; - m = NULL; - } - } - if (m == NULL) { - finished = true; - } - else { - bd_idx = BD_ptr - sc->Rx_Frst_BD; - sc->Rx_mBuf_Ptr[bd_idx] = m; - - m->m_pkthdr.rcvif= &sc->arpcom.ac_if; - m->m_data = TSEC_ALIGN_BUFFER(m->m_ext.ext_buf,64); - BD_ptr->buffer = m->m_data; - BD_ptr->length = 0; - BD_ptr->status = (BD_EMPTY - | BD_INTERRUPT - | ((BD_ptr == sc->Rx_Last_BD) - ? BD_WRAP - : 0)); - /* - * Advance BD_ptr to next BD - */ - BD_ptr = ((BD_ptr == sc->Rx_Last_BD) - ? sc->Rx_Frst_BD - : BD_ptr+1); - } - } - sc->Rx_NxtFill_BD = BD_ptr; -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_rxDaemon -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| handle all rx buffers and events | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - void * arg /* argument, is sc structure ptr */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - struct tsec_struct *sc = - (struct tsec_struct *)arg; - bool finished = false; -#if !defined(CLREVENT_IN_IRQ) - uint32_t irq_events; -#endif - /* - * enable Rx in MACCFG1 register - */ - sc->reg_ptr->maccfg1 |= TSEC_MACCFG1_RXEN; - while (!finished) { - /* - * fetch MBufs, associate them to RxBDs - */ - tsec_refill_rxbds(sc); - /* - * wait for events to come in - */ - tsec_rx_wait_for_events(sc,INTERRUPT_EVENT); -#if !defined(CLREVENT_IN_IRQ) - /* - * clear any pending RX events - */ - irq_events = sc->reg_ptr->ievent & IEVENT_RXALL; - sc->reg_ptr->ievent = irq_events; -#endif - /* - * fetch any completed buffers/packets received - * and stuff them into the TCP/IP Stack - */ - tsec_receive_packets(sc); - } - /* - * disable Rx in MACCFG1 register - */ - sc->reg_ptr->maccfg1 &= ~TSEC_MACCFG1_RXEN; - /* - * terminate daemon - */ - sc->rxDaemonTid = 0; - rtems_task_exit(); -} - -/***************************************************************************\ -| TX Transmit functions | -\***************************************************************************/ - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void mpc83xx_txbd_alloc_clear -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| allocate space for Tx BDs, clear them | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct tsec_struct *sc /* control structure */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - char *alloc_ptr; - PQBufferDescriptor_t *BD_ptr; - /* - * allocate proper space for Tx BDs - */ - alloc_ptr = calloc((sc->txBdCount+1),sizeof(PQBufferDescriptor_t)); - if (alloc_ptr == NULL) { - rtems_panic("TSEC: cannot allocate space for Tx BDs"); - } - alloc_ptr = (void *)((uint32_t )((alloc_ptr + (sizeof(PQBufferDescriptor_t)-1))) - & ~(sizeof(PQBufferDescriptor_t)-1)); - /* - * store pointers to certain positions in BD chain - */ - sc->Tx_Last_BD = ((PQBufferDescriptor_t *)alloc_ptr)+sc->txBdCount-1; - sc->Tx_Frst_BD = (PQBufferDescriptor_t *)alloc_ptr; - sc->Tx_NxtUsed_BD = sc->Tx_Frst_BD; - sc->Tx_NxtFill_BD = sc->Tx_Frst_BD; - - /* - * clear all BDs - */ - for (BD_ptr = sc->Tx_Frst_BD; - BD_ptr <= sc->Tx_Last_BD; - BD_ptr++) { - BD_ptr->status = 0; - } - /* - * Init BD chain registers - */ - sc->reg_ptr->tbase = (uint32_t)(sc->Tx_Frst_BD); -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_tx_start -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| start transmission | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ -struct ifnet *ifp -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - struct tsec_struct *sc = ifp->if_softc; - - ifp->if_flags |= IFF_OACTIVE; - - rtems_bsdnet_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static rtems_event_set tsec_tx_wait_for_events -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| handle all tx events | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct tsec_struct *sc, /* control structure */ - rtems_event_set event_mask /* events to wait for */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| event set received | -\*=========================================================================*/ -{ - rtems_event_set events; /* events received */ - /* - * enable Tx interrupts, make sure this is not interrupted :-) - */ - TSEC_IMASK_SET(sc,IEVENT_TXALL,~0); - - /* - * wait for events to come in - */ - rtems_bsdnet_event_receive(event_mask, - RTEMS_EVENT_ANY | RTEMS_WAIT, - RTEMS_NO_TIMEOUT, - &events); - return events; -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_tx_retire -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| handle all tx events | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct tsec_struct *sc /* control structure */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - PQBufferDescriptor_t *RetBD; - RetBD = sc->Tx_NxtUsed_BD; - int bd_idx; - struct mbuf *m,*n; - /* - * check next BDs to be empty - */ - while ((RetBD->buffer != NULL) /* BD is filled */ - && (0 == (RetBD->status & BD_READY ))) {/* BD no longer ready*/ - - bd_idx = RetBD - sc->Tx_Frst_BD; - m = sc->Tx_mBuf_Ptr[bd_idx]; - sc->Tx_mBuf_Ptr[bd_idx] = NULL; - - MFREE(m,n); - (void) n; - RetBD->buffer = NULL; - /* - * Advance CurrBD to next BD - */ - RetBD = ((RetBD == sc->Tx_Last_BD) - ? sc->Tx_Frst_BD - : RetBD+1); - } - sc->Tx_NxtUsed_BD = RetBD; -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_sendpacket -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| handle all tx events | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct tsec_struct *sc, /* control structure */ - struct mbuf *m /* start of packet to send */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - PQBufferDescriptor_t *FrstBD = NULL; - PQBufferDescriptor_t *CurrBD; - uint16_t status; - struct mbuf *l = NULL; /* ptr to last non-freed (non-empty) mbuf */ - int bd_idx; - /* - * get next Tx BD - */ - CurrBD = sc->Tx_NxtFill_BD; - while (m) { - if(m->m_len == 0) { - /* - * Just toss empty mbufs - */ - struct mbuf *n; - MFREE(m, n); - m = n; - if(l != NULL) { - l->m_next = m; - } - } - else { - /* - * this mbuf is non-empty, so send it - */ - /* - * Is CurrBD still in Use/not yet retired? - */ - while (CurrBD->buffer != NULL) { - /* - * Then try to retire it - * and to return its mbuf - */ - tsec_tx_retire(sc); - if (CurrBD->buffer != NULL) { - /* - * Wait for anything to happen... - */ - tsec_tx_wait_for_events(sc,INTERRUPT_EVENT); - } - } - status = ((BD_PAD_CRC | BD_TX_CRC) - | ((m->m_next == NULL) - ? BD_LAST | BD_INTERRUPT - : 0) - | ((CurrBD == sc->Tx_Last_BD) ? BD_WRAP : 0)); - - /* - * link buffer to BD - */ - CurrBD->buffer = mtod(m, void *); - CurrBD->length = (uint32_t)m->m_len; - l = m; /* remember: we use this mbuf */ - PF("TX[%08x] (%i)\n", CurrBD, m->m_len); - - bd_idx = CurrBD - sc->Tx_Frst_BD; - sc->Tx_mBuf_Ptr[bd_idx] = m; - - m = m->m_next; /* advance to next mbuf of this packet */ - /* - * is this the first BD of the packet? - * then don't set it to "READY" state, - * and remember this BD position - */ - if (FrstBD == NULL) { - FrstBD = CurrBD; - } - else { - status |= BD_READY; - } - CurrBD->status = status; - /* - * Advance CurrBD to next BD - */ - CurrBD = ((CurrBD == sc->Tx_Last_BD) - ? sc->Tx_Frst_BD - : CurrBD+1); - } - } - /* - * mbuf chain of this packet - * has been translated - * to BD chain, so set first BD ready now - */ - if (FrstBD != NULL) { - FrstBD->status |= BD_READY; - } - sc->Tx_NxtFill_BD = CurrBD; - /* - * wake up transmitter (clear TSTAT[THLT]) - */ - sc->reg_ptr->tstat = TSEC_TSTAT_THLT; -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_txDaemon -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| handle all tx events | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - void * arg /* argument, is sc structure ptr */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - struct tsec_struct *sc = - (struct tsec_struct *)arg; - struct ifnet *ifp = &sc->arpcom.ac_if; - struct mbuf *m; - bool finished = false; -#if !defined(CLREVENT_IN_IRQ) - uint32_t irq_events; -#endif - - /* - * enable Tx in MACCFG1 register - * FIXME: make this irq save - */ - sc->reg_ptr->maccfg1 |= TSEC_MACCFG1_TXEN; - while (!finished) { - /* - * wait for events to come in - */ - tsec_tx_wait_for_events(sc, - START_TRANSMIT_EVENT - | INTERRUPT_EVENT); -#if !defined(CLREVENT_IN_IRQ) - /* - * clear any pending TX events - */ - irq_events = sc->reg_ptr->ievent & IEVENT_TXALL; - sc->reg_ptr->ievent = irq_events; -#endif - /* - * retire any sent tx BDs - */ - tsec_tx_retire(sc); - /* - * Send packets till queue is empty - */ - do { - /* - * Get the next mbuf chain to transmit. - */ - IF_DEQUEUE(&ifp->if_snd, m); - - if (m) { - tsec_sendpacket(sc,m); - } - } while (m != NULL); - - ifp->if_flags &= ~IFF_OACTIVE; - } - /* - * disable Tx in MACCFG1 register - */ - sc->reg_ptr->maccfg1 &= ~TSEC_MACCFG1_TXEN; - /* - * terminate daemon - */ - sc->txDaemonTid = 0; - rtems_task_exit(); -} - -/***************************************************************************\ -| Interrupt handlers and management routines | -\***************************************************************************/ - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_tx_irq_handler -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| handle tx interrupts | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - rtems_irq_hdl_param handle /* handle, is sc structure ptr */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - struct tsec_struct *sc = - (struct tsec_struct *)handle; -#if defined(CLREVENT_IN_IRQ) - uint32_t irq_events; -#endif - - PF("TXIRQ\n"); - sc->txInterrupts++; - /* - * disable tx interrupts - */ - TSEC_IMASK_SET(sc,IEVENT_TXALL,0); - -#if defined(CLREVENT_IN_IRQ) - /* - * clear any pending TX events - */ - irq_events = sc->reg_ptr->ievent & IEVENT_TXALL; - sc->reg_ptr->ievent = irq_events; -#endif - /* - * wake up tx Daemon - */ - rtems_bsdnet_event_send(sc->txDaemonTid, INTERRUPT_EVENT); -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_rx_irq_handler -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| handle rx interrupts | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - rtems_irq_hdl_param handle /* handle, is sc structure */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - struct tsec_struct *sc = - (struct tsec_struct *)handle; -#if defined(CLREVENT_IN_IRQ) - uint32_t irq_events; -#endif - - sc->rxInterrupts++; - PF("RXIRQ\n"); - /* - * disable rx interrupts - */ - TSEC_IMASK_SET(sc,IEVENT_RXALL,0); -#if defined(CLREVENT_IN_IRQ) - /* - * clear any pending RX events - */ - irq_events = sc->reg_ptr->ievent & IEVENT_RXALL; - sc->reg_ptr->ievent = irq_events; -#endif - /* - * wake up rx Daemon< - */ - rtems_bsdnet_event_send(sc->rxDaemonTid, INTERRUPT_EVENT); -} - - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_err_irq_handler -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| handle error interrupts | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - rtems_irq_hdl_param handle /* handle, is sc structure */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - struct tsec_struct *sc = - (struct tsec_struct *)handle; - PF("ERIRQ\n"); - /* - * clear error events in IEVENT - */ - sc->reg_ptr->ievent = IEVENT_ERRALL; - /* - * has Rx been stopped? then restart it - */ - if (0 != (sc->reg_ptr->rstat & TSEC_RSTAT_QHLT)) { - sc->rxErrors++; - sc->reg_ptr->rstat = TSEC_RSTAT_QHLT; - } - /* - * has Tx been stopped? then restart it - */ - if (0 != (sc->reg_ptr->tstat & TSEC_TSTAT_THLT)) { - sc->txErrors++; - sc->reg_ptr->tstat = TSEC_TSTAT_THLT; - } -} - - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static uint32_t tsec_irq_mask -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| determine irq mask for given interrupt number | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - int irqnum, - struct tsec_struct *sc -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| interrupt mask (for ievent/imask register) | -\*=========================================================================*/ -{ - return ((irqnum == sc->irq_num_tx) - ? IEVENT_TXALL - : ((irqnum == sc->irq_num_rx) - ? IEVENT_RXALL - : ((irqnum == sc->irq_num_err) - ? IEVENT_ERRALL - : 0))); -} -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_irq_on -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| enable interrupts in TSEC mask register | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - const - rtems_irq_connect_data *irq_conn_data /* irq connect data */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - struct tsec_struct *sc = - (struct tsec_struct *)(irq_conn_data->handle); - - TSEC_IMASK_SET(sc, - tsec_irq_mask(irq_conn_data->name,sc), - ~0); -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_irq_off -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| disable TX interrupts in TSEC mask register | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - const - rtems_irq_connect_data *irq_conn_data /* irq connect data */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - struct tsec_struct *sc = - (struct tsec_struct *)irq_conn_data->handle; - - TSEC_IMASK_SET(sc, - tsec_irq_mask(irq_conn_data->name,sc), - 0); -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static int tsec_irq_isOn -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| check state of interrupts in TSEC mask register | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - const - rtems_irq_connect_data *irq_conn_data /* irq connect data */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - struct tsec_struct *sc = - (struct tsec_struct *)irq_conn_data->handle; - - return (0 != (sc->reg_ptr->imask - & tsec_irq_mask(irq_conn_data->name,sc))); -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_install_irq_handlers -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| (un-)install the interrupt handlers | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct tsec_struct *sc, /* ptr to control structure */ - bool install /* true: install, false: remove */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - size_t i; - - rtems_irq_connect_data irq_conn_data[3] = { - { - sc->irq_num_tx, - tsec_tx_irq_handler, /* rtems_irq_hdl */ - (rtems_irq_hdl_param)sc, /* (rtems_irq_hdl_param) */ - tsec_irq_on, /* (rtems_irq_enable) */ - tsec_irq_off, /* (rtems_irq_disable) */ - tsec_irq_isOn /* (rtems_irq_is_enabled) */ - },{ - sc->irq_num_rx, - tsec_rx_irq_handler, /* rtems_irq_hdl */ - (rtems_irq_hdl_param)sc, /* (rtems_irq_hdl_param) */ - tsec_irq_on, /* (rtems_irq_enable) */ - tsec_irq_off, /* (rtems_irq_disable) */ - tsec_irq_isOn /* (rtems_irq_is_enabled) */ - },{ - sc->irq_num_err, - tsec_err_irq_handler, /* rtems_irq_hdl */ - (rtems_irq_hdl_param)sc, /* (rtems_irq_hdl_param) */ - tsec_irq_on, /* (rtems_irq_enable) */ - tsec_irq_off, /* (rtems_irq_disable) */ - tsec_irq_isOn /* (rtems_irq_is_enabled) */ - } - }; - - /* - * (un-)install handler for Tx/Rx/Error - */ - for (i = 0; - i < sizeof(irq_conn_data)/sizeof(irq_conn_data[0]); - i++) { - if (install) { - if (!BSP_install_rtems_irq_handler (&irq_conn_data[i])) { - rtems_panic("TSEC: cannot install IRQ handler"); - } - } - else { - if (!BSP_remove_rtems_irq_handler (&irq_conn_data[i])) { - rtems_panic("TSEC: cannot uninstall IRQ handler"); - } - } - } -} - -/***************************************************************************\ -| Initialization and interface routines | -\***************************************************************************/ - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_init -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| initialize the driver and the hardware | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - void *arg /* argument pointer, contains *sc */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| zero, if success | -\*=========================================================================*/ -{ - struct tsec_struct *sc = (struct tsec_struct *)arg; - struct ifnet *ifp = &sc->arpcom.ac_if; - /* - * check, whether device is not yet running - */ - if (0 == sc->rxDaemonTid) { - /* - * allocate rx/tx BDs - */ - mpc83xx_rxbd_alloc_clear(sc); - mpc83xx_txbd_alloc_clear(sc); - /* - * allocate storage for mbuf ptrs - */ - sc->Rx_mBuf_Ptr = calloc(sc->rxBdCount,sizeof(struct mbuf *)); - sc->Tx_mBuf_Ptr = calloc(sc->txBdCount,sizeof(struct mbuf *)); - if ((sc->Rx_mBuf_Ptr == NULL) || - (sc->Tx_mBuf_Ptr == NULL)) { - rtems_panic("TSEC: cannot allocate buffers for mbuf management"); - - } - - /* - * initialize TSEC hardware: - * - set interrupt coalescing to BDCount/8, Time of 8 frames - * - enable DMA snooping - */ - tsec_hwinit(sc); - /* - * init access to phys - */ - tsec_mdio_init(sc); - /* - * Start driver tasks - */ - sc->txDaemonTid = rtems_bsdnet_newproc("TStx", - 4096, - tsec_txDaemon, - sc); - sc->rxDaemonTid = rtems_bsdnet_newproc("TSrx", 4096, - tsec_rxDaemon, - sc); - /* - * install interrupt handlers - */ - tsec_install_irq_handlers(sc,true); - } - /* - * Set flags appropriately - */ - if(ifp->if_flags & IFF_PROMISC) { - sc->reg_ptr->rctrl |= TSEC_RCTRL_PROM; - } - else { - sc->reg_ptr->rctrl &= ~TSEC_RCTRL_PROM; - } - -#if defined(MPC83XX_BOARD_HSC_CM01) - /* - * for HSC CM01: we need to configure the PHY to use maximum skew adjust - */ - - tsec_mdio_write(-1,sc,23,0x0100); -#endif - - /* - * init timer so the "watchdog function gets called periodically - */ - ifp->if_timer = 1; - /* - * Tell the world that we're running. - */ - ifp->if_flags |= IFF_RUNNING; -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_off -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| deinitialize the driver and the hardware | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct tsec_struct *sc /* ptr to control structure */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - /* - * deinitialize driver? - */ -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_stats -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| print statistics | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct tsec_struct *sc /* ptr to control structure */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - if (sc->phy_default >= 0) { - int media; - int result; - /* - * fetch/print media info - */ - media = IFM_MAKEWORD(0,0,0,sc->phy_default); /* fetch from default phy */ - - result = tsec_ioctl(&(sc->arpcom.ac_if), - SIOCGIFMEDIA, - (caddr_t)&media); - if (result == 0) { - rtems_ifmedia2str(media,NULL,0); - printf ("\n"); - } else { - printf ("PHY communication error\n"); - } - } -#if 0 /* print all PHY registers */ - { - int reg; - uint32_t reg_val; - printf("****** PHY register values****\n"); - for (reg = 0;reg <= 31;reg++) { - tsec_mdio_read(-1,sc,reg,®_val); - printf("%02d:0x%04x%c",reg,reg_val, - (((reg % 4) == 3) ? '\n' : ' ')); - } - } -#endif - /* - * print some statistics - */ - printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); - printf (" Rx Errors:%-8lu", sc->rxErrors); - printf (" Rx packets:%-8lu\n", - sc->reg_ptr->rmon_mib[TSEC_RMON_RPKT]); - printf (" Rx broadcasts:%-8lu", - sc->reg_ptr->rmon_mib[TSEC_RMON_RBCA]); - printf (" Rx multicasts:%-8lu", - sc->reg_ptr->rmon_mib[TSEC_RMON_RMCA]); - printf (" Giant:%-8lu\n", - sc->reg_ptr->rmon_mib[TSEC_RMON_ROVR]); - printf (" Non-octet:%-8lu", - sc->reg_ptr->rmon_mib[TSEC_RMON_RALN]); - printf (" Bad CRC:%-8lu", - sc->reg_ptr->rmon_mib[TSEC_RMON_RFCS]); - printf (" Overrun:%-8lu\n", - sc->reg_ptr->rmon_mib[TSEC_RMON_RDRP]); - - printf (" Tx Interrupts:%-8lu", sc->txInterrupts); - printf (" Tx Errors:%-8lu", sc->txErrors); - printf (" Tx packets:%-8lu\n", - sc->reg_ptr->rmon_mib[TSEC_RMON_TPKT]); - printf (" Deferred:%-8lu", - sc->reg_ptr->rmon_mib[TSEC_RMON_TDFR]); - printf (" Late Collision:%-8lu", - sc->reg_ptr->rmon_mib[TSEC_RMON_TLCL]); - printf ("Retransmit Limit:%-8lu\n", - sc->reg_ptr->rmon_mib[TSEC_RMON_TEDF]); - printf (" Underrun:%-8lu\n", - sc->reg_ptr->rmon_mib[TSEC_RMON_TUND]); -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static int tsec_ioctl -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| perform io control functions | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct ifnet *ifp, /* interface information */ - ioctl_command_t command, /* ioctl command code */ - caddr_t data /* optional data */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| zero, if success | -\*=========================================================================*/ -{ - struct tsec_struct *sc = ifp->if_softc; - int error = 0; - - switch(command) { - /* - * access PHY via MII - */ - case SIOCGIFMEDIA: - case SIOCSIFMEDIA: - rtems_mii_ioctl (&(sc->mdio_info),sc,command,(void *)data); - break; - case SIOCGIFADDR: - case SIOCSIFADDR: - /* - * pass through to general ether_ioctl - */ - ether_ioctl(ifp, command, data); - break; - - case SIOCSIFFLAGS: - /* - * adjust active state - */ - if (ifp->if_flags & IFF_RUNNING) { - tsec_off(sc); - } - if (ifp->if_flags & IFF_UP) { - tsec_init(sc); - } - break; - - case SIO_RTEMS_SHOW_STATS: - /* - * show interface statistics - */ - tsec_stats(sc); - break; - - /* - * All sorts of multicast commands need to be added here! - */ - default: - error = EINVAL; - break; - } - - return error; -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static int tsec_mode_adapt -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| init the PHY and adapt TSEC settings | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct ifnet *ifp -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| 0, if success | -\*=========================================================================*/ -{ - int result = 0; - struct tsec_struct *sc = ifp->if_softc; - int media = IFM_MAKEWORD( 0, 0, 0, sc->phy_default); - - /* In case no PHY is available stop now */ - if (sc->phy_default < 0) { - return 0; - } - - /* - * fetch media status - */ - result = tsec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media); - if (result != 0) { - return result; - } - - /* - * status is unchanged? then do nothing - */ - if (media == sc->media_state) { - return 0; - } - /* - * otherwise: for the first call, try to negotiate mode - */ - if (sc->media_state == 0) { - /* - * set media status: set auto negotiation -> start auto-negotiation - */ - media = IFM_MAKEWORD(0,IFM_AUTO,0,sc->phy_default); - result = tsec_ioctl(ifp,SIOCSIFMEDIA,(caddr_t)&media); - if (result != 0) { - return result; - } - /* - * check auto-negotiation status - */ - media = IFM_MAKEWORD(0,0,0,sc->phy_default); - result = tsec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media); - if (result != 0 || IFM_NONE == IFM_SUBTYPE(media)) { - return result; - } - } - - /* - * now set HW according to media results: - */ - /* - * if we are 1000MBit, then switch IF to byte mode - */ - if (IFM_1000_T == IFM_SUBTYPE(media)) { - sc->reg_ptr->maccfg2 = - ((sc->reg_ptr->maccfg2 & ~TSEC_MACCFG2_IFMODE_MSK) - | TSEC_MACCFG2_IFMODE_BYT); - } - else { - sc->reg_ptr->maccfg2 = - ((sc->reg_ptr->maccfg2 & ~TSEC_MACCFG2_IFMODE_MSK) - | TSEC_MACCFG2_IFMODE_NIB); - } - /* - * if we are 10MBit, then switch rate to 10M - */ - if (IFM_10_T == IFM_SUBTYPE(media)) { - sc->reg_ptr->ecntrl &= ~TSEC_ECNTRL_R100M; - } - else { - sc->reg_ptr->ecntrl |= TSEC_ECNTRL_R100M; - } - /* - * if we are half duplex then switch to half duplex - */ - if (0 == (IFM_FDX & IFM_OPTIONS(media))) { - sc->reg_ptr->maccfg2 &= ~TSEC_MACCFG2_FULLDUPLEX; - } - else { - sc->reg_ptr->maccfg2 |= TSEC_MACCFG2_FULLDUPLEX; - } - /* - * store current media state for future compares - */ - sc->media_state = media; - - return 0; -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -static void tsec_watchdog -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| periodically poll the PHY. if mode has changed, | -| then adjust the TSEC settings | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - struct ifnet *ifp -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| 1, if success | -\*=========================================================================*/ -{ - tsec_mode_adapt(ifp); - ifp->if_timer = TSEC_WATCHDOG_TIMEOUT; -} - -static int tsec_driver_attach(struct rtems_bsdnet_ifconfig *config) -{ - tsec_config *tsec_cfg = config->drv_ctrl; - int unitNumber = tsec_cfg->unit_number; - char *unitName = tsec_cfg->unit_name; - struct tsec_struct *sc; - struct ifnet *ifp; - - /* - * Is driver free? - */ - if ((unitNumber <= 0) || (unitNumber > TSEC_COUNT)) { - - printk ("Bad TSEC unit number.\n"); - return 0; - - } - - sc = &tsec_driver[unitNumber - 1]; - ifp = &sc->arpcom.ac_if; - - if(ifp->if_softc != NULL) { - printk ("Driver already in use.\n"); - return 0; - } - - /* - * Process options - */ - if(config->hardware_address) { - memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); - } - else { - rtems_panic("TSEC: No Ethernet address specified!\n"); - } - - sc->rxBdCount = (config->rbuf_count > 0) ? config->rbuf_count : RX_BUF_COUNT; - sc->txBdCount = (config->xbuf_count > 0) ? config->xbuf_count : TX_BUF_COUNT; - sc->acceptBroadcast = !config->ignore_broadcast; - - /* get pointer to TSEC register block */ - sc->reg_ptr = tsec_cfg->reg_ptr; - sc->mdio_ptr = tsec_cfg->mdio_ptr; - - /* IRQ numbers */ - sc->irq_num_tx = tsec_cfg->irq_num_tx; - sc->irq_num_rx = tsec_cfg->irq_num_rx; - sc->irq_num_err = tsec_cfg->irq_num_err; - - /* - * setup info about mdio interface - */ - sc->mdio_info.mdio_r = tsec_mdio_read; - sc->mdio_info.mdio_w = tsec_mdio_write; - sc->mdio_info.has_gmii = 1; /* we support gigabit IF */ - - /* PHY address */ - sc->phy_default = tsec_cfg->phy_default; - - /* - * Set up network interface values - */ - ifp->if_softc = sc; - ifp->if_unit = unitNumber; - ifp->if_name = unitName; - ifp->if_mtu = (config->mtu > 0) ? config->mtu : ETHERMTU; - ifp->if_init = tsec_init; - ifp->if_ioctl = tsec_ioctl; - ifp->if_start = tsec_tx_start; - ifp->if_output = ether_output; - ifp->if_watchdog = tsec_watchdog; /* XXX: timer is set in "init" */ - - ifp->if_flags = (config->ignore_broadcast) ? 0 : IFF_BROADCAST; - /*ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;*/ - - if(ifp->if_snd.ifq_maxlen == 0) { - ifp->if_snd.ifq_maxlen = ifqmaxlen; - } - - /* - * Attach the interface - */ - if_attach(ifp); - - ether_ifattach(ifp); - - return 1; -} - -int tsec_driver_attach_detach( - struct rtems_bsdnet_ifconfig *config, - int attaching -) -{ - if (attaching) { - return tsec_driver_attach(config); - } else { - return 0; - } -} |