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