Deprecated fork of old network stack source from github. Please use official library instead: https://mbed.org/users/mbed_official/code/EthernetInterface/
lwip-eth/arch/lpc17_emac.c@1:eadc868c2acf, 2013-10-26 (annotated)
- Committer:
- AdamGreen
- Date:
- Sat Oct 26 08:51:36 2013 +0000
- Revision:
- 1:eadc868c2acf
- Parent:
- 0:3b00827bb0b7
Fix TCP checksum bug and stranded large TCP segments.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
AdamGreen | 0:3b00827bb0b7 | 1 | /********************************************************************** |
AdamGreen | 0:3b00827bb0b7 | 2 | * $Id$ lpc17_emac.c 2011-11-20 |
AdamGreen | 0:3b00827bb0b7 | 3 | *//** |
AdamGreen | 0:3b00827bb0b7 | 4 | * @file lpc17_emac.c |
AdamGreen | 0:3b00827bb0b7 | 5 | * @brief LPC17 ethernet driver for LWIP |
AdamGreen | 0:3b00827bb0b7 | 6 | * @version 1.0 |
AdamGreen | 0:3b00827bb0b7 | 7 | * @date 20. Nov. 2011 |
AdamGreen | 0:3b00827bb0b7 | 8 | * @author NXP MCU SW Application Team |
AdamGreen | 0:3b00827bb0b7 | 9 | * |
AdamGreen | 0:3b00827bb0b7 | 10 | * Copyright(C) 2011, NXP Semiconductor |
AdamGreen | 0:3b00827bb0b7 | 11 | * All rights reserved. |
AdamGreen | 0:3b00827bb0b7 | 12 | * |
AdamGreen | 0:3b00827bb0b7 | 13 | *********************************************************************** |
AdamGreen | 0:3b00827bb0b7 | 14 | * Software that is described herein is for illustrative purposes only |
AdamGreen | 0:3b00827bb0b7 | 15 | * which provides customers with programming information regarding the |
AdamGreen | 0:3b00827bb0b7 | 16 | * products. This software is supplied "AS IS" without any warranties. |
AdamGreen | 0:3b00827bb0b7 | 17 | * NXP Semiconductors assumes no responsibility or liability for the |
AdamGreen | 0:3b00827bb0b7 | 18 | * use of the software, conveys no license or title under any patent, |
AdamGreen | 0:3b00827bb0b7 | 19 | * copyright, or mask work right to the product. NXP Semiconductors |
AdamGreen | 0:3b00827bb0b7 | 20 | * reserves the right to make changes in the software without |
AdamGreen | 0:3b00827bb0b7 | 21 | * notification. NXP Semiconductors also make no representation or |
AdamGreen | 0:3b00827bb0b7 | 22 | * warranty that such application will be suitable for the specified |
AdamGreen | 0:3b00827bb0b7 | 23 | * use without further testing or modification. |
AdamGreen | 0:3b00827bb0b7 | 24 | **********************************************************************/ |
AdamGreen | 0:3b00827bb0b7 | 25 | |
AdamGreen | 0:3b00827bb0b7 | 26 | #include "lwip/opt.h" |
AdamGreen | 0:3b00827bb0b7 | 27 | #include "lwip/sys.h" |
AdamGreen | 0:3b00827bb0b7 | 28 | #include "lwip/def.h" |
AdamGreen | 0:3b00827bb0b7 | 29 | #include "lwip/mem.h" |
AdamGreen | 0:3b00827bb0b7 | 30 | #include "lwip/pbuf.h" |
AdamGreen | 0:3b00827bb0b7 | 31 | #include "lwip/stats.h" |
AdamGreen | 0:3b00827bb0b7 | 32 | #include "lwip/snmp.h" |
AdamGreen | 0:3b00827bb0b7 | 33 | #include "netif/etharp.h" |
AdamGreen | 0:3b00827bb0b7 | 34 | #include "netif/ppp_oe.h" |
AdamGreen | 0:3b00827bb0b7 | 35 | |
AdamGreen | 0:3b00827bb0b7 | 36 | #include "lpc17xx_emac.h" |
AdamGreen | 0:3b00827bb0b7 | 37 | #include "lpc17_emac.h" |
AdamGreen | 0:3b00827bb0b7 | 38 | #include "lpc_emac_config.h" |
AdamGreen | 0:3b00827bb0b7 | 39 | #include "lpc_phy.h" |
AdamGreen | 0:3b00827bb0b7 | 40 | #include "sys_arch.h" |
AdamGreen | 0:3b00827bb0b7 | 41 | |
AdamGreen | 0:3b00827bb0b7 | 42 | #include "mbed_interface.h" |
AdamGreen | 0:3b00827bb0b7 | 43 | #include <string.h> |
AdamGreen | 0:3b00827bb0b7 | 44 | |
AdamGreen | 0:3b00827bb0b7 | 45 | #ifndef LPC_EMAC_RMII |
AdamGreen | 0:3b00827bb0b7 | 46 | #error LPC_EMAC_RMII is not defined! |
AdamGreen | 0:3b00827bb0b7 | 47 | #endif |
AdamGreen | 0:3b00827bb0b7 | 48 | |
AdamGreen | 0:3b00827bb0b7 | 49 | #if LPC_NUM_BUFF_TXDESCS < 2 |
AdamGreen | 0:3b00827bb0b7 | 50 | #error LPC_NUM_BUFF_TXDESCS must be at least 2 |
AdamGreen | 0:3b00827bb0b7 | 51 | #endif |
AdamGreen | 0:3b00827bb0b7 | 52 | |
AdamGreen | 0:3b00827bb0b7 | 53 | #if LPC_NUM_BUFF_RXDESCS < 3 |
AdamGreen | 0:3b00827bb0b7 | 54 | #error LPC_NUM_BUFF_RXDESCS must be at least 3 |
AdamGreen | 0:3b00827bb0b7 | 55 | #endif |
AdamGreen | 0:3b00827bb0b7 | 56 | |
AdamGreen | 0:3b00827bb0b7 | 57 | /** @defgroup lwip17xx_emac_DRIVER lpc17 EMAC driver for LWIP |
AdamGreen | 0:3b00827bb0b7 | 58 | * @ingroup lwip_emac |
AdamGreen | 0:3b00827bb0b7 | 59 | * |
AdamGreen | 0:3b00827bb0b7 | 60 | * @{ |
AdamGreen | 0:3b00827bb0b7 | 61 | */ |
AdamGreen | 0:3b00827bb0b7 | 62 | |
AdamGreen | 0:3b00827bb0b7 | 63 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 64 | /** \brief Driver transmit and receive thread priorities |
AdamGreen | 0:3b00827bb0b7 | 65 | * |
AdamGreen | 0:3b00827bb0b7 | 66 | * Thread priorities for receive thread and TX cleanup thread. Alter |
AdamGreen | 0:3b00827bb0b7 | 67 | * to prioritize receive or transmit bandwidth. In a heavily loaded |
AdamGreen | 0:3b00827bb0b7 | 68 | * system or with LEIP_DEBUG enabled, the priorities might be better |
AdamGreen | 0:3b00827bb0b7 | 69 | * the same. */ |
AdamGreen | 0:3b00827bb0b7 | 70 | #define RX_PRIORITY (osPriorityNormal) |
AdamGreen | 0:3b00827bb0b7 | 71 | #define TX_PRIORITY (osPriorityNormal) |
AdamGreen | 0:3b00827bb0b7 | 72 | |
AdamGreen | 0:3b00827bb0b7 | 73 | /** \brief Debug output formatter lock define |
AdamGreen | 0:3b00827bb0b7 | 74 | * |
AdamGreen | 0:3b00827bb0b7 | 75 | * When using FreeRTOS and with LWIP_DEBUG enabled, enabling this |
AdamGreen | 0:3b00827bb0b7 | 76 | * define will allow RX debug messages to not interleave with the |
AdamGreen | 0:3b00827bb0b7 | 77 | * TX messages (so they are actually readable). Not enabling this |
AdamGreen | 0:3b00827bb0b7 | 78 | * define when the system is under load will cause the output to |
AdamGreen | 0:3b00827bb0b7 | 79 | * be unreadable. There is a small tradeoff in performance for this |
AdamGreen | 0:3b00827bb0b7 | 80 | * so use it only for debug. */ |
AdamGreen | 0:3b00827bb0b7 | 81 | //#define LOCK_RX_THREAD |
AdamGreen | 0:3b00827bb0b7 | 82 | |
AdamGreen | 0:3b00827bb0b7 | 83 | /** \brief Receive group interrupts |
AdamGreen | 0:3b00827bb0b7 | 84 | */ |
AdamGreen | 0:3b00827bb0b7 | 85 | #define RXINTGROUP (EMAC_INT_RX_OVERRUN | EMAC_INT_RX_ERR | EMAC_INT_RX_DONE) |
AdamGreen | 0:3b00827bb0b7 | 86 | |
AdamGreen | 0:3b00827bb0b7 | 87 | /** \brief Transmit group interrupts |
AdamGreen | 0:3b00827bb0b7 | 88 | */ |
AdamGreen | 0:3b00827bb0b7 | 89 | #define TXINTGROUP (EMAC_INT_TX_UNDERRUN | EMAC_INT_TX_ERR | EMAC_INT_TX_DONE) |
AdamGreen | 0:3b00827bb0b7 | 90 | |
AdamGreen | 0:3b00827bb0b7 | 91 | /** \brief Signal used for ethernet ISR to signal packet_rx() thread. |
AdamGreen | 0:3b00827bb0b7 | 92 | */ |
AdamGreen | 0:3b00827bb0b7 | 93 | #define RX_SIGNAL 1 |
AdamGreen | 0:3b00827bb0b7 | 94 | |
AdamGreen | 0:3b00827bb0b7 | 95 | #else |
AdamGreen | 0:3b00827bb0b7 | 96 | #define RXINTGROUP 0 |
AdamGreen | 0:3b00827bb0b7 | 97 | #define TXINTGROUP 0 |
AdamGreen | 0:3b00827bb0b7 | 98 | #endif |
AdamGreen | 0:3b00827bb0b7 | 99 | |
AdamGreen | 0:3b00827bb0b7 | 100 | /** \brief Structure of a TX/RX descriptor |
AdamGreen | 0:3b00827bb0b7 | 101 | */ |
AdamGreen | 0:3b00827bb0b7 | 102 | typedef struct |
AdamGreen | 0:3b00827bb0b7 | 103 | { |
AdamGreen | 0:3b00827bb0b7 | 104 | volatile u32_t packet; /**< Pointer to buffer */ |
AdamGreen | 0:3b00827bb0b7 | 105 | volatile u32_t control; /**< Control word */ |
AdamGreen | 0:3b00827bb0b7 | 106 | } LPC_TXRX_DESC_T; |
AdamGreen | 0:3b00827bb0b7 | 107 | |
AdamGreen | 0:3b00827bb0b7 | 108 | /** \brief Structure of a RX status entry |
AdamGreen | 0:3b00827bb0b7 | 109 | */ |
AdamGreen | 0:3b00827bb0b7 | 110 | typedef struct |
AdamGreen | 0:3b00827bb0b7 | 111 | { |
AdamGreen | 0:3b00827bb0b7 | 112 | volatile u32_t statusinfo; /**< RX status word */ |
AdamGreen | 0:3b00827bb0b7 | 113 | volatile u32_t statushashcrc; /**< RX hash CRC */ |
AdamGreen | 0:3b00827bb0b7 | 114 | } LPC_TXRX_STATUS_T; |
AdamGreen | 0:3b00827bb0b7 | 115 | |
AdamGreen | 0:3b00827bb0b7 | 116 | /* LPC EMAC driver data structure */ |
AdamGreen | 0:3b00827bb0b7 | 117 | struct lpc_enetdata { |
AdamGreen | 0:3b00827bb0b7 | 118 | /* prxs must be 8 byte aligned! */ |
AdamGreen | 0:3b00827bb0b7 | 119 | LPC_TXRX_STATUS_T prxs[LPC_NUM_BUFF_RXDESCS]; /**< Pointer to RX statuses */ |
AdamGreen | 0:3b00827bb0b7 | 120 | struct netif *netif; /**< Reference back to LWIP parent netif */ |
AdamGreen | 0:3b00827bb0b7 | 121 | LPC_TXRX_DESC_T ptxd[LPC_NUM_BUFF_TXDESCS]; /**< Pointer to TX descriptor list */ |
AdamGreen | 0:3b00827bb0b7 | 122 | LPC_TXRX_STATUS_T ptxs[LPC_NUM_BUFF_TXDESCS]; /**< Pointer to TX statuses */ |
AdamGreen | 0:3b00827bb0b7 | 123 | LPC_TXRX_DESC_T prxd[LPC_NUM_BUFF_RXDESCS]; /**< Pointer to RX descriptor list */ |
AdamGreen | 0:3b00827bb0b7 | 124 | struct pbuf *rxb[LPC_NUM_BUFF_RXDESCS]; /**< RX pbuf pointer list, zero-copy mode */ |
AdamGreen | 0:3b00827bb0b7 | 125 | u32_t rx_fill_desc_index; /**< RX descriptor next available index */ |
AdamGreen | 0:3b00827bb0b7 | 126 | volatile u32_t rx_free_descs; /**< Count of free RX descriptors */ |
AdamGreen | 0:3b00827bb0b7 | 127 | struct pbuf *txb[LPC_NUM_BUFF_TXDESCS]; /**< TX pbuf pointer list, zero-copy mode */ |
AdamGreen | 0:3b00827bb0b7 | 128 | u32_t lpc_last_tx_idx; /**< TX last descriptor index, zero-copy mode */ |
AdamGreen | 0:3b00827bb0b7 | 129 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 130 | sys_thread_t RxThread; /**< RX receive thread data object pointer */ |
AdamGreen | 0:3b00827bb0b7 | 131 | sys_sem_t TxCleanSem; /**< TX cleanup thread wakeup semaphore */ |
AdamGreen | 0:3b00827bb0b7 | 132 | sys_mutex_t TXLockMutex; /**< TX critical section mutex */ |
AdamGreen | 0:3b00827bb0b7 | 133 | sys_sem_t xTXDCountSem; /**< TX free buffer counting semaphore */ |
AdamGreen | 0:3b00827bb0b7 | 134 | #endif |
AdamGreen | 0:3b00827bb0b7 | 135 | }; |
AdamGreen | 0:3b00827bb0b7 | 136 | |
AdamGreen | 0:3b00827bb0b7 | 137 | #if defined(TARGET_LPC4088) |
AdamGreen | 0:3b00827bb0b7 | 138 | # if defined (__ICCARM__) |
AdamGreen | 0:3b00827bb0b7 | 139 | # define ETHMEM_SECTION |
AdamGreen | 0:3b00827bb0b7 | 140 | # elif defined(TOOLCHAIN_GCC_CR) |
AdamGreen | 0:3b00827bb0b7 | 141 | # define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32"))) |
AdamGreen | 0:3b00827bb0b7 | 142 | # else |
AdamGreen | 0:3b00827bb0b7 | 143 | # define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned)) |
AdamGreen | 0:3b00827bb0b7 | 144 | # endif |
AdamGreen | 0:3b00827bb0b7 | 145 | #elif defined(TARGET_LPC1768) |
AdamGreen | 0:3b00827bb0b7 | 146 | # if defined(TOOLCHAIN_GCC_ARM) |
AdamGreen | 0:3b00827bb0b7 | 147 | # define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned)) |
AdamGreen | 0:3b00827bb0b7 | 148 | # endif |
AdamGreen | 0:3b00827bb0b7 | 149 | #endif |
AdamGreen | 0:3b00827bb0b7 | 150 | |
AdamGreen | 0:3b00827bb0b7 | 151 | #ifndef ETHMEM_SECTION |
AdamGreen | 0:3b00827bb0b7 | 152 | #define ETHMEM_SECTION ALIGNED(8) |
AdamGreen | 0:3b00827bb0b7 | 153 | #endif |
AdamGreen | 0:3b00827bb0b7 | 154 | |
AdamGreen | 0:3b00827bb0b7 | 155 | /** \brief LPC EMAC driver work data |
AdamGreen | 0:3b00827bb0b7 | 156 | */ |
AdamGreen | 0:3b00827bb0b7 | 157 | ETHMEM_SECTION struct lpc_enetdata lpc_enetdata; |
AdamGreen | 0:3b00827bb0b7 | 158 | |
AdamGreen | 0:3b00827bb0b7 | 159 | /* Write a value via the MII link (non-blocking) */ |
AdamGreen | 0:3b00827bb0b7 | 160 | void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value) |
AdamGreen | 0:3b00827bb0b7 | 161 | { |
AdamGreen | 0:3b00827bb0b7 | 162 | /* Write value at PHY address and register */ |
AdamGreen | 0:3b00827bb0b7 | 163 | LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg; |
AdamGreen | 0:3b00827bb0b7 | 164 | LPC_EMAC->MWTD = Value; |
AdamGreen | 0:3b00827bb0b7 | 165 | } |
AdamGreen | 0:3b00827bb0b7 | 166 | |
AdamGreen | 0:3b00827bb0b7 | 167 | /* Write a value via the MII link (blocking) */ |
AdamGreen | 0:3b00827bb0b7 | 168 | err_t lpc_mii_write(u32_t PhyReg, u32_t Value) |
AdamGreen | 0:3b00827bb0b7 | 169 | { |
AdamGreen | 0:3b00827bb0b7 | 170 | u32_t mst = 250; |
AdamGreen | 0:3b00827bb0b7 | 171 | err_t sts = ERR_OK; |
AdamGreen | 0:3b00827bb0b7 | 172 | |
AdamGreen | 0:3b00827bb0b7 | 173 | /* Write value at PHY address and register */ |
AdamGreen | 0:3b00827bb0b7 | 174 | lpc_mii_write_noblock(PhyReg, Value); |
AdamGreen | 0:3b00827bb0b7 | 175 | |
AdamGreen | 0:3b00827bb0b7 | 176 | /* Wait for unbusy status */ |
AdamGreen | 0:3b00827bb0b7 | 177 | while (mst > 0) { |
AdamGreen | 0:3b00827bb0b7 | 178 | sts = LPC_EMAC->MIND; |
AdamGreen | 0:3b00827bb0b7 | 179 | if ((sts & EMAC_MIND_BUSY) == 0) |
AdamGreen | 0:3b00827bb0b7 | 180 | mst = 0; |
AdamGreen | 0:3b00827bb0b7 | 181 | else { |
AdamGreen | 0:3b00827bb0b7 | 182 | mst--; |
AdamGreen | 0:3b00827bb0b7 | 183 | osDelay(1); |
AdamGreen | 0:3b00827bb0b7 | 184 | } |
AdamGreen | 0:3b00827bb0b7 | 185 | } |
AdamGreen | 0:3b00827bb0b7 | 186 | |
AdamGreen | 0:3b00827bb0b7 | 187 | if (sts != 0) |
AdamGreen | 0:3b00827bb0b7 | 188 | sts = ERR_TIMEOUT; |
AdamGreen | 0:3b00827bb0b7 | 189 | |
AdamGreen | 0:3b00827bb0b7 | 190 | return sts; |
AdamGreen | 0:3b00827bb0b7 | 191 | } |
AdamGreen | 0:3b00827bb0b7 | 192 | |
AdamGreen | 0:3b00827bb0b7 | 193 | /* Reads current MII link busy status */ |
AdamGreen | 0:3b00827bb0b7 | 194 | u32_t lpc_mii_is_busy(void) |
AdamGreen | 0:3b00827bb0b7 | 195 | { |
AdamGreen | 0:3b00827bb0b7 | 196 | return (u32_t) (LPC_EMAC->MIND & EMAC_MIND_BUSY); |
AdamGreen | 0:3b00827bb0b7 | 197 | } |
AdamGreen | 0:3b00827bb0b7 | 198 | |
AdamGreen | 0:3b00827bb0b7 | 199 | /* Starts a read operation via the MII link (non-blocking) */ |
AdamGreen | 0:3b00827bb0b7 | 200 | u32_t lpc_mii_read_data(void) |
AdamGreen | 0:3b00827bb0b7 | 201 | { |
AdamGreen | 0:3b00827bb0b7 | 202 | u32_t data = LPC_EMAC->MRDD; |
AdamGreen | 0:3b00827bb0b7 | 203 | LPC_EMAC->MCMD = 0; |
AdamGreen | 0:3b00827bb0b7 | 204 | |
AdamGreen | 0:3b00827bb0b7 | 205 | return data; |
AdamGreen | 0:3b00827bb0b7 | 206 | } |
AdamGreen | 0:3b00827bb0b7 | 207 | |
AdamGreen | 0:3b00827bb0b7 | 208 | /* Starts a read operation via the MII link (non-blocking) */ |
AdamGreen | 0:3b00827bb0b7 | 209 | void lpc_mii_read_noblock(u32_t PhyReg) |
AdamGreen | 0:3b00827bb0b7 | 210 | { |
AdamGreen | 0:3b00827bb0b7 | 211 | /* Read value at PHY address and register */ |
AdamGreen | 0:3b00827bb0b7 | 212 | LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg; |
AdamGreen | 0:3b00827bb0b7 | 213 | LPC_EMAC->MCMD = EMAC_MCMD_READ; |
AdamGreen | 0:3b00827bb0b7 | 214 | } |
AdamGreen | 0:3b00827bb0b7 | 215 | |
AdamGreen | 0:3b00827bb0b7 | 216 | /* Read a value via the MII link (blocking) */ |
AdamGreen | 0:3b00827bb0b7 | 217 | err_t lpc_mii_read(u32_t PhyReg, u32_t *data) |
AdamGreen | 0:3b00827bb0b7 | 218 | { |
AdamGreen | 0:3b00827bb0b7 | 219 | u32_t mst = 250; |
AdamGreen | 0:3b00827bb0b7 | 220 | err_t sts = ERR_OK; |
AdamGreen | 0:3b00827bb0b7 | 221 | |
AdamGreen | 0:3b00827bb0b7 | 222 | /* Read value at PHY address and register */ |
AdamGreen | 0:3b00827bb0b7 | 223 | lpc_mii_read_noblock(PhyReg); |
AdamGreen | 0:3b00827bb0b7 | 224 | |
AdamGreen | 0:3b00827bb0b7 | 225 | /* Wait for unbusy status */ |
AdamGreen | 0:3b00827bb0b7 | 226 | while (mst > 0) { |
AdamGreen | 0:3b00827bb0b7 | 227 | sts = LPC_EMAC->MIND & ~EMAC_MIND_MII_LINK_FAIL; |
AdamGreen | 0:3b00827bb0b7 | 228 | if ((sts & EMAC_MIND_BUSY) == 0) { |
AdamGreen | 0:3b00827bb0b7 | 229 | mst = 0; |
AdamGreen | 0:3b00827bb0b7 | 230 | *data = LPC_EMAC->MRDD; |
AdamGreen | 0:3b00827bb0b7 | 231 | } else { |
AdamGreen | 0:3b00827bb0b7 | 232 | mst--; |
AdamGreen | 0:3b00827bb0b7 | 233 | osDelay(1); |
AdamGreen | 0:3b00827bb0b7 | 234 | } |
AdamGreen | 0:3b00827bb0b7 | 235 | } |
AdamGreen | 0:3b00827bb0b7 | 236 | |
AdamGreen | 0:3b00827bb0b7 | 237 | LPC_EMAC->MCMD = 0; |
AdamGreen | 0:3b00827bb0b7 | 238 | |
AdamGreen | 0:3b00827bb0b7 | 239 | if (sts != 0) |
AdamGreen | 0:3b00827bb0b7 | 240 | sts = ERR_TIMEOUT; |
AdamGreen | 0:3b00827bb0b7 | 241 | |
AdamGreen | 0:3b00827bb0b7 | 242 | return sts; |
AdamGreen | 0:3b00827bb0b7 | 243 | } |
AdamGreen | 0:3b00827bb0b7 | 244 | |
AdamGreen | 0:3b00827bb0b7 | 245 | /** \brief Queues a pbuf into the RX descriptor list |
AdamGreen | 0:3b00827bb0b7 | 246 | * |
AdamGreen | 0:3b00827bb0b7 | 247 | * \param[in] lpc_enetif Pointer to the drvier data structure |
AdamGreen | 0:3b00827bb0b7 | 248 | * \param[in] p Pointer to pbuf to queue |
AdamGreen | 0:3b00827bb0b7 | 249 | */ |
AdamGreen | 0:3b00827bb0b7 | 250 | static void lpc_rxqueue_pbuf(struct lpc_enetdata *lpc_enetif, struct pbuf *p) |
AdamGreen | 0:3b00827bb0b7 | 251 | { |
AdamGreen | 0:3b00827bb0b7 | 252 | u32_t idx; |
AdamGreen | 0:3b00827bb0b7 | 253 | |
AdamGreen | 0:3b00827bb0b7 | 254 | /* Get next free descriptor index */ |
AdamGreen | 0:3b00827bb0b7 | 255 | idx = lpc_enetif->rx_fill_desc_index; |
AdamGreen | 0:3b00827bb0b7 | 256 | |
AdamGreen | 0:3b00827bb0b7 | 257 | /* Setup descriptor and clear statuses */ |
AdamGreen | 0:3b00827bb0b7 | 258 | lpc_enetif->prxd[idx].control = EMAC_RCTRL_INT | ((u32_t) (p->len - 1)); |
AdamGreen | 0:3b00827bb0b7 | 259 | lpc_enetif->prxd[idx].packet = (u32_t) p->payload; |
AdamGreen | 0:3b00827bb0b7 | 260 | lpc_enetif->prxs[idx].statusinfo = 0xFFFFFFFF; |
AdamGreen | 0:3b00827bb0b7 | 261 | lpc_enetif->prxs[idx].statushashcrc = 0xFFFFFFFF; |
AdamGreen | 0:3b00827bb0b7 | 262 | |
AdamGreen | 0:3b00827bb0b7 | 263 | /* Save pbuf pointer for push to network layer later */ |
AdamGreen | 0:3b00827bb0b7 | 264 | lpc_enetif->rxb[idx] = p; |
AdamGreen | 0:3b00827bb0b7 | 265 | |
AdamGreen | 0:3b00827bb0b7 | 266 | /* Wrap at end of descriptor list */ |
AdamGreen | 0:3b00827bb0b7 | 267 | idx++; |
AdamGreen | 0:3b00827bb0b7 | 268 | if (idx >= LPC_NUM_BUFF_RXDESCS) |
AdamGreen | 0:3b00827bb0b7 | 269 | idx = 0; |
AdamGreen | 0:3b00827bb0b7 | 270 | |
AdamGreen | 0:3b00827bb0b7 | 271 | /* Queue descriptor(s) */ |
AdamGreen | 0:3b00827bb0b7 | 272 | lpc_enetif->rx_free_descs -= 1; |
AdamGreen | 0:3b00827bb0b7 | 273 | lpc_enetif->rx_fill_desc_index = idx; |
AdamGreen | 0:3b00827bb0b7 | 274 | LPC_EMAC->RxConsumeIndex = idx; |
AdamGreen | 0:3b00827bb0b7 | 275 | |
AdamGreen | 0:3b00827bb0b7 | 276 | LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, |
AdamGreen | 0:3b00827bb0b7 | 277 | ("lpc_rxqueue_pbuf: pbuf packet queued: %p (free desc=%d)\n", p, |
AdamGreen | 0:3b00827bb0b7 | 278 | lpc_enetif->rx_free_descs)); |
AdamGreen | 0:3b00827bb0b7 | 279 | } |
AdamGreen | 0:3b00827bb0b7 | 280 | |
AdamGreen | 0:3b00827bb0b7 | 281 | /** \brief Attempt to allocate and requeue a new pbuf for RX |
AdamGreen | 0:3b00827bb0b7 | 282 | * |
AdamGreen | 0:3b00827bb0b7 | 283 | * \param[in] netif Pointer to the netif structure |
AdamGreen | 0:3b00827bb0b7 | 284 | * \returns 1 if a packet was allocated and requeued, otherwise 0 |
AdamGreen | 0:3b00827bb0b7 | 285 | */ |
AdamGreen | 0:3b00827bb0b7 | 286 | s32_t lpc_rx_queue(struct netif *netif) |
AdamGreen | 0:3b00827bb0b7 | 287 | { |
AdamGreen | 0:3b00827bb0b7 | 288 | struct lpc_enetdata *lpc_enetif = netif->state; |
AdamGreen | 0:3b00827bb0b7 | 289 | struct pbuf *p; |
AdamGreen | 0:3b00827bb0b7 | 290 | s32_t queued = 0; |
AdamGreen | 0:3b00827bb0b7 | 291 | |
AdamGreen | 0:3b00827bb0b7 | 292 | /* Attempt to requeue as many packets as possible */ |
AdamGreen | 0:3b00827bb0b7 | 293 | while (lpc_enetif->rx_free_descs > 0) { |
AdamGreen | 0:3b00827bb0b7 | 294 | /* Allocate a pbuf from the pool. We need to allocate at the |
AdamGreen | 0:3b00827bb0b7 | 295 | maximum size as we don't know the size of the yet to be |
AdamGreen | 0:3b00827bb0b7 | 296 | received packet. */ |
AdamGreen | 0:3b00827bb0b7 | 297 | p = pbuf_alloc(PBUF_RAW, (u16_t) EMAC_ETH_MAX_FLEN, PBUF_RAM); |
AdamGreen | 0:3b00827bb0b7 | 298 | if (p == NULL) { |
AdamGreen | 0:3b00827bb0b7 | 299 | LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, |
AdamGreen | 0:3b00827bb0b7 | 300 | ("lpc_rx_queue: could not allocate RX pbuf (free desc=%d)\n", |
AdamGreen | 0:3b00827bb0b7 | 301 | lpc_enetif->rx_free_descs)); |
AdamGreen | 0:3b00827bb0b7 | 302 | return queued; |
AdamGreen | 0:3b00827bb0b7 | 303 | } |
AdamGreen | 0:3b00827bb0b7 | 304 | |
AdamGreen | 0:3b00827bb0b7 | 305 | /* pbufs allocated from the RAM pool should be non-chained. */ |
AdamGreen | 0:3b00827bb0b7 | 306 | LWIP_ASSERT("lpc_rx_queue: pbuf is not contiguous (chained)", |
AdamGreen | 0:3b00827bb0b7 | 307 | pbuf_clen(p) <= 1); |
AdamGreen | 0:3b00827bb0b7 | 308 | |
AdamGreen | 0:3b00827bb0b7 | 309 | /* Queue packet */ |
AdamGreen | 0:3b00827bb0b7 | 310 | lpc_rxqueue_pbuf(lpc_enetif, p); |
AdamGreen | 0:3b00827bb0b7 | 311 | |
AdamGreen | 0:3b00827bb0b7 | 312 | /* Update queued count */ |
AdamGreen | 0:3b00827bb0b7 | 313 | queued++; |
AdamGreen | 0:3b00827bb0b7 | 314 | } |
AdamGreen | 0:3b00827bb0b7 | 315 | |
AdamGreen | 0:3b00827bb0b7 | 316 | return queued; |
AdamGreen | 0:3b00827bb0b7 | 317 | } |
AdamGreen | 0:3b00827bb0b7 | 318 | |
AdamGreen | 0:3b00827bb0b7 | 319 | /** \brief Sets up the RX descriptor ring buffers. |
AdamGreen | 0:3b00827bb0b7 | 320 | * |
AdamGreen | 0:3b00827bb0b7 | 321 | * This function sets up the descriptor list used for receive packets. |
AdamGreen | 0:3b00827bb0b7 | 322 | * |
AdamGreen | 0:3b00827bb0b7 | 323 | * \param[in] lpc_enetif Pointer to driver data structure |
AdamGreen | 0:3b00827bb0b7 | 324 | * \returns Always returns ERR_OK |
AdamGreen | 0:3b00827bb0b7 | 325 | */ |
AdamGreen | 0:3b00827bb0b7 | 326 | static err_t lpc_rx_setup(struct lpc_enetdata *lpc_enetif) |
AdamGreen | 0:3b00827bb0b7 | 327 | { |
AdamGreen | 0:3b00827bb0b7 | 328 | /* Setup pointers to RX structures */ |
AdamGreen | 0:3b00827bb0b7 | 329 | LPC_EMAC->RxDescriptor = (u32_t) &lpc_enetif->prxd[0]; |
AdamGreen | 0:3b00827bb0b7 | 330 | LPC_EMAC->RxStatus = (u32_t) &lpc_enetif->prxs[0]; |
AdamGreen | 0:3b00827bb0b7 | 331 | LPC_EMAC->RxDescriptorNumber = LPC_NUM_BUFF_RXDESCS - 1; |
AdamGreen | 0:3b00827bb0b7 | 332 | |
AdamGreen | 0:3b00827bb0b7 | 333 | lpc_enetif->rx_free_descs = LPC_NUM_BUFF_RXDESCS; |
AdamGreen | 0:3b00827bb0b7 | 334 | lpc_enetif->rx_fill_desc_index = 0; |
AdamGreen | 0:3b00827bb0b7 | 335 | |
AdamGreen | 0:3b00827bb0b7 | 336 | /* Build RX buffer and descriptors */ |
AdamGreen | 0:3b00827bb0b7 | 337 | lpc_rx_queue(lpc_enetif->netif); |
AdamGreen | 0:3b00827bb0b7 | 338 | |
AdamGreen | 0:3b00827bb0b7 | 339 | return ERR_OK; |
AdamGreen | 0:3b00827bb0b7 | 340 | } |
AdamGreen | 0:3b00827bb0b7 | 341 | |
AdamGreen | 0:3b00827bb0b7 | 342 | /** \brief Allocates a pbuf and returns the data from the incoming packet. |
AdamGreen | 0:3b00827bb0b7 | 343 | * |
AdamGreen | 0:3b00827bb0b7 | 344 | * \param[in] netif the lwip network interface structure for this lpc_enetif |
AdamGreen | 0:3b00827bb0b7 | 345 | * \return a pbuf filled with the received packet (including MAC header) |
AdamGreen | 0:3b00827bb0b7 | 346 | * NULL on memory error |
AdamGreen | 0:3b00827bb0b7 | 347 | */ |
AdamGreen | 0:3b00827bb0b7 | 348 | static struct pbuf *lpc_low_level_input(struct netif *netif) |
AdamGreen | 0:3b00827bb0b7 | 349 | { |
AdamGreen | 0:3b00827bb0b7 | 350 | struct lpc_enetdata *lpc_enetif = netif->state; |
AdamGreen | 0:3b00827bb0b7 | 351 | struct pbuf *p = NULL; |
AdamGreen | 0:3b00827bb0b7 | 352 | u32_t idx, length; |
AdamGreen | 0:3b00827bb0b7 | 353 | u16_t origLength; |
AdamGreen | 0:3b00827bb0b7 | 354 | |
AdamGreen | 0:3b00827bb0b7 | 355 | #ifdef LOCK_RX_THREAD |
AdamGreen | 0:3b00827bb0b7 | 356 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 357 | /* Get exclusive access */ |
AdamGreen | 0:3b00827bb0b7 | 358 | sys_mutex_lock(&lpc_enetif->TXLockMutex); |
AdamGreen | 0:3b00827bb0b7 | 359 | #endif |
AdamGreen | 0:3b00827bb0b7 | 360 | #endif |
AdamGreen | 0:3b00827bb0b7 | 361 | |
AdamGreen | 0:3b00827bb0b7 | 362 | /* Monitor RX overrun status. This should never happen unless |
AdamGreen | 0:3b00827bb0b7 | 363 | (possibly) the internal bus is behing held up by something. |
AdamGreen | 0:3b00827bb0b7 | 364 | Unless your system is running at a very low clock speed or |
AdamGreen | 0:3b00827bb0b7 | 365 | there are possibilities that the internal buses may be held |
AdamGreen | 0:3b00827bb0b7 | 366 | up for a long time, this can probably safely be removed. */ |
AdamGreen | 0:3b00827bb0b7 | 367 | if (LPC_EMAC->IntStatus & EMAC_INT_RX_OVERRUN) { |
AdamGreen | 0:3b00827bb0b7 | 368 | LINK_STATS_INC(link.err); |
AdamGreen | 0:3b00827bb0b7 | 369 | LINK_STATS_INC(link.drop); |
AdamGreen | 0:3b00827bb0b7 | 370 | |
AdamGreen | 0:3b00827bb0b7 | 371 | /* Temporarily disable RX */ |
AdamGreen | 0:3b00827bb0b7 | 372 | LPC_EMAC->MAC1 &= ~EMAC_MAC1_REC_EN; |
AdamGreen | 0:3b00827bb0b7 | 373 | |
AdamGreen | 0:3b00827bb0b7 | 374 | /* Reset the RX side */ |
AdamGreen | 0:3b00827bb0b7 | 375 | LPC_EMAC->MAC1 |= EMAC_MAC1_RES_RX; |
AdamGreen | 0:3b00827bb0b7 | 376 | LPC_EMAC->IntClear = EMAC_INT_RX_OVERRUN; |
AdamGreen | 0:3b00827bb0b7 | 377 | |
AdamGreen | 0:3b00827bb0b7 | 378 | /* De-allocate all queued RX pbufs */ |
AdamGreen | 0:3b00827bb0b7 | 379 | for (idx = 0; idx < LPC_NUM_BUFF_RXDESCS; idx++) { |
AdamGreen | 0:3b00827bb0b7 | 380 | if (lpc_enetif->rxb[idx] != NULL) { |
AdamGreen | 0:3b00827bb0b7 | 381 | pbuf_free(lpc_enetif->rxb[idx]); |
AdamGreen | 0:3b00827bb0b7 | 382 | lpc_enetif->rxb[idx] = NULL; |
AdamGreen | 0:3b00827bb0b7 | 383 | } |
AdamGreen | 0:3b00827bb0b7 | 384 | } |
AdamGreen | 0:3b00827bb0b7 | 385 | |
AdamGreen | 0:3b00827bb0b7 | 386 | /* Start RX side again */ |
AdamGreen | 0:3b00827bb0b7 | 387 | lpc_rx_setup(lpc_enetif); |
AdamGreen | 0:3b00827bb0b7 | 388 | |
AdamGreen | 0:3b00827bb0b7 | 389 | /* Re-enable RX */ |
AdamGreen | 0:3b00827bb0b7 | 390 | LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN; |
AdamGreen | 0:3b00827bb0b7 | 391 | |
AdamGreen | 0:3b00827bb0b7 | 392 | #ifdef LOCK_RX_THREAD |
AdamGreen | 0:3b00827bb0b7 | 393 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 394 | sys_mutex_unlock(&lpc_enetif->TXLockMutex); |
AdamGreen | 0:3b00827bb0b7 | 395 | #endif |
AdamGreen | 0:3b00827bb0b7 | 396 | #endif |
AdamGreen | 0:3b00827bb0b7 | 397 | |
AdamGreen | 0:3b00827bb0b7 | 398 | return NULL; |
AdamGreen | 0:3b00827bb0b7 | 399 | } |
AdamGreen | 0:3b00827bb0b7 | 400 | |
AdamGreen | 0:3b00827bb0b7 | 401 | /* Determine if a frame has been received */ |
AdamGreen | 0:3b00827bb0b7 | 402 | length = 0; |
AdamGreen | 0:3b00827bb0b7 | 403 | idx = LPC_EMAC->RxConsumeIndex; |
AdamGreen | 0:3b00827bb0b7 | 404 | if (LPC_EMAC->RxProduceIndex != idx) { |
AdamGreen | 0:3b00827bb0b7 | 405 | /* Handle errors */ |
AdamGreen | 0:3b00827bb0b7 | 406 | if (lpc_enetif->prxs[idx].statusinfo & (EMAC_RINFO_CRC_ERR | |
AdamGreen | 0:3b00827bb0b7 | 407 | EMAC_RINFO_SYM_ERR | EMAC_RINFO_ALIGN_ERR | EMAC_RINFO_LEN_ERR)) { |
AdamGreen | 0:3b00827bb0b7 | 408 | #if LINK_STATS |
AdamGreen | 0:3b00827bb0b7 | 409 | if (lpc_enetif->prxs[idx].statusinfo & (EMAC_RINFO_CRC_ERR | |
AdamGreen | 0:3b00827bb0b7 | 410 | EMAC_RINFO_SYM_ERR | EMAC_RINFO_ALIGN_ERR)) |
AdamGreen | 0:3b00827bb0b7 | 411 | LINK_STATS_INC(link.chkerr); |
AdamGreen | 0:3b00827bb0b7 | 412 | if (lpc_enetif->prxs[idx].statusinfo & EMAC_RINFO_LEN_ERR) |
AdamGreen | 0:3b00827bb0b7 | 413 | LINK_STATS_INC(link.lenerr); |
AdamGreen | 0:3b00827bb0b7 | 414 | #endif |
AdamGreen | 0:3b00827bb0b7 | 415 | |
AdamGreen | 0:3b00827bb0b7 | 416 | /* Drop the frame */ |
AdamGreen | 0:3b00827bb0b7 | 417 | LINK_STATS_INC(link.drop); |
AdamGreen | 0:3b00827bb0b7 | 418 | |
AdamGreen | 0:3b00827bb0b7 | 419 | /* Re-queue the pbuf for receive */ |
AdamGreen | 0:3b00827bb0b7 | 420 | lpc_enetif->rx_free_descs++; |
AdamGreen | 0:3b00827bb0b7 | 421 | p = lpc_enetif->rxb[idx]; |
AdamGreen | 0:3b00827bb0b7 | 422 | lpc_enetif->rxb[idx] = NULL; |
AdamGreen | 0:3b00827bb0b7 | 423 | lpc_rxqueue_pbuf(lpc_enetif, p); |
AdamGreen | 0:3b00827bb0b7 | 424 | |
AdamGreen | 0:3b00827bb0b7 | 425 | LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, |
AdamGreen | 0:3b00827bb0b7 | 426 | ("lpc_low_level_input: Packet dropped with errors (0x%x)\n", |
AdamGreen | 0:3b00827bb0b7 | 427 | lpc_enetif->prxs[idx].statusinfo)); |
AdamGreen | 0:3b00827bb0b7 | 428 | |
AdamGreen | 0:3b00827bb0b7 | 429 | p = NULL; |
AdamGreen | 0:3b00827bb0b7 | 430 | } else { |
AdamGreen | 0:3b00827bb0b7 | 431 | /* A packet is waiting, get length */ |
AdamGreen | 0:3b00827bb0b7 | 432 | length = (lpc_enetif->prxs[idx].statusinfo & 0x7FF) + 1; |
AdamGreen | 0:3b00827bb0b7 | 433 | |
AdamGreen | 0:3b00827bb0b7 | 434 | /* Zero-copy */ |
AdamGreen | 0:3b00827bb0b7 | 435 | p = lpc_enetif->rxb[idx]; |
AdamGreen | 0:3b00827bb0b7 | 436 | origLength = p->len; |
AdamGreen | 0:3b00827bb0b7 | 437 | p->len = (u16_t) length; |
AdamGreen | 0:3b00827bb0b7 | 438 | |
AdamGreen | 0:3b00827bb0b7 | 439 | /* Free pbuf from descriptor */ |
AdamGreen | 0:3b00827bb0b7 | 440 | lpc_enetif->rxb[idx] = NULL; |
AdamGreen | 0:3b00827bb0b7 | 441 | lpc_enetif->rx_free_descs++; |
AdamGreen | 0:3b00827bb0b7 | 442 | |
AdamGreen | 0:3b00827bb0b7 | 443 | /* Attempt to queue new buffer(s) */ |
AdamGreen | 0:3b00827bb0b7 | 444 | if (lpc_rx_queue(lpc_enetif->netif) == 0) { |
AdamGreen | 0:3b00827bb0b7 | 445 | /* Drop the frame due to OOM. */ |
AdamGreen | 0:3b00827bb0b7 | 446 | LINK_STATS_INC(link.drop); |
AdamGreen | 0:3b00827bb0b7 | 447 | |
AdamGreen | 0:3b00827bb0b7 | 448 | /* Re-queue the pbuf for receive */ |
AdamGreen | 0:3b00827bb0b7 | 449 | p->len = origLength; |
AdamGreen | 0:3b00827bb0b7 | 450 | lpc_rxqueue_pbuf(lpc_enetif, p); |
AdamGreen | 0:3b00827bb0b7 | 451 | |
AdamGreen | 0:3b00827bb0b7 | 452 | LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, |
AdamGreen | 0:3b00827bb0b7 | 453 | ("lpc_low_level_input: Packet index %d dropped for OOM\n", |
AdamGreen | 0:3b00827bb0b7 | 454 | idx)); |
AdamGreen | 0:3b00827bb0b7 | 455 | |
AdamGreen | 0:3b00827bb0b7 | 456 | #ifdef LOCK_RX_THREAD |
AdamGreen | 0:3b00827bb0b7 | 457 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 458 | sys_mutex_unlock(&lpc_enetif->TXLockMutex); |
AdamGreen | 0:3b00827bb0b7 | 459 | #endif |
AdamGreen | 0:3b00827bb0b7 | 460 | #endif |
AdamGreen | 0:3b00827bb0b7 | 461 | |
AdamGreen | 0:3b00827bb0b7 | 462 | return NULL; |
AdamGreen | 0:3b00827bb0b7 | 463 | } |
AdamGreen | 0:3b00827bb0b7 | 464 | |
AdamGreen | 0:3b00827bb0b7 | 465 | LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, |
AdamGreen | 0:3b00827bb0b7 | 466 | ("lpc_low_level_input: Packet received: %p, size %d (index=%d)\n", |
AdamGreen | 0:3b00827bb0b7 | 467 | p, length, idx)); |
AdamGreen | 0:3b00827bb0b7 | 468 | |
AdamGreen | 0:3b00827bb0b7 | 469 | /* Save size */ |
AdamGreen | 0:3b00827bb0b7 | 470 | p->tot_len = (u16_t) length; |
AdamGreen | 0:3b00827bb0b7 | 471 | LINK_STATS_INC(link.recv); |
AdamGreen | 0:3b00827bb0b7 | 472 | } |
AdamGreen | 0:3b00827bb0b7 | 473 | } |
AdamGreen | 0:3b00827bb0b7 | 474 | |
AdamGreen | 0:3b00827bb0b7 | 475 | #ifdef LOCK_RX_THREAD |
AdamGreen | 0:3b00827bb0b7 | 476 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 477 | sys_mutex_unlock(&lpc_enetif->TXLockMutex); |
AdamGreen | 0:3b00827bb0b7 | 478 | #endif |
AdamGreen | 0:3b00827bb0b7 | 479 | #endif |
AdamGreen | 0:3b00827bb0b7 | 480 | |
AdamGreen | 0:3b00827bb0b7 | 481 | return p; |
AdamGreen | 0:3b00827bb0b7 | 482 | } |
AdamGreen | 0:3b00827bb0b7 | 483 | |
AdamGreen | 0:3b00827bb0b7 | 484 | /** \brief Attempt to read a packet from the EMAC interface. |
AdamGreen | 0:3b00827bb0b7 | 485 | * |
AdamGreen | 0:3b00827bb0b7 | 486 | * \param[in] netif the lwip network interface structure for this lpc_enetif |
AdamGreen | 0:3b00827bb0b7 | 487 | */ |
AdamGreen | 0:3b00827bb0b7 | 488 | void lpc_enetif_input(struct netif *netif) |
AdamGreen | 0:3b00827bb0b7 | 489 | { |
AdamGreen | 0:3b00827bb0b7 | 490 | struct eth_hdr *ethhdr; |
AdamGreen | 0:3b00827bb0b7 | 491 | struct pbuf *p; |
AdamGreen | 0:3b00827bb0b7 | 492 | |
AdamGreen | 0:3b00827bb0b7 | 493 | /* move received packet into a new pbuf */ |
AdamGreen | 0:3b00827bb0b7 | 494 | p = lpc_low_level_input(netif); |
AdamGreen | 0:3b00827bb0b7 | 495 | if (p == NULL) |
AdamGreen | 0:3b00827bb0b7 | 496 | return; |
AdamGreen | 0:3b00827bb0b7 | 497 | |
AdamGreen | 0:3b00827bb0b7 | 498 | /* points to packet payload, which starts with an Ethernet header */ |
AdamGreen | 0:3b00827bb0b7 | 499 | ethhdr = p->payload; |
AdamGreen | 0:3b00827bb0b7 | 500 | |
AdamGreen | 0:3b00827bb0b7 | 501 | switch (htons(ethhdr->type)) { |
AdamGreen | 0:3b00827bb0b7 | 502 | case ETHTYPE_IP: |
AdamGreen | 0:3b00827bb0b7 | 503 | case ETHTYPE_ARP: |
AdamGreen | 0:3b00827bb0b7 | 504 | #if PPPOE_SUPPORT |
AdamGreen | 0:3b00827bb0b7 | 505 | case ETHTYPE_PPPOEDISC: |
AdamGreen | 0:3b00827bb0b7 | 506 | case ETHTYPE_PPPOE: |
AdamGreen | 0:3b00827bb0b7 | 507 | #endif /* PPPOE_SUPPORT */ |
AdamGreen | 0:3b00827bb0b7 | 508 | /* full packet send to tcpip_thread to process */ |
AdamGreen | 0:3b00827bb0b7 | 509 | if (netif->input(p, netif) != ERR_OK) { |
AdamGreen | 0:3b00827bb0b7 | 510 | LWIP_DEBUGF(NETIF_DEBUG, ("lpc_enetif_input: IP input error\n")); |
AdamGreen | 0:3b00827bb0b7 | 511 | /* Free buffer */ |
AdamGreen | 0:3b00827bb0b7 | 512 | pbuf_free(p); |
AdamGreen | 0:3b00827bb0b7 | 513 | } |
AdamGreen | 0:3b00827bb0b7 | 514 | break; |
AdamGreen | 0:3b00827bb0b7 | 515 | |
AdamGreen | 0:3b00827bb0b7 | 516 | default: |
AdamGreen | 0:3b00827bb0b7 | 517 | /* Return buffer */ |
AdamGreen | 0:3b00827bb0b7 | 518 | pbuf_free(p); |
AdamGreen | 0:3b00827bb0b7 | 519 | break; |
AdamGreen | 0:3b00827bb0b7 | 520 | } |
AdamGreen | 0:3b00827bb0b7 | 521 | } |
AdamGreen | 0:3b00827bb0b7 | 522 | |
AdamGreen | 0:3b00827bb0b7 | 523 | /** \brief Determine if the passed address is usable for the ethernet |
AdamGreen | 0:3b00827bb0b7 | 524 | * DMA controller. |
AdamGreen | 0:3b00827bb0b7 | 525 | * |
AdamGreen | 0:3b00827bb0b7 | 526 | * \param[in] addr Address of packet to check for DMA safe operation |
AdamGreen | 0:3b00827bb0b7 | 527 | * \return 1 if the packet address is not safe, otherwise 0 |
AdamGreen | 0:3b00827bb0b7 | 528 | */ |
AdamGreen | 0:3b00827bb0b7 | 529 | static s32_t lpc_packet_addr_notsafe(void *addr) { |
AdamGreen | 0:3b00827bb0b7 | 530 | /* Check for legal address ranges */ |
AdamGreen | 0:3b00827bb0b7 | 531 | #if defined(TARGET_LPC1768) |
AdamGreen | 0:3b00827bb0b7 | 532 | if ((((u32_t) addr >= 0x2007C000) && ((u32_t) addr < 0x20083FFF))) { |
AdamGreen | 0:3b00827bb0b7 | 533 | #elif defined(TARGET_LPC4088) |
AdamGreen | 0:3b00827bb0b7 | 534 | if ((((u32_t) addr >= 0x20000000) && ((u32_t) addr < 0x20007FFF))) { |
AdamGreen | 0:3b00827bb0b7 | 535 | #endif |
AdamGreen | 0:3b00827bb0b7 | 536 | return 0; |
AdamGreen | 0:3b00827bb0b7 | 537 | } |
AdamGreen | 0:3b00827bb0b7 | 538 | return 1; |
AdamGreen | 0:3b00827bb0b7 | 539 | } |
AdamGreen | 0:3b00827bb0b7 | 540 | |
AdamGreen | 0:3b00827bb0b7 | 541 | /** \brief Sets up the TX descriptor ring buffers. |
AdamGreen | 0:3b00827bb0b7 | 542 | * |
AdamGreen | 0:3b00827bb0b7 | 543 | * This function sets up the descriptor list used for transmit packets. |
AdamGreen | 0:3b00827bb0b7 | 544 | * |
AdamGreen | 0:3b00827bb0b7 | 545 | * \param[in] lpc_enetif Pointer to driver data structure |
AdamGreen | 0:3b00827bb0b7 | 546 | */ |
AdamGreen | 0:3b00827bb0b7 | 547 | static err_t lpc_tx_setup(struct lpc_enetdata *lpc_enetif) |
AdamGreen | 0:3b00827bb0b7 | 548 | { |
AdamGreen | 0:3b00827bb0b7 | 549 | s32_t idx; |
AdamGreen | 0:3b00827bb0b7 | 550 | |
AdamGreen | 0:3b00827bb0b7 | 551 | /* Build TX descriptors for local buffers */ |
AdamGreen | 0:3b00827bb0b7 | 552 | for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) { |
AdamGreen | 0:3b00827bb0b7 | 553 | lpc_enetif->ptxd[idx].control = 0; |
AdamGreen | 0:3b00827bb0b7 | 554 | lpc_enetif->ptxs[idx].statusinfo = 0xFFFFFFFF; |
AdamGreen | 0:3b00827bb0b7 | 555 | } |
AdamGreen | 0:3b00827bb0b7 | 556 | |
AdamGreen | 0:3b00827bb0b7 | 557 | /* Setup pointers to TX structures */ |
AdamGreen | 0:3b00827bb0b7 | 558 | LPC_EMAC->TxDescriptor = (u32_t) &lpc_enetif->ptxd[0]; |
AdamGreen | 0:3b00827bb0b7 | 559 | LPC_EMAC->TxStatus = (u32_t) &lpc_enetif->ptxs[0]; |
AdamGreen | 0:3b00827bb0b7 | 560 | LPC_EMAC->TxDescriptorNumber = LPC_NUM_BUFF_TXDESCS - 1; |
AdamGreen | 0:3b00827bb0b7 | 561 | |
AdamGreen | 0:3b00827bb0b7 | 562 | lpc_enetif->lpc_last_tx_idx = 0; |
AdamGreen | 0:3b00827bb0b7 | 563 | |
AdamGreen | 0:3b00827bb0b7 | 564 | return ERR_OK; |
AdamGreen | 0:3b00827bb0b7 | 565 | } |
AdamGreen | 0:3b00827bb0b7 | 566 | |
AdamGreen | 0:3b00827bb0b7 | 567 | /** \brief Free TX buffers that are complete |
AdamGreen | 0:3b00827bb0b7 | 568 | * |
AdamGreen | 0:3b00827bb0b7 | 569 | * \param[in] lpc_enetif Pointer to driver data structure |
AdamGreen | 0:3b00827bb0b7 | 570 | * \param[in] cidx EMAC current descriptor comsumer index |
AdamGreen | 0:3b00827bb0b7 | 571 | */ |
AdamGreen | 0:3b00827bb0b7 | 572 | static void lpc_tx_reclaim_st(struct lpc_enetdata *lpc_enetif, u32_t cidx) |
AdamGreen | 0:3b00827bb0b7 | 573 | { |
AdamGreen | 0:3b00827bb0b7 | 574 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 575 | /* Get exclusive access */ |
AdamGreen | 0:3b00827bb0b7 | 576 | sys_mutex_lock(&lpc_enetif->TXLockMutex); |
AdamGreen | 0:3b00827bb0b7 | 577 | #endif |
AdamGreen | 0:3b00827bb0b7 | 578 | |
AdamGreen | 0:3b00827bb0b7 | 579 | while (cidx != lpc_enetif->lpc_last_tx_idx) { |
AdamGreen | 0:3b00827bb0b7 | 580 | if (lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx] != NULL) { |
AdamGreen | 0:3b00827bb0b7 | 581 | LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, |
AdamGreen | 0:3b00827bb0b7 | 582 | ("lpc_tx_reclaim_st: Freeing packet %p (index %d)\n", |
AdamGreen | 0:3b00827bb0b7 | 583 | lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx], |
AdamGreen | 0:3b00827bb0b7 | 584 | lpc_enetif->lpc_last_tx_idx)); |
AdamGreen | 0:3b00827bb0b7 | 585 | pbuf_free(lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx]); |
AdamGreen | 0:3b00827bb0b7 | 586 | lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx] = NULL; |
AdamGreen | 0:3b00827bb0b7 | 587 | } |
AdamGreen | 0:3b00827bb0b7 | 588 | |
AdamGreen | 0:3b00827bb0b7 | 589 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 590 | osSemaphoreRelease(lpc_enetif->xTXDCountSem.id); |
AdamGreen | 0:3b00827bb0b7 | 591 | #endif |
AdamGreen | 0:3b00827bb0b7 | 592 | lpc_enetif->lpc_last_tx_idx++; |
AdamGreen | 0:3b00827bb0b7 | 593 | if (lpc_enetif->lpc_last_tx_idx >= LPC_NUM_BUFF_TXDESCS) |
AdamGreen | 0:3b00827bb0b7 | 594 | lpc_enetif->lpc_last_tx_idx = 0; |
AdamGreen | 0:3b00827bb0b7 | 595 | } |
AdamGreen | 0:3b00827bb0b7 | 596 | |
AdamGreen | 0:3b00827bb0b7 | 597 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 598 | /* Restore access */ |
AdamGreen | 0:3b00827bb0b7 | 599 | sys_mutex_unlock(&lpc_enetif->TXLockMutex); |
AdamGreen | 0:3b00827bb0b7 | 600 | #endif |
AdamGreen | 0:3b00827bb0b7 | 601 | } |
AdamGreen | 0:3b00827bb0b7 | 602 | |
AdamGreen | 0:3b00827bb0b7 | 603 | /** \brief User call for freeingTX buffers that are complete |
AdamGreen | 0:3b00827bb0b7 | 604 | * |
AdamGreen | 0:3b00827bb0b7 | 605 | * \param[in] netif the lwip network interface structure for this lpc_enetif |
AdamGreen | 0:3b00827bb0b7 | 606 | */ |
AdamGreen | 0:3b00827bb0b7 | 607 | void lpc_tx_reclaim(struct netif *netif) |
AdamGreen | 0:3b00827bb0b7 | 608 | { |
AdamGreen | 0:3b00827bb0b7 | 609 | lpc_tx_reclaim_st((struct lpc_enetdata *) netif->state, |
AdamGreen | 0:3b00827bb0b7 | 610 | LPC_EMAC->TxConsumeIndex); |
AdamGreen | 0:3b00827bb0b7 | 611 | } |
AdamGreen | 0:3b00827bb0b7 | 612 | |
AdamGreen | 0:3b00827bb0b7 | 613 | /** \brief Polls if an available TX descriptor is ready. Can be used to |
AdamGreen | 0:3b00827bb0b7 | 614 | * determine if the low level transmit function will block. |
AdamGreen | 0:3b00827bb0b7 | 615 | * |
AdamGreen | 0:3b00827bb0b7 | 616 | * \param[in] netif the lwip network interface structure for this lpc_enetif |
AdamGreen | 0:3b00827bb0b7 | 617 | * \return 0 if no descriptors are read, or >0 |
AdamGreen | 0:3b00827bb0b7 | 618 | */ |
AdamGreen | 0:3b00827bb0b7 | 619 | s32_t lpc_tx_ready(struct netif *netif) |
AdamGreen | 0:3b00827bb0b7 | 620 | { |
AdamGreen | 0:3b00827bb0b7 | 621 | s32_t fb; |
AdamGreen | 0:3b00827bb0b7 | 622 | u32_t idx, cidx; |
AdamGreen | 0:3b00827bb0b7 | 623 | |
AdamGreen | 0:3b00827bb0b7 | 624 | cidx = LPC_EMAC->TxConsumeIndex; |
AdamGreen | 0:3b00827bb0b7 | 625 | idx = LPC_EMAC->TxProduceIndex; |
AdamGreen | 0:3b00827bb0b7 | 626 | |
AdamGreen | 0:3b00827bb0b7 | 627 | /* Determine number of free buffers */ |
AdamGreen | 0:3b00827bb0b7 | 628 | if (idx == cidx) |
AdamGreen | 0:3b00827bb0b7 | 629 | fb = LPC_NUM_BUFF_TXDESCS; |
AdamGreen | 0:3b00827bb0b7 | 630 | else if (cidx > idx) |
AdamGreen | 0:3b00827bb0b7 | 631 | fb = (LPC_NUM_BUFF_TXDESCS - 1) - |
AdamGreen | 0:3b00827bb0b7 | 632 | ((idx + LPC_NUM_BUFF_TXDESCS) - cidx); |
AdamGreen | 0:3b00827bb0b7 | 633 | else |
AdamGreen | 0:3b00827bb0b7 | 634 | fb = (LPC_NUM_BUFF_TXDESCS - 1) - (cidx - idx); |
AdamGreen | 0:3b00827bb0b7 | 635 | |
AdamGreen | 0:3b00827bb0b7 | 636 | return fb; |
AdamGreen | 0:3b00827bb0b7 | 637 | } |
AdamGreen | 0:3b00827bb0b7 | 638 | |
AdamGreen | 0:3b00827bb0b7 | 639 | /** \brief Low level output of a packet. Never call this from an |
AdamGreen | 0:3b00827bb0b7 | 640 | * interrupt context, as it may block until TX descriptors |
AdamGreen | 0:3b00827bb0b7 | 641 | * become available. |
AdamGreen | 0:3b00827bb0b7 | 642 | * |
AdamGreen | 0:3b00827bb0b7 | 643 | * \param[in] netif the lwip network interface structure for this lpc_enetif |
AdamGreen | 0:3b00827bb0b7 | 644 | * \param[in] p the MAC packet to send (e.g. IP packet including MAC addresses and type) |
AdamGreen | 0:3b00827bb0b7 | 645 | * \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent |
AdamGreen | 0:3b00827bb0b7 | 646 | */ |
AdamGreen | 0:3b00827bb0b7 | 647 | static err_t lpc_low_level_output(struct netif *netif, struct pbuf *p) |
AdamGreen | 0:3b00827bb0b7 | 648 | { |
AdamGreen | 0:3b00827bb0b7 | 649 | struct lpc_enetdata *lpc_enetif = netif->state; |
AdamGreen | 0:3b00827bb0b7 | 650 | struct pbuf *q; |
AdamGreen | 0:3b00827bb0b7 | 651 | u8_t *dst; |
AdamGreen | 0:3b00827bb0b7 | 652 | u32_t idx, notdmasafe = 0; |
AdamGreen | 0:3b00827bb0b7 | 653 | struct pbuf *np; |
AdamGreen | 0:3b00827bb0b7 | 654 | s32_t dn; |
AdamGreen | 0:3b00827bb0b7 | 655 | |
AdamGreen | 0:3b00827bb0b7 | 656 | /* Zero-copy TX buffers may be fragmented across mutliple payload |
AdamGreen | 0:3b00827bb0b7 | 657 | chains. Determine the number of descriptors needed for the |
AdamGreen | 0:3b00827bb0b7 | 658 | transfer. The pbuf chaining can be a mess! */ |
AdamGreen | 0:3b00827bb0b7 | 659 | dn = (s32_t) pbuf_clen(p); |
AdamGreen | 0:3b00827bb0b7 | 660 | |
AdamGreen | 0:3b00827bb0b7 | 661 | /* Test to make sure packet addresses are DMA safe. A DMA safe |
AdamGreen | 0:3b00827bb0b7 | 662 | address is once that uses external memory or periphheral RAM. |
AdamGreen | 0:3b00827bb0b7 | 663 | IRAM and FLASH are not safe! */ |
AdamGreen | 0:3b00827bb0b7 | 664 | for (q = p; q != NULL; q = q->next) |
AdamGreen | 0:3b00827bb0b7 | 665 | notdmasafe += lpc_packet_addr_notsafe(q->payload); |
AdamGreen | 0:3b00827bb0b7 | 666 | |
AdamGreen | 0:3b00827bb0b7 | 667 | #if LPC_TX_PBUF_BOUNCE_EN==1 |
AdamGreen | 0:3b00827bb0b7 | 668 | /* If the pbuf is not DMA safe, a new bounce buffer (pbuf) will be |
AdamGreen | 0:3b00827bb0b7 | 669 | created that will be used instead. This requires an copy from the |
AdamGreen | 0:3b00827bb0b7 | 670 | non-safe DMA region to the new pbuf */ |
AdamGreen | 0:3b00827bb0b7 | 671 | if (notdmasafe) { |
AdamGreen | 0:3b00827bb0b7 | 672 | /* Allocate a pbuf in DMA memory */ |
AdamGreen | 0:3b00827bb0b7 | 673 | np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); |
AdamGreen | 0:3b00827bb0b7 | 674 | if (np == NULL) |
AdamGreen | 0:3b00827bb0b7 | 675 | return ERR_MEM; |
AdamGreen | 0:3b00827bb0b7 | 676 | |
AdamGreen | 0:3b00827bb0b7 | 677 | /* This buffer better be contiguous! */ |
AdamGreen | 0:3b00827bb0b7 | 678 | LWIP_ASSERT("lpc_low_level_output: New transmit pbuf is chained", |
AdamGreen | 0:3b00827bb0b7 | 679 | (pbuf_clen(np) == 1)); |
AdamGreen | 0:3b00827bb0b7 | 680 | |
AdamGreen | 0:3b00827bb0b7 | 681 | /* Copy to DMA safe pbuf */ |
AdamGreen | 0:3b00827bb0b7 | 682 | dst = (u8_t *) np->payload; |
AdamGreen | 0:3b00827bb0b7 | 683 | for(q = p; q != NULL; q = q->next) { |
AdamGreen | 0:3b00827bb0b7 | 684 | /* Copy the buffer to the descriptor's buffer */ |
AdamGreen | 0:3b00827bb0b7 | 685 | MEMCPY(dst, (u8_t *) q->payload, q->len); |
AdamGreen | 0:3b00827bb0b7 | 686 | dst += q->len; |
AdamGreen | 0:3b00827bb0b7 | 687 | } |
AdamGreen | 0:3b00827bb0b7 | 688 | np->len = p->tot_len; |
AdamGreen | 0:3b00827bb0b7 | 689 | |
AdamGreen | 0:3b00827bb0b7 | 690 | LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, |
AdamGreen | 0:3b00827bb0b7 | 691 | ("lpc_low_level_output: Switched to DMA safe buffer, old=%p, new=%p\n", |
AdamGreen | 0:3b00827bb0b7 | 692 | q, np)); |
AdamGreen | 0:3b00827bb0b7 | 693 | |
AdamGreen | 0:3b00827bb0b7 | 694 | /* use the new buffer for descrptor queueing. The original pbuf will |
AdamGreen | 0:3b00827bb0b7 | 695 | be de-allocated outsuide this driver. */ |
AdamGreen | 0:3b00827bb0b7 | 696 | p = np; |
AdamGreen | 0:3b00827bb0b7 | 697 | dn = 1; |
AdamGreen | 0:3b00827bb0b7 | 698 | } |
AdamGreen | 0:3b00827bb0b7 | 699 | #else |
AdamGreen | 0:3b00827bb0b7 | 700 | if (notdmasafe) |
AdamGreen | 0:3b00827bb0b7 | 701 | LWIP_ASSERT("lpc_low_level_output: Not a DMA safe pbuf", |
AdamGreen | 0:3b00827bb0b7 | 702 | (notdmasafe == 0)); |
AdamGreen | 0:3b00827bb0b7 | 703 | #endif |
AdamGreen | 0:3b00827bb0b7 | 704 | |
AdamGreen | 0:3b00827bb0b7 | 705 | /* Wait until enough descriptors are available for the transfer. */ |
AdamGreen | 0:3b00827bb0b7 | 706 | /* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */ |
AdamGreen | 0:3b00827bb0b7 | 707 | while (dn > lpc_tx_ready(netif)) |
AdamGreen | 0:3b00827bb0b7 | 708 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 709 | osSemaphoreWait(lpc_enetif->xTXDCountSem.id, osWaitForever); |
AdamGreen | 0:3b00827bb0b7 | 710 | #else |
AdamGreen | 0:3b00827bb0b7 | 711 | osDelay(1); |
AdamGreen | 0:3b00827bb0b7 | 712 | #endif |
AdamGreen | 0:3b00827bb0b7 | 713 | |
AdamGreen | 0:3b00827bb0b7 | 714 | /* Get free TX buffer index */ |
AdamGreen | 0:3b00827bb0b7 | 715 | idx = LPC_EMAC->TxProduceIndex; |
AdamGreen | 0:3b00827bb0b7 | 716 | |
AdamGreen | 0:3b00827bb0b7 | 717 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 718 | /* Get exclusive access */ |
AdamGreen | 0:3b00827bb0b7 | 719 | sys_mutex_lock(&lpc_enetif->TXLockMutex); |
AdamGreen | 0:3b00827bb0b7 | 720 | #endif |
AdamGreen | 0:3b00827bb0b7 | 721 | |
AdamGreen | 0:3b00827bb0b7 | 722 | /* Prevent LWIP from de-allocating this pbuf. The driver will |
AdamGreen | 0:3b00827bb0b7 | 723 | free it once it's been transmitted. */ |
AdamGreen | 0:3b00827bb0b7 | 724 | if (!notdmasafe) |
AdamGreen | 0:3b00827bb0b7 | 725 | pbuf_ref(p); |
AdamGreen | 0:3b00827bb0b7 | 726 | |
AdamGreen | 0:3b00827bb0b7 | 727 | /* Setup transfers */ |
AdamGreen | 0:3b00827bb0b7 | 728 | q = p; |
AdamGreen | 0:3b00827bb0b7 | 729 | while (dn > 0) { |
AdamGreen | 0:3b00827bb0b7 | 730 | dn--; |
AdamGreen | 0:3b00827bb0b7 | 731 | |
AdamGreen | 0:3b00827bb0b7 | 732 | /* Only save pointer to free on last descriptor */ |
AdamGreen | 0:3b00827bb0b7 | 733 | if (dn == 0) { |
AdamGreen | 0:3b00827bb0b7 | 734 | /* Save size of packet and signal it's ready */ |
AdamGreen | 0:3b00827bb0b7 | 735 | lpc_enetif->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT | |
AdamGreen | 0:3b00827bb0b7 | 736 | EMAC_TCTRL_LAST; |
AdamGreen | 0:3b00827bb0b7 | 737 | lpc_enetif->txb[idx] = p; |
AdamGreen | 0:3b00827bb0b7 | 738 | } |
AdamGreen | 0:3b00827bb0b7 | 739 | else { |
AdamGreen | 0:3b00827bb0b7 | 740 | /* Save size of packet, descriptor is not last */ |
AdamGreen | 0:3b00827bb0b7 | 741 | lpc_enetif->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT; |
AdamGreen | 0:3b00827bb0b7 | 742 | lpc_enetif->txb[idx] = NULL; |
AdamGreen | 0:3b00827bb0b7 | 743 | } |
AdamGreen | 0:3b00827bb0b7 | 744 | |
AdamGreen | 0:3b00827bb0b7 | 745 | LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, |
AdamGreen | 0:3b00827bb0b7 | 746 | ("lpc_low_level_output: pbuf packet(%p) sent, chain#=%d," |
AdamGreen | 0:3b00827bb0b7 | 747 | " size = %d (index=%d)\n", q->payload, dn, q->len, idx)); |
AdamGreen | 0:3b00827bb0b7 | 748 | |
AdamGreen | 0:3b00827bb0b7 | 749 | lpc_enetif->ptxd[idx].packet = (u32_t) q->payload; |
AdamGreen | 0:3b00827bb0b7 | 750 | |
AdamGreen | 0:3b00827bb0b7 | 751 | q = q->next; |
AdamGreen | 0:3b00827bb0b7 | 752 | |
AdamGreen | 0:3b00827bb0b7 | 753 | idx++; |
AdamGreen | 0:3b00827bb0b7 | 754 | if (idx >= LPC_NUM_BUFF_TXDESCS) |
AdamGreen | 0:3b00827bb0b7 | 755 | idx = 0; |
AdamGreen | 0:3b00827bb0b7 | 756 | } |
AdamGreen | 0:3b00827bb0b7 | 757 | |
AdamGreen | 0:3b00827bb0b7 | 758 | LPC_EMAC->TxProduceIndex = idx; |
AdamGreen | 0:3b00827bb0b7 | 759 | |
AdamGreen | 0:3b00827bb0b7 | 760 | LINK_STATS_INC(link.xmit); |
AdamGreen | 0:3b00827bb0b7 | 761 | |
AdamGreen | 0:3b00827bb0b7 | 762 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 763 | /* Restore access */ |
AdamGreen | 0:3b00827bb0b7 | 764 | sys_mutex_unlock(&lpc_enetif->TXLockMutex); |
AdamGreen | 0:3b00827bb0b7 | 765 | #endif |
AdamGreen | 0:3b00827bb0b7 | 766 | |
AdamGreen | 0:3b00827bb0b7 | 767 | return ERR_OK; |
AdamGreen | 0:3b00827bb0b7 | 768 | } |
AdamGreen | 0:3b00827bb0b7 | 769 | |
AdamGreen | 0:3b00827bb0b7 | 770 | /** \brief LPC EMAC interrupt handler. |
AdamGreen | 0:3b00827bb0b7 | 771 | * |
AdamGreen | 0:3b00827bb0b7 | 772 | * This function handles the transmit, receive, and error interrupt of |
AdamGreen | 0:3b00827bb0b7 | 773 | * the LPC177x_8x. This is meant to be used when NO_SYS=0. |
AdamGreen | 0:3b00827bb0b7 | 774 | */ |
AdamGreen | 0:3b00827bb0b7 | 775 | void ENET_IRQHandler(void) |
AdamGreen | 0:3b00827bb0b7 | 776 | { |
AdamGreen | 0:3b00827bb0b7 | 777 | #if NO_SYS == 1 |
AdamGreen | 0:3b00827bb0b7 | 778 | /* Interrupts are not used without an RTOS */ |
AdamGreen | 0:3b00827bb0b7 | 779 | NVIC_DisableIRQ(ENET_IRQn); |
AdamGreen | 0:3b00827bb0b7 | 780 | #else |
AdamGreen | 0:3b00827bb0b7 | 781 | uint32_t ints; |
AdamGreen | 0:3b00827bb0b7 | 782 | |
AdamGreen | 0:3b00827bb0b7 | 783 | /* Interrupts are of 2 groups - transmit or receive. Based on the |
AdamGreen | 0:3b00827bb0b7 | 784 | interrupt, kick off the receive or transmit (cleanup) task */ |
AdamGreen | 0:3b00827bb0b7 | 785 | |
AdamGreen | 0:3b00827bb0b7 | 786 | /* Get pending interrupts */ |
AdamGreen | 0:3b00827bb0b7 | 787 | ints = LPC_EMAC->IntStatus; |
AdamGreen | 0:3b00827bb0b7 | 788 | |
AdamGreen | 0:3b00827bb0b7 | 789 | if (ints & RXINTGROUP) { |
AdamGreen | 0:3b00827bb0b7 | 790 | /* RX group interrupt(s): Give signal to wakeup RX receive task.*/ |
AdamGreen | 0:3b00827bb0b7 | 791 | osSignalSet(lpc_enetdata.RxThread->id, RX_SIGNAL); |
AdamGreen | 0:3b00827bb0b7 | 792 | } |
AdamGreen | 0:3b00827bb0b7 | 793 | |
AdamGreen | 0:3b00827bb0b7 | 794 | if (ints & TXINTGROUP) { |
AdamGreen | 0:3b00827bb0b7 | 795 | /* TX group interrupt(s): Give semaphore to wakeup TX cleanup task. */ |
AdamGreen | 0:3b00827bb0b7 | 796 | sys_sem_signal(&lpc_enetdata.TxCleanSem); |
AdamGreen | 0:3b00827bb0b7 | 797 | } |
AdamGreen | 0:3b00827bb0b7 | 798 | |
AdamGreen | 0:3b00827bb0b7 | 799 | /* Clear pending interrupts */ |
AdamGreen | 0:3b00827bb0b7 | 800 | LPC_EMAC->IntClear = ints; |
AdamGreen | 0:3b00827bb0b7 | 801 | #endif |
AdamGreen | 0:3b00827bb0b7 | 802 | } |
AdamGreen | 0:3b00827bb0b7 | 803 | |
AdamGreen | 0:3b00827bb0b7 | 804 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 805 | /** \brief Packet reception task |
AdamGreen | 0:3b00827bb0b7 | 806 | * |
AdamGreen | 0:3b00827bb0b7 | 807 | * This task is called when a packet is received. It will |
AdamGreen | 0:3b00827bb0b7 | 808 | * pass the packet to the LWIP core. |
AdamGreen | 0:3b00827bb0b7 | 809 | * |
AdamGreen | 0:3b00827bb0b7 | 810 | * \param[in] pvParameters Not used yet |
AdamGreen | 0:3b00827bb0b7 | 811 | */ |
AdamGreen | 0:3b00827bb0b7 | 812 | static void packet_rx(void* pvParameters) { |
AdamGreen | 0:3b00827bb0b7 | 813 | struct lpc_enetdata *lpc_enetif = pvParameters; |
AdamGreen | 0:3b00827bb0b7 | 814 | |
AdamGreen | 0:3b00827bb0b7 | 815 | while (1) { |
AdamGreen | 0:3b00827bb0b7 | 816 | /* Wait for receive task to wakeup */ |
AdamGreen | 0:3b00827bb0b7 | 817 | osSignalWait(RX_SIGNAL, osWaitForever); |
AdamGreen | 0:3b00827bb0b7 | 818 | |
AdamGreen | 0:3b00827bb0b7 | 819 | /* Process packets until all empty */ |
AdamGreen | 0:3b00827bb0b7 | 820 | while (LPC_EMAC->RxConsumeIndex != LPC_EMAC->RxProduceIndex) |
AdamGreen | 0:3b00827bb0b7 | 821 | lpc_enetif_input(lpc_enetif->netif); |
AdamGreen | 0:3b00827bb0b7 | 822 | } |
AdamGreen | 0:3b00827bb0b7 | 823 | } |
AdamGreen | 0:3b00827bb0b7 | 824 | |
AdamGreen | 0:3b00827bb0b7 | 825 | /** \brief Transmit cleanup task |
AdamGreen | 0:3b00827bb0b7 | 826 | * |
AdamGreen | 0:3b00827bb0b7 | 827 | * This task is called when a transmit interrupt occurs and |
AdamGreen | 0:3b00827bb0b7 | 828 | * reclaims the pbuf and descriptor used for the packet once |
AdamGreen | 0:3b00827bb0b7 | 829 | * the packet has been transferred. |
AdamGreen | 0:3b00827bb0b7 | 830 | * |
AdamGreen | 0:3b00827bb0b7 | 831 | * \param[in] pvParameters Not used yet |
AdamGreen | 0:3b00827bb0b7 | 832 | */ |
AdamGreen | 0:3b00827bb0b7 | 833 | static void packet_tx(void* pvParameters) { |
AdamGreen | 0:3b00827bb0b7 | 834 | struct lpc_enetdata *lpc_enetif = pvParameters; |
AdamGreen | 0:3b00827bb0b7 | 835 | s32_t idx; |
AdamGreen | 0:3b00827bb0b7 | 836 | |
AdamGreen | 0:3b00827bb0b7 | 837 | while (1) { |
AdamGreen | 0:3b00827bb0b7 | 838 | /* Wait for transmit cleanup task to wakeup */ |
AdamGreen | 0:3b00827bb0b7 | 839 | sys_arch_sem_wait(&lpc_enetif->TxCleanSem, 0); |
AdamGreen | 0:3b00827bb0b7 | 840 | |
AdamGreen | 0:3b00827bb0b7 | 841 | /* Error handling for TX underruns. This should never happen unless |
AdamGreen | 0:3b00827bb0b7 | 842 | something is holding the bus or the clocks are going too slow. It |
AdamGreen | 0:3b00827bb0b7 | 843 | can probably be safely removed. */ |
AdamGreen | 0:3b00827bb0b7 | 844 | if (LPC_EMAC->IntStatus & EMAC_INT_TX_UNDERRUN) { |
AdamGreen | 0:3b00827bb0b7 | 845 | LINK_STATS_INC(link.err); |
AdamGreen | 0:3b00827bb0b7 | 846 | LINK_STATS_INC(link.drop); |
AdamGreen | 0:3b00827bb0b7 | 847 | |
AdamGreen | 0:3b00827bb0b7 | 848 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 849 | /* Get exclusive access */ |
AdamGreen | 0:3b00827bb0b7 | 850 | sys_mutex_lock(&lpc_enetif->TXLockMutex); |
AdamGreen | 0:3b00827bb0b7 | 851 | #endif |
AdamGreen | 0:3b00827bb0b7 | 852 | /* Reset the TX side */ |
AdamGreen | 0:3b00827bb0b7 | 853 | LPC_EMAC->MAC1 |= EMAC_MAC1_RES_TX; |
AdamGreen | 0:3b00827bb0b7 | 854 | LPC_EMAC->IntClear = EMAC_INT_TX_UNDERRUN; |
AdamGreen | 0:3b00827bb0b7 | 855 | |
AdamGreen | 0:3b00827bb0b7 | 856 | /* De-allocate all queued TX pbufs */ |
AdamGreen | 0:3b00827bb0b7 | 857 | for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) { |
AdamGreen | 0:3b00827bb0b7 | 858 | if (lpc_enetif->txb[idx] != NULL) { |
AdamGreen | 0:3b00827bb0b7 | 859 | pbuf_free(lpc_enetif->txb[idx]); |
AdamGreen | 0:3b00827bb0b7 | 860 | lpc_enetif->txb[idx] = NULL; |
AdamGreen | 0:3b00827bb0b7 | 861 | } |
AdamGreen | 0:3b00827bb0b7 | 862 | } |
AdamGreen | 0:3b00827bb0b7 | 863 | |
AdamGreen | 0:3b00827bb0b7 | 864 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 865 | /* Restore access */ |
AdamGreen | 0:3b00827bb0b7 | 866 | sys_mutex_unlock(&lpc_enetif->TXLockMutex); |
AdamGreen | 0:3b00827bb0b7 | 867 | #endif |
AdamGreen | 0:3b00827bb0b7 | 868 | /* Start TX side again */ |
AdamGreen | 0:3b00827bb0b7 | 869 | lpc_tx_setup(lpc_enetif); |
AdamGreen | 0:3b00827bb0b7 | 870 | } else { |
AdamGreen | 0:3b00827bb0b7 | 871 | /* Free TX buffers that are done sending */ |
AdamGreen | 0:3b00827bb0b7 | 872 | lpc_tx_reclaim(lpc_enetdata.netif); |
AdamGreen | 0:3b00827bb0b7 | 873 | } |
AdamGreen | 0:3b00827bb0b7 | 874 | } |
AdamGreen | 0:3b00827bb0b7 | 875 | } |
AdamGreen | 0:3b00827bb0b7 | 876 | #endif |
AdamGreen | 0:3b00827bb0b7 | 877 | |
AdamGreen | 0:3b00827bb0b7 | 878 | /** \brief Low level init of the MAC and PHY. |
AdamGreen | 0:3b00827bb0b7 | 879 | * |
AdamGreen | 0:3b00827bb0b7 | 880 | * \param[in] netif Pointer to LWIP netif structure |
AdamGreen | 0:3b00827bb0b7 | 881 | */ |
AdamGreen | 0:3b00827bb0b7 | 882 | static err_t low_level_init(struct netif *netif) |
AdamGreen | 0:3b00827bb0b7 | 883 | { |
AdamGreen | 0:3b00827bb0b7 | 884 | struct lpc_enetdata *lpc_enetif = netif->state; |
AdamGreen | 0:3b00827bb0b7 | 885 | err_t err = ERR_OK; |
AdamGreen | 0:3b00827bb0b7 | 886 | |
AdamGreen | 0:3b00827bb0b7 | 887 | /* Enable MII clocking */ |
AdamGreen | 0:3b00827bb0b7 | 888 | LPC_SC->PCONP |= CLKPWR_PCONP_PCENET; |
AdamGreen | 0:3b00827bb0b7 | 889 | |
AdamGreen | 0:3b00827bb0b7 | 890 | #if defined(TARGET_LPC1768) |
AdamGreen | 0:3b00827bb0b7 | 891 | LPC_PINCON->PINSEL2 = 0x50150105; /* Enable P1 Ethernet Pins. */ |
AdamGreen | 0:3b00827bb0b7 | 892 | LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000005; |
AdamGreen | 0:3b00827bb0b7 | 893 | #elif defined(TARGET_LPC4088) |
AdamGreen | 0:3b00827bb0b7 | 894 | LPC_IOCON->P1_0 &= ~0x07; /* ENET I/O config */ |
AdamGreen | 0:3b00827bb0b7 | 895 | LPC_IOCON->P1_0 |= 0x01; /* ENET_TXD0 */ |
AdamGreen | 0:3b00827bb0b7 | 896 | LPC_IOCON->P1_1 &= ~0x07; |
AdamGreen | 0:3b00827bb0b7 | 897 | LPC_IOCON->P1_1 |= 0x01; /* ENET_TXD1 */ |
AdamGreen | 0:3b00827bb0b7 | 898 | LPC_IOCON->P1_4 &= ~0x07; |
AdamGreen | 0:3b00827bb0b7 | 899 | LPC_IOCON->P1_4 |= 0x01; /* ENET_TXEN */ |
AdamGreen | 0:3b00827bb0b7 | 900 | LPC_IOCON->P1_8 &= ~0x07; |
AdamGreen | 0:3b00827bb0b7 | 901 | LPC_IOCON->P1_8 |= 0x01; /* ENET_CRS */ |
AdamGreen | 0:3b00827bb0b7 | 902 | LPC_IOCON->P1_9 &= ~0x07; |
AdamGreen | 0:3b00827bb0b7 | 903 | LPC_IOCON->P1_9 |= 0x01; /* ENET_RXD0 */ |
AdamGreen | 0:3b00827bb0b7 | 904 | LPC_IOCON->P1_10 &= ~0x07; |
AdamGreen | 0:3b00827bb0b7 | 905 | LPC_IOCON->P1_10 |= 0x01; /* ENET_RXD1 */ |
AdamGreen | 0:3b00827bb0b7 | 906 | LPC_IOCON->P1_14 &= ~0x07; |
AdamGreen | 0:3b00827bb0b7 | 907 | LPC_IOCON->P1_14 |= 0x01; /* ENET_RX_ER */ |
AdamGreen | 0:3b00827bb0b7 | 908 | LPC_IOCON->P1_15 &= ~0x07; |
AdamGreen | 0:3b00827bb0b7 | 909 | LPC_IOCON->P1_15 |= 0x01; /* ENET_REF_CLK */ |
AdamGreen | 0:3b00827bb0b7 | 910 | LPC_IOCON->P1_16 &= ~0x07; /* ENET/PHY I/O config */ |
AdamGreen | 0:3b00827bb0b7 | 911 | LPC_IOCON->P1_16 |= 0x01; /* ENET_MDC */ |
AdamGreen | 0:3b00827bb0b7 | 912 | LPC_IOCON->P1_17 &= ~0x07; |
AdamGreen | 0:3b00827bb0b7 | 913 | LPC_IOCON->P1_17 |= 0x01; /* ENET_MDIO */ |
AdamGreen | 0:3b00827bb0b7 | 914 | #endif |
AdamGreen | 0:3b00827bb0b7 | 915 | |
AdamGreen | 0:3b00827bb0b7 | 916 | /* Reset all MAC logic */ |
AdamGreen | 0:3b00827bb0b7 | 917 | LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | |
AdamGreen | 0:3b00827bb0b7 | 918 | EMAC_MAC1_RES_RX | EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES | |
AdamGreen | 0:3b00827bb0b7 | 919 | EMAC_MAC1_SOFT_RES; |
AdamGreen | 0:3b00827bb0b7 | 920 | LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES | |
AdamGreen | 0:3b00827bb0b7 | 921 | EMAC_CR_PASS_RUNT_FRM; |
AdamGreen | 0:3b00827bb0b7 | 922 | osDelay(10); |
AdamGreen | 0:3b00827bb0b7 | 923 | |
AdamGreen | 0:3b00827bb0b7 | 924 | /* Initial MAC initialization */ |
AdamGreen | 0:3b00827bb0b7 | 925 | LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL; |
AdamGreen | 0:3b00827bb0b7 | 926 | LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN | |
AdamGreen | 0:3b00827bb0b7 | 927 | EMAC_MAC2_VLAN_PAD_EN; |
AdamGreen | 0:3b00827bb0b7 | 928 | LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN; |
AdamGreen | 0:3b00827bb0b7 | 929 | |
AdamGreen | 0:3b00827bb0b7 | 930 | /* Set RMII management clock rate to lowest speed */ |
AdamGreen | 0:3b00827bb0b7 | 931 | LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(11) | EMAC_MCFG_RES_MII; |
AdamGreen | 0:3b00827bb0b7 | 932 | LPC_EMAC->MCFG &= ~EMAC_MCFG_RES_MII; |
AdamGreen | 0:3b00827bb0b7 | 933 | |
AdamGreen | 0:3b00827bb0b7 | 934 | /* Maximum number of retries, 0x37 collision window, gap */ |
AdamGreen | 0:3b00827bb0b7 | 935 | LPC_EMAC->CLRT = EMAC_CLRT_DEF; |
AdamGreen | 0:3b00827bb0b7 | 936 | LPC_EMAC->IPGR = EMAC_IPGR_P1_DEF | EMAC_IPGR_P2_DEF; |
AdamGreen | 0:3b00827bb0b7 | 937 | |
AdamGreen | 0:3b00827bb0b7 | 938 | #if LPC_EMAC_RMII |
AdamGreen | 0:3b00827bb0b7 | 939 | /* RMII setup */ |
AdamGreen | 0:3b00827bb0b7 | 940 | LPC_EMAC->Command = EMAC_CR_PASS_RUNT_FRM | EMAC_CR_RMII; |
AdamGreen | 0:3b00827bb0b7 | 941 | #else |
AdamGreen | 0:3b00827bb0b7 | 942 | /* MII setup */ |
AdamGreen | 0:3b00827bb0b7 | 943 | LPC_EMAC->CR = EMAC_CR_PASS_RUNT_FRM; |
AdamGreen | 0:3b00827bb0b7 | 944 | #endif |
AdamGreen | 0:3b00827bb0b7 | 945 | |
AdamGreen | 0:3b00827bb0b7 | 946 | /* Initialize the PHY and reset */ |
AdamGreen | 0:3b00827bb0b7 | 947 | err = lpc_phy_init(netif, LPC_EMAC_RMII); |
AdamGreen | 0:3b00827bb0b7 | 948 | if (err != ERR_OK) |
AdamGreen | 0:3b00827bb0b7 | 949 | return err; |
AdamGreen | 0:3b00827bb0b7 | 950 | |
AdamGreen | 0:3b00827bb0b7 | 951 | /* Save station address */ |
AdamGreen | 0:3b00827bb0b7 | 952 | LPC_EMAC->SA2 = (u32_t) netif->hwaddr[0] | |
AdamGreen | 0:3b00827bb0b7 | 953 | (((u32_t) netif->hwaddr[1]) << 8); |
AdamGreen | 0:3b00827bb0b7 | 954 | LPC_EMAC->SA1 = (u32_t) netif->hwaddr[2] | |
AdamGreen | 0:3b00827bb0b7 | 955 | (((u32_t) netif->hwaddr[3]) << 8); |
AdamGreen | 0:3b00827bb0b7 | 956 | LPC_EMAC->SA0 = (u32_t) netif->hwaddr[4] | |
AdamGreen | 0:3b00827bb0b7 | 957 | (((u32_t) netif->hwaddr[5]) << 8); |
AdamGreen | 0:3b00827bb0b7 | 958 | |
AdamGreen | 0:3b00827bb0b7 | 959 | /* Setup transmit and receive descriptors */ |
AdamGreen | 0:3b00827bb0b7 | 960 | if (lpc_tx_setup(lpc_enetif) != ERR_OK) |
AdamGreen | 0:3b00827bb0b7 | 961 | return ERR_BUF; |
AdamGreen | 0:3b00827bb0b7 | 962 | if (lpc_rx_setup(lpc_enetif) != ERR_OK) |
AdamGreen | 0:3b00827bb0b7 | 963 | return ERR_BUF; |
AdamGreen | 0:3b00827bb0b7 | 964 | |
AdamGreen | 0:3b00827bb0b7 | 965 | /* Enable packet reception */ |
AdamGreen | 0:3b00827bb0b7 | 966 | #if IP_SOF_BROADCAST_RECV |
AdamGreen | 0:3b00827bb0b7 | 967 | LPC_EMAC->RxFilterCtrl = EMAC_RFC_PERFECT_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_MCAST_EN; |
AdamGreen | 0:3b00827bb0b7 | 968 | #else |
AdamGreen | 0:3b00827bb0b7 | 969 | LPC_EMAC->RxFilterCtrl = EMAC_RFC_PERFECT_EN; |
AdamGreen | 0:3b00827bb0b7 | 970 | #endif |
AdamGreen | 0:3b00827bb0b7 | 971 | |
AdamGreen | 0:3b00827bb0b7 | 972 | /* Clear and enable rx/tx interrupts */ |
AdamGreen | 0:3b00827bb0b7 | 973 | LPC_EMAC->IntClear = 0xFFFF; |
AdamGreen | 0:3b00827bb0b7 | 974 | LPC_EMAC->IntEnable = RXINTGROUP | TXINTGROUP; |
AdamGreen | 0:3b00827bb0b7 | 975 | |
AdamGreen | 0:3b00827bb0b7 | 976 | /* Enable RX and TX */ |
AdamGreen | 0:3b00827bb0b7 | 977 | LPC_EMAC->Command |= EMAC_CR_RX_EN | EMAC_CR_TX_EN; |
AdamGreen | 0:3b00827bb0b7 | 978 | LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN; |
AdamGreen | 0:3b00827bb0b7 | 979 | |
AdamGreen | 0:3b00827bb0b7 | 980 | return err; |
AdamGreen | 0:3b00827bb0b7 | 981 | } |
AdamGreen | 0:3b00827bb0b7 | 982 | |
AdamGreen | 0:3b00827bb0b7 | 983 | /* This function provides a method for the PHY to setup the EMAC |
AdamGreen | 0:3b00827bb0b7 | 984 | for the PHY negotiated duplex mode */ |
AdamGreen | 0:3b00827bb0b7 | 985 | void lpc_emac_set_duplex(int full_duplex) |
AdamGreen | 0:3b00827bb0b7 | 986 | { |
AdamGreen | 0:3b00827bb0b7 | 987 | if (full_duplex) { |
AdamGreen | 0:3b00827bb0b7 | 988 | LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP; |
AdamGreen | 0:3b00827bb0b7 | 989 | LPC_EMAC->Command |= EMAC_CR_FULL_DUP; |
AdamGreen | 0:3b00827bb0b7 | 990 | LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP; |
AdamGreen | 0:3b00827bb0b7 | 991 | } else { |
AdamGreen | 0:3b00827bb0b7 | 992 | LPC_EMAC->MAC2 &= ~EMAC_MAC2_FULL_DUP; |
AdamGreen | 0:3b00827bb0b7 | 993 | LPC_EMAC->Command &= ~EMAC_CR_FULL_DUP; |
AdamGreen | 0:3b00827bb0b7 | 994 | LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP; |
AdamGreen | 0:3b00827bb0b7 | 995 | } |
AdamGreen | 0:3b00827bb0b7 | 996 | } |
AdamGreen | 0:3b00827bb0b7 | 997 | |
AdamGreen | 0:3b00827bb0b7 | 998 | /* This function provides a method for the PHY to setup the EMAC |
AdamGreen | 0:3b00827bb0b7 | 999 | for the PHY negotiated bit rate */ |
AdamGreen | 0:3b00827bb0b7 | 1000 | void lpc_emac_set_speed(int mbs_100) |
AdamGreen | 0:3b00827bb0b7 | 1001 | { |
AdamGreen | 0:3b00827bb0b7 | 1002 | if (mbs_100) |
AdamGreen | 0:3b00827bb0b7 | 1003 | LPC_EMAC->SUPP = EMAC_SUPP_SPEED; |
AdamGreen | 0:3b00827bb0b7 | 1004 | else |
AdamGreen | 0:3b00827bb0b7 | 1005 | LPC_EMAC->SUPP = 0; |
AdamGreen | 0:3b00827bb0b7 | 1006 | } |
AdamGreen | 0:3b00827bb0b7 | 1007 | |
AdamGreen | 0:3b00827bb0b7 | 1008 | /** |
AdamGreen | 0:3b00827bb0b7 | 1009 | * This function is the ethernet packet send function. It calls |
AdamGreen | 0:3b00827bb0b7 | 1010 | * etharp_output after checking link status. |
AdamGreen | 0:3b00827bb0b7 | 1011 | * |
AdamGreen | 0:3b00827bb0b7 | 1012 | * \param[in] netif the lwip network interface structure for this lpc_enetif |
AdamGreen | 0:3b00827bb0b7 | 1013 | * \param[in] q Pointer to pbug to send |
AdamGreen | 0:3b00827bb0b7 | 1014 | * \param[in] ipaddr IP address |
AdamGreen | 0:3b00827bb0b7 | 1015 | * \return ERR_OK or error code |
AdamGreen | 0:3b00827bb0b7 | 1016 | */ |
AdamGreen | 0:3b00827bb0b7 | 1017 | err_t lpc_etharp_output(struct netif *netif, struct pbuf *q, |
AdamGreen | 0:3b00827bb0b7 | 1018 | ip_addr_t *ipaddr) |
AdamGreen | 0:3b00827bb0b7 | 1019 | { |
AdamGreen | 0:3b00827bb0b7 | 1020 | /* Only send packet is link is up */ |
AdamGreen | 0:3b00827bb0b7 | 1021 | if (netif->flags & NETIF_FLAG_LINK_UP) |
AdamGreen | 0:3b00827bb0b7 | 1022 | return etharp_output(netif, q, ipaddr); |
AdamGreen | 0:3b00827bb0b7 | 1023 | |
AdamGreen | 0:3b00827bb0b7 | 1024 | return ERR_CONN; |
AdamGreen | 0:3b00827bb0b7 | 1025 | } |
AdamGreen | 0:3b00827bb0b7 | 1026 | |
AdamGreen | 0:3b00827bb0b7 | 1027 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 1028 | /* periodic PHY status update */ |
AdamGreen | 0:3b00827bb0b7 | 1029 | void phy_update(void const *nif) { |
AdamGreen | 0:3b00827bb0b7 | 1030 | lpc_phy_sts_sm((struct netif*)nif); |
AdamGreen | 0:3b00827bb0b7 | 1031 | } |
AdamGreen | 0:3b00827bb0b7 | 1032 | osTimerDef(phy_update, phy_update); |
AdamGreen | 0:3b00827bb0b7 | 1033 | #endif |
AdamGreen | 0:3b00827bb0b7 | 1034 | |
AdamGreen | 0:3b00827bb0b7 | 1035 | /** |
AdamGreen | 0:3b00827bb0b7 | 1036 | * Should be called at the beginning of the program to set up the |
AdamGreen | 0:3b00827bb0b7 | 1037 | * network interface. |
AdamGreen | 0:3b00827bb0b7 | 1038 | * |
AdamGreen | 0:3b00827bb0b7 | 1039 | * This function should be passed as a parameter to netif_add(). |
AdamGreen | 0:3b00827bb0b7 | 1040 | * |
AdamGreen | 0:3b00827bb0b7 | 1041 | * @param[in] netif the lwip network interface structure for this lpc_enetif |
AdamGreen | 0:3b00827bb0b7 | 1042 | * @return ERR_OK if the loopif is initialized |
AdamGreen | 0:3b00827bb0b7 | 1043 | * ERR_MEM if private data couldn't be allocated |
AdamGreen | 0:3b00827bb0b7 | 1044 | * any other err_t on error |
AdamGreen | 0:3b00827bb0b7 | 1045 | */ |
AdamGreen | 0:3b00827bb0b7 | 1046 | err_t lpc_enetif_init(struct netif *netif) |
AdamGreen | 0:3b00827bb0b7 | 1047 | { |
AdamGreen | 0:3b00827bb0b7 | 1048 | err_t err; |
AdamGreen | 0:3b00827bb0b7 | 1049 | |
AdamGreen | 0:3b00827bb0b7 | 1050 | LWIP_ASSERT("netif != NULL", (netif != NULL)); |
AdamGreen | 0:3b00827bb0b7 | 1051 | |
AdamGreen | 0:3b00827bb0b7 | 1052 | lpc_enetdata.netif = netif; |
AdamGreen | 0:3b00827bb0b7 | 1053 | |
AdamGreen | 0:3b00827bb0b7 | 1054 | /* set MAC hardware address */ |
AdamGreen | 0:3b00827bb0b7 | 1055 | #if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE) |
AdamGreen | 0:3b00827bb0b7 | 1056 | netif->hwaddr[0] = MBED_MAC_ADDR_0; |
AdamGreen | 0:3b00827bb0b7 | 1057 | netif->hwaddr[1] = MBED_MAC_ADDR_1; |
AdamGreen | 0:3b00827bb0b7 | 1058 | netif->hwaddr[2] = MBED_MAC_ADDR_2; |
AdamGreen | 0:3b00827bb0b7 | 1059 | netif->hwaddr[3] = MBED_MAC_ADDR_3; |
AdamGreen | 0:3b00827bb0b7 | 1060 | netif->hwaddr[4] = MBED_MAC_ADDR_4; |
AdamGreen | 0:3b00827bb0b7 | 1061 | netif->hwaddr[5] = MBED_MAC_ADDR_5; |
AdamGreen | 0:3b00827bb0b7 | 1062 | #else |
AdamGreen | 0:3b00827bb0b7 | 1063 | mbed_mac_address((char *)netif->hwaddr); |
AdamGreen | 0:3b00827bb0b7 | 1064 | #endif |
AdamGreen | 0:3b00827bb0b7 | 1065 | netif->hwaddr_len = ETHARP_HWADDR_LEN; |
AdamGreen | 0:3b00827bb0b7 | 1066 | |
AdamGreen | 0:3b00827bb0b7 | 1067 | /* maximum transfer unit */ |
AdamGreen | 0:3b00827bb0b7 | 1068 | netif->mtu = 1500; |
AdamGreen | 0:3b00827bb0b7 | 1069 | |
AdamGreen | 0:3b00827bb0b7 | 1070 | /* device capabilities */ |
AdamGreen | 0:3b00827bb0b7 | 1071 | netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP; |
AdamGreen | 0:3b00827bb0b7 | 1072 | |
AdamGreen | 0:3b00827bb0b7 | 1073 | /* Initialize the hardware */ |
AdamGreen | 0:3b00827bb0b7 | 1074 | netif->state = &lpc_enetdata; |
AdamGreen | 0:3b00827bb0b7 | 1075 | err = low_level_init(netif); |
AdamGreen | 0:3b00827bb0b7 | 1076 | if (err != ERR_OK) |
AdamGreen | 0:3b00827bb0b7 | 1077 | return err; |
AdamGreen | 0:3b00827bb0b7 | 1078 | |
AdamGreen | 0:3b00827bb0b7 | 1079 | #if LWIP_NETIF_HOSTNAME |
AdamGreen | 0:3b00827bb0b7 | 1080 | /* Initialize interface hostname */ |
AdamGreen | 0:3b00827bb0b7 | 1081 | netif->hostname = "lwiplpc"; |
AdamGreen | 0:3b00827bb0b7 | 1082 | #endif /* LWIP_NETIF_HOSTNAME */ |
AdamGreen | 0:3b00827bb0b7 | 1083 | |
AdamGreen | 0:3b00827bb0b7 | 1084 | netif->name[0] = 'e'; |
AdamGreen | 0:3b00827bb0b7 | 1085 | netif->name[1] = 'n'; |
AdamGreen | 0:3b00827bb0b7 | 1086 | |
AdamGreen | 0:3b00827bb0b7 | 1087 | netif->output = lpc_etharp_output; |
AdamGreen | 0:3b00827bb0b7 | 1088 | netif->linkoutput = lpc_low_level_output; |
AdamGreen | 0:3b00827bb0b7 | 1089 | |
AdamGreen | 0:3b00827bb0b7 | 1090 | /* CMSIS-RTOS, start tasks */ |
AdamGreen | 0:3b00827bb0b7 | 1091 | #if NO_SYS == 0 |
AdamGreen | 0:3b00827bb0b7 | 1092 | #ifdef CMSIS_OS_RTX |
AdamGreen | 0:3b00827bb0b7 | 1093 | memset(lpc_enetdata.xTXDCountSem.data, 0, sizeof(lpc_enetdata.xTXDCountSem.data)); |
AdamGreen | 0:3b00827bb0b7 | 1094 | lpc_enetdata.xTXDCountSem.def.semaphore = lpc_enetdata.xTXDCountSem.data; |
AdamGreen | 0:3b00827bb0b7 | 1095 | #endif |
AdamGreen | 0:3b00827bb0b7 | 1096 | lpc_enetdata.xTXDCountSem.id = osSemaphoreCreate(&lpc_enetdata.xTXDCountSem.def, LPC_NUM_BUFF_TXDESCS); |
AdamGreen | 0:3b00827bb0b7 | 1097 | LWIP_ASSERT("xTXDCountSem creation error", (lpc_enetdata.xTXDCountSem.id != NULL)); |
AdamGreen | 0:3b00827bb0b7 | 1098 | |
AdamGreen | 0:3b00827bb0b7 | 1099 | err = sys_mutex_new(&lpc_enetdata.TXLockMutex); |
AdamGreen | 0:3b00827bb0b7 | 1100 | LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK)); |
AdamGreen | 0:3b00827bb0b7 | 1101 | |
AdamGreen | 0:3b00827bb0b7 | 1102 | /* Packet receive task */ |
AdamGreen | 0:3b00827bb0b7 | 1103 | lpc_enetdata.RxThread = sys_thread_new("receive_thread", packet_rx, netif->state, DEFAULT_THREAD_STACKSIZE, RX_PRIORITY); |
AdamGreen | 0:3b00827bb0b7 | 1104 | LWIP_ASSERT("RxThread creation error", (lpc_enetdata.RxThread)); |
AdamGreen | 0:3b00827bb0b7 | 1105 | |
AdamGreen | 0:3b00827bb0b7 | 1106 | /* Transmit cleanup task */ |
AdamGreen | 0:3b00827bb0b7 | 1107 | err = sys_sem_new(&lpc_enetdata.TxCleanSem, 0); |
AdamGreen | 0:3b00827bb0b7 | 1108 | LWIP_ASSERT("TxCleanSem creation error", (err == ERR_OK)); |
AdamGreen | 0:3b00827bb0b7 | 1109 | sys_thread_new("txclean_thread", packet_tx, netif->state, DEFAULT_THREAD_STACKSIZE, TX_PRIORITY); |
AdamGreen | 0:3b00827bb0b7 | 1110 | |
AdamGreen | 0:3b00827bb0b7 | 1111 | /* periodic PHY status update */ |
AdamGreen | 0:3b00827bb0b7 | 1112 | osTimerId phy_timer = osTimerCreate(osTimer(phy_update), osTimerPeriodic, (void *)netif); |
AdamGreen | 0:3b00827bb0b7 | 1113 | osTimerStart(phy_timer, 250); |
AdamGreen | 0:3b00827bb0b7 | 1114 | #endif |
AdamGreen | 0:3b00827bb0b7 | 1115 | |
AdamGreen | 0:3b00827bb0b7 | 1116 | return ERR_OK; |
AdamGreen | 0:3b00827bb0b7 | 1117 | } |
AdamGreen | 0:3b00827bb0b7 | 1118 | |
AdamGreen | 0:3b00827bb0b7 | 1119 | /** |
AdamGreen | 0:3b00827bb0b7 | 1120 | * @} |
AdamGreen | 0:3b00827bb0b7 | 1121 | */ |
AdamGreen | 0:3b00827bb0b7 | 1122 | |
AdamGreen | 0:3b00827bb0b7 | 1123 | /* --------------------------------- End Of File ------------------------------ */ |