[f610e83f] | 1 | /*===============================================================*\ |
---|
| 2 | | Project: RTEMS support for MPC83xx | |
---|
| 3 | +-----------------------------------------------------------------+ |
---|
| 4 | | Copyright (c) 2007 | |
---|
| 5 | | Embedded Brains GmbH | |
---|
| 6 | | Obere Lagerstr. 30 | |
---|
| 7 | | D-82178 Puchheim | |
---|
| 8 | | Germany | |
---|
| 9 | | rtems@embedded-brains.de | |
---|
| 10 | +-----------------------------------------------------------------+ |
---|
| 11 | | The license and distribution terms for this file may be | |
---|
| 12 | | found in the file LICENSE in this distribution or at | |
---|
| 13 | | | |
---|
[c499856] | 14 | | http://www.rtems.org/license/LICENSE. | |
---|
[f610e83f] | 15 | | | |
---|
| 16 | +-----------------------------------------------------------------+ |
---|
| 17 | | this file contains the MPC83xx TSEC networking driver | |
---|
| 18 | \*===============================================================*/ |
---|
[f2c8c34] | 19 | |
---|
[d8d6a08] | 20 | #define __INSIDE_RTEMS_BSD_TCPIP_STACK__ |
---|
| 21 | |
---|
[f610e83f] | 22 | #include <stdlib.h> |
---|
| 23 | #include <bsp.h> |
---|
| 24 | #include <bsp/irq.h> |
---|
[1e86d1e] | 25 | #include <bsp/tsec.h> |
---|
[f610e83f] | 26 | #include <rtems/error.h> |
---|
| 27 | #include <rtems/bspIo.h> |
---|
| 28 | #include <rtems/rtems_bsdnet.h> |
---|
| 29 | #include <rtems/rtems_mii_ioctl.h> |
---|
| 30 | #include <errno.h> |
---|
| 31 | |
---|
| 32 | #include <sys/param.h> |
---|
| 33 | #include <sys/socket.h> |
---|
| 34 | #include <sys/sockio.h> |
---|
| 35 | #include <sys/mbuf.h> |
---|
| 36 | #include <net/if.h> |
---|
| 37 | #include <net/if_arp.h> |
---|
| 38 | #include <netinet/in.h> |
---|
| 39 | #include <netinet/if_ether.h> |
---|
| 40 | #include <stdio.h> |
---|
| 41 | |
---|
| 42 | #define CLREVENT_IN_IRQ |
---|
| 43 | |
---|
| 44 | #define TSEC_WATCHDOG_TIMEOUT 5 /* check media every 5 seconds */ |
---|
| 45 | |
---|
[f2c8c34] | 46 | #ifdef DEBUG |
---|
| 47 | #define PF(fmt, ...) printk("%s: " fmt, __func__, ##__VA_ARGS__) |
---|
| 48 | #else |
---|
| 49 | #define PF(...) |
---|
| 50 | #endif |
---|
| 51 | |
---|
[f610e83f] | 52 | /* |
---|
| 53 | * Device data |
---|
| 54 | */ |
---|
[1e86d1e] | 55 | struct tsec_struct { |
---|
[f610e83f] | 56 | struct arpcom arpcom; |
---|
| 57 | int acceptBroadcast; |
---|
| 58 | |
---|
| 59 | /* |
---|
| 60 | * HW links: (filled from rtems_bsdnet_ifconfig |
---|
| 61 | */ |
---|
[f2c8c34] | 62 | volatile tsec_registers *reg_ptr; /* pointer to TSEC register block */ |
---|
| 63 | volatile tsec_registers *mdio_ptr; /* pointer to TSEC register block which is responsible for MDIO communication */ |
---|
| 64 | rtems_irq_number irq_num_tx; |
---|
| 65 | rtems_irq_number irq_num_rx; |
---|
| 66 | rtems_irq_number irq_num_err; |
---|
[359e537] | 67 | |
---|
[509040f0] | 68 | rtems_interrupt_lock lock; |
---|
| 69 | |
---|
[359e537] | 70 | /* |
---|
[f610e83f] | 71 | * BD management |
---|
| 72 | */ |
---|
| 73 | int rxBdCount; |
---|
| 74 | int txBdCount; |
---|
| 75 | PQBufferDescriptor_t *Rx_Frst_BD; |
---|
| 76 | PQBufferDescriptor_t *Rx_Last_BD; |
---|
| 77 | PQBufferDescriptor_t *Rx_NxtUsed_BD; /* First BD, which is in Use */ |
---|
| 78 | PQBufferDescriptor_t *Rx_NxtFill_BD; /* BD to be filled next */ |
---|
| 79 | struct mbuf **Rx_mBuf_Ptr; /* Storage for mbufs */ |
---|
| 80 | |
---|
| 81 | PQBufferDescriptor_t *Tx_Frst_BD; |
---|
| 82 | PQBufferDescriptor_t *Tx_Last_BD; |
---|
| 83 | PQBufferDescriptor_t *Tx_NxtUsed_BD; /* First BD, which is in Use */ |
---|
| 84 | PQBufferDescriptor_t *Tx_NxtFill_BD; /* BD to be filled next */ |
---|
| 85 | struct mbuf **Tx_mBuf_Ptr; /* Storage for mbufs */ |
---|
[359e537] | 86 | /* |
---|
| 87 | * Daemon IDs |
---|
[f610e83f] | 88 | */ |
---|
[359e537] | 89 | rtems_id rxDaemonTid; |
---|
[f610e83f] | 90 | rtems_id txDaemonTid; |
---|
| 91 | |
---|
| 92 | /* |
---|
| 93 | * MDIO/Phy info |
---|
| 94 | */ |
---|
| 95 | struct rtems_mdio_info mdio_info; |
---|
| 96 | int phy_default; |
---|
| 97 | int media_state; /* (last detected) state of media */ |
---|
| 98 | /* |
---|
| 99 | * statistic counters Rx |
---|
| 100 | */ |
---|
| 101 | unsigned long rxInterrupts; |
---|
[55a685b] | 102 | unsigned long rxErrors; |
---|
[f610e83f] | 103 | /* |
---|
| 104 | * statistic counters Tx |
---|
| 105 | */ |
---|
| 106 | unsigned long txInterrupts; |
---|
[55a685b] | 107 | unsigned long txErrors; |
---|
[f610e83f] | 108 | }; |
---|
| 109 | |
---|
[1e86d1e] | 110 | static struct tsec_struct tsec_driver[TSEC_COUNT]; |
---|
[f610e83f] | 111 | |
---|
| 112 | /* |
---|
| 113 | * default numbers for buffers |
---|
| 114 | */ |
---|
| 115 | #define RX_BUF_COUNT 64 |
---|
| 116 | #define TX_BUF_COUNT 64 |
---|
| 117 | |
---|
| 118 | /* |
---|
| 119 | * mask for all Tx interrupts |
---|
| 120 | */ |
---|
[1e86d1e] | 121 | #define IEVENT_TXALL (TSEC_IEVENT_GTSC \ |
---|
| 122 | | TSEC_IEVENT_TXC \ |
---|
| 123 | /*| TSEC_IEVENT_TXB*/ \ |
---|
| 124 | | TSEC_IEVENT_TXF ) |
---|
[f610e83f] | 125 | |
---|
| 126 | /* |
---|
| 127 | * mask for all Rx interrupts |
---|
| 128 | */ |
---|
[1e86d1e] | 129 | #define IEVENT_RXALL (TSEC_IEVENT_RXC \ |
---|
| 130 | /* | TSEC_IEVENT_RXB */ \ |
---|
| 131 | | TSEC_IEVENT_GRSC \ |
---|
| 132 | | TSEC_IEVENT_RXF ) |
---|
[f610e83f] | 133 | |
---|
| 134 | /* |
---|
| 135 | * mask for all Error interrupts |
---|
| 136 | */ |
---|
[1e86d1e] | 137 | #define IEVENT_ERRALL (TSEC_IEVENT_BABR \ |
---|
| 138 | | TSEC_IEVENT_BSY \ |
---|
| 139 | | TSEC_IEVENT_EBERR \ |
---|
| 140 | | TSEC_IEVENT_MSRO \ |
---|
| 141 | | TSEC_IEVENT_BABT \ |
---|
| 142 | | TSEC_IEVENT_TXE \ |
---|
| 143 | | TSEC_IEVENT_LC \ |
---|
| 144 | | TSEC_IEVENT_CRL_XDA \ |
---|
| 145 | | TSEC_IEVENT_XFUN ) |
---|
| 146 | |
---|
[509040f0] | 147 | static void TSEC_IMASK_SET(struct tsec_struct *sc, uint32_t mask, uint32_t val) |
---|
| 148 | { |
---|
| 149 | volatile uint32_t *reg = &sc->reg_ptr->imask; |
---|
| 150 | rtems_interrupt_lock_context lock_context; |
---|
| 151 | |
---|
| 152 | rtems_interrupt_lock_acquire(&sc->lock, &lock_context); |
---|
| 153 | *reg = (*reg & ~mask) | (val & mask); |
---|
| 154 | rtems_interrupt_lock_release(&sc->lock, &lock_context); |
---|
[f610e83f] | 155 | } |
---|
| 156 | |
---|
[1e86d1e] | 157 | #define TSEC_ALIGN_BUFFER(buf,align) \ |
---|
[f610e83f] | 158 | ((void *)( (((uint32_t)(buf))+(align)-1) \ |
---|
| 159 | -(((uint32_t)(buf))+(align)-1)%align)) |
---|
| 160 | |
---|
| 161 | /* |
---|
| 162 | * RTEMS event used by interrupt handler to signal daemons. |
---|
| 163 | * This must *not* be the same event used by the TCP/IP task synchronization. |
---|
| 164 | */ |
---|
| 165 | #define INTERRUPT_EVENT RTEMS_EVENT_1 |
---|
| 166 | #define FATAL_INT_EVENT RTEMS_EVENT_3 |
---|
| 167 | |
---|
| 168 | /* |
---|
| 169 | * RTEMS event used to start transmit daemon. |
---|
| 170 | * This must not be the same as INTERRUPT_EVENT. |
---|
| 171 | */ |
---|
| 172 | #define START_TRANSMIT_EVENT RTEMS_EVENT_2 |
---|
| 173 | |
---|
[1e86d1e] | 174 | static int tsec_ioctl |
---|
[f610e83f] | 175 | ( |
---|
| 176 | struct ifnet *ifp, /* interface information */ |
---|
| 177 | ioctl_command_t command, /* ioctl command code */ |
---|
| 178 | caddr_t data /* optional data */ |
---|
| 179 | ); |
---|
| 180 | |
---|
| 181 | /*=========================================================================*\ |
---|
| 182 | | Function: | |
---|
| 183 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 184 | static void tsec_hwinit |
---|
[f610e83f] | 185 | ( |
---|
| 186 | /*-------------------------------------------------------------------------*\ |
---|
| 187 | | Purpose: | |
---|
| 188 | | initialize hardware register | |
---|
| 189 | +---------------------------------------------------------------------------+ |
---|
| 190 | | Input Parameters: | |
---|
| 191 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 192 | struct tsec_struct *sc /* control structure */ |
---|
[f610e83f] | 193 | ) |
---|
| 194 | /*-------------------------------------------------------------------------*\ |
---|
| 195 | | Return Value: | |
---|
| 196 | | <none> | |
---|
| 197 | \*=========================================================================*/ |
---|
| 198 | { |
---|
[1e86d1e] | 199 | volatile tsec_registers *reg_ptr = sc->reg_ptr; /* pointer to TSEC registers*/ |
---|
[f610e83f] | 200 | uint8_t *mac_addr; |
---|
[574fb67] | 201 | size_t i; |
---|
[f610e83f] | 202 | |
---|
[4b23c94] | 203 | /* Clear interrupt mask and all pending events */ |
---|
| 204 | reg_ptr->imask = 0; |
---|
| 205 | reg_ptr->ievent = 0xffffffff; |
---|
| 206 | |
---|
[f610e83f] | 207 | /* |
---|
| 208 | * init ECNTL register |
---|
| 209 | * - clear statistics counters |
---|
| 210 | * - enable statistics |
---|
| 211 | * NOTE: do not clear bits set in BSP init function |
---|
| 212 | */ |
---|
[1e86d1e] | 213 | reg_ptr->ecntrl = ((reg_ptr->ecntrl & ~TSEC_ECNTRL_AUTOZ) |
---|
| 214 | | TSEC_ECNTRL_CLRCNT |
---|
| 215 | | TSEC_ECNTRL_STEN |
---|
| 216 | | TSEC_ECNTRL_R100M); |
---|
[f610e83f] | 217 | |
---|
| 218 | /* |
---|
| 219 | * init DMA control register: |
---|
| 220 | * - enable snooping |
---|
| 221 | * - write BD status before interrupt request |
---|
| 222 | * - do not poll TxBD, but wait for TSTAT[THLT] to be written |
---|
| 223 | */ |
---|
[1e86d1e] | 224 | reg_ptr->dmactrl = (TSEC_DMACTL_TDSEN |
---|
| 225 | | TSEC_DMACTL_TBDSEN |
---|
| 226 | | TSEC_DMACTL_WWR |
---|
| 227 | | TSEC_DMACTL_WOP); |
---|
[f610e83f] | 228 | |
---|
| 229 | /* |
---|
| 230 | * init Attribute register: |
---|
| 231 | * - enable read snooping for data and BD |
---|
| 232 | */ |
---|
[1e86d1e] | 233 | reg_ptr->attr = (TSEC_ATTR_RDSEN |
---|
| 234 | | TSEC_ATTR_RBDSEN); |
---|
[f610e83f] | 235 | |
---|
| 236 | |
---|
[359e537] | 237 | reg_ptr->mrblr = MCLBYTES-64; /* take care of buffer size lost |
---|
[f610e83f] | 238 | * due to alignment */ |
---|
| 239 | |
---|
| 240 | /* |
---|
[55a685b] | 241 | * init EDIS register: disable all error reportings |
---|
[f610e83f] | 242 | */ |
---|
[1e86d1e] | 243 | reg_ptr->edis = (TSEC_EDIS_BSYDIS | |
---|
| 244 | TSEC_EDIS_EBERRDIS | |
---|
| 245 | TSEC_EDIS_TXEDIS | |
---|
| 246 | TSEC_EDIS_LCDIS | |
---|
| 247 | TSEC_EDIS_CRLXDADIS | |
---|
| 248 | TSEC_EDIS_FUNDIS); |
---|
[f610e83f] | 249 | /* |
---|
| 250 | * init minimum frame length register |
---|
| 251 | */ |
---|
| 252 | reg_ptr->minflr = 64; |
---|
| 253 | /* |
---|
| 254 | * init maximum frame length register |
---|
| 255 | */ |
---|
| 256 | reg_ptr->maxfrm = 1536; |
---|
| 257 | /* |
---|
| 258 | * define physical address of TBI |
---|
| 259 | */ |
---|
| 260 | reg_ptr->tbipa = 0x1e; |
---|
| 261 | /* |
---|
| 262 | * init transmit interrupt coalescing register |
---|
| 263 | */ |
---|
[1e86d1e] | 264 | reg_ptr->txic = (TSEC_TXIC_ICEN |
---|
| 265 | | TSEC_TXIC_ICFCT(2) |
---|
| 266 | | TSEC_TXIC_ICTT(32)); |
---|
[f610e83f] | 267 | /* |
---|
| 268 | * init receive interrupt coalescing register |
---|
| 269 | */ |
---|
[41d7c0fe] | 270 | #if 0 |
---|
[1e86d1e] | 271 | reg_ptr->rxic = (TSEC_RXIC_ICEN |
---|
| 272 | | TSEC_RXIC_ICFCT(2) |
---|
| 273 | | TSEC_RXIC_ICTT(32)); |
---|
[41d7c0fe] | 274 | #else |
---|
| 275 | reg_ptr->rxic = 0; |
---|
| 276 | #endif |
---|
[f610e83f] | 277 | /* |
---|
| 278 | * init MACCFG1 register |
---|
| 279 | */ |
---|
[1e86d1e] | 280 | reg_ptr->maccfg1 = (TSEC_MACCFG1_RX_FLOW |
---|
| 281 | | TSEC_MACCFG1_TX_FLOW); |
---|
[359e537] | 282 | |
---|
[f610e83f] | 283 | /* |
---|
| 284 | * init MACCFG2 register |
---|
| 285 | */ |
---|
[1e86d1e] | 286 | reg_ptr->maccfg2 = ((reg_ptr->maccfg2 & TSEC_MACCFG2_IFMODE_MSK) |
---|
[06280c35] | 287 | | TSEC_MACCFG2_IFMODE_BYT |
---|
[1e86d1e] | 288 | | TSEC_MACCFG2_PRELEN( 7) |
---|
| 289 | | TSEC_MACCFG2_FULLDUPLEX); |
---|
[f610e83f] | 290 | |
---|
| 291 | /* |
---|
| 292 | * init station address register |
---|
| 293 | */ |
---|
| 294 | mac_addr = sc->arpcom.ac_enaddr; |
---|
| 295 | |
---|
| 296 | reg_ptr->macstnaddr[0] = ((mac_addr[5] << 24) |
---|
| 297 | | (mac_addr[4] << 16) |
---|
| 298 | | (mac_addr[3] << 8) |
---|
| 299 | | (mac_addr[2] << 0)); |
---|
| 300 | reg_ptr->macstnaddr[1] = ((mac_addr[1] << 24) |
---|
| 301 | | (mac_addr[0] << 16)); |
---|
| 302 | /* |
---|
| 303 | * clear hash filters |
---|
| 304 | */ |
---|
| 305 | for (i = 0; |
---|
| 306 | i < sizeof(reg_ptr->iaddr)/sizeof(reg_ptr->iaddr[0]); |
---|
| 307 | i++) { |
---|
| 308 | reg_ptr->iaddr[i] = 0; |
---|
| 309 | } |
---|
| 310 | for (i = 0; |
---|
| 311 | i < sizeof(reg_ptr->gaddr)/sizeof(reg_ptr->gaddr[0]); |
---|
| 312 | i++) { |
---|
| 313 | reg_ptr->gaddr[i] = 0; |
---|
| 314 | } |
---|
| 315 | } |
---|
| 316 | |
---|
| 317 | /***************************************************************************\ |
---|
| 318 | | MII Management access functions | |
---|
| 319 | \***************************************************************************/ |
---|
| 320 | |
---|
| 321 | /*=========================================================================*\ |
---|
| 322 | | Function: | |
---|
| 323 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 324 | static void tsec_mdio_init |
---|
[f610e83f] | 325 | ( |
---|
| 326 | /*-------------------------------------------------------------------------*\ |
---|
| 327 | | Purpose: | |
---|
| 328 | | initialize the MIIM interface | |
---|
| 329 | +---------------------------------------------------------------------------+ |
---|
| 330 | | Input Parameters: | |
---|
| 331 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 332 | struct tsec_struct *sc /* control structure */ |
---|
[f610e83f] | 333 | ) |
---|
| 334 | /*-------------------------------------------------------------------------*\ |
---|
| 335 | | Return Value: | |
---|
| 336 | | <none> | |
---|
| 337 | \*=========================================================================*/ |
---|
| 338 | { |
---|
[f0e748c] | 339 | static const uint8_t divider [] = { 32, 32, 48, 64, 80, 112, 160, 224 }; |
---|
[06280c35] | 340 | size_t n = sizeof(divider) / sizeof(divider [0]); |
---|
| 341 | size_t i = 0; |
---|
[f0e748c] | 342 | uint32_t mii_clock = UINT32_MAX; |
---|
| 343 | uint32_t tsec_system_clock = BSP_bus_frequency / 2; |
---|
[574fb67] | 344 | |
---|
| 345 | /* Set TSEC registers for MDIO communication */ |
---|
| 346 | |
---|
[f610e83f] | 347 | /* |
---|
| 348 | * set clock divider |
---|
| 349 | */ |
---|
[f0e748c] | 350 | for (i = 0; i < n && mii_clock > 2500000; ++i) { |
---|
| 351 | mii_clock = tsec_system_clock / divider [i]; |
---|
[06280c35] | 352 | } |
---|
| 353 | |
---|
| 354 | sc->mdio_ptr->miimcfg = i; |
---|
[f610e83f] | 355 | } |
---|
| 356 | |
---|
| 357 | /*=========================================================================*\ |
---|
| 358 | | Function: | |
---|
| 359 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 360 | static int tsec_mdio_read |
---|
[f610e83f] | 361 | ( |
---|
| 362 | /*-------------------------------------------------------------------------*\ |
---|
| 363 | | Purpose: | |
---|
| 364 | | read register of a phy | |
---|
| 365 | +---------------------------------------------------------------------------+ |
---|
| 366 | | Input Parameters: | |
---|
| 367 | \*-------------------------------------------------------------------------*/ |
---|
| 368 | int phy, /* PHY number to access or -1 */ |
---|
| 369 | void *uarg, /* unit argument */ |
---|
| 370 | unsigned reg, /* register address */ |
---|
| 371 | uint32_t *pval /* ptr to read buffer */ |
---|
| 372 | ) |
---|
| 373 | /*-------------------------------------------------------------------------*\ |
---|
| 374 | | Return Value: | |
---|
| 375 | | 0, if ok, else error | |
---|
| 376 | \*=========================================================================*/ |
---|
| 377 | { |
---|
[1e86d1e] | 378 | struct tsec_struct *sc = uarg;/* control structure */ |
---|
[f610e83f] | 379 | |
---|
[574fb67] | 380 | /* pointer to TSEC registers */ |
---|
[1e86d1e] | 381 | volatile tsec_registers *reg_ptr = sc->mdio_ptr; |
---|
[f2c8c34] | 382 | PF("%u\n", reg); |
---|
[f610e83f] | 383 | |
---|
| 384 | /* |
---|
| 385 | * make sure we work with a valid phy |
---|
| 386 | */ |
---|
| 387 | if (phy == -1) { |
---|
| 388 | phy = sc->phy_default; |
---|
| 389 | } |
---|
| 390 | if ( (phy < 0) || (phy > 31)) { |
---|
| 391 | /* |
---|
| 392 | * invalid phy number |
---|
| 393 | */ |
---|
| 394 | return EINVAL; |
---|
| 395 | } |
---|
| 396 | /* |
---|
[359e537] | 397 | * set PHY/reg address |
---|
[f610e83f] | 398 | */ |
---|
[1e86d1e] | 399 | reg_ptr->miimadd = (TSEC_MIIMADD_PHY(phy) |
---|
| 400 | | TSEC_MIIMADD_REGADDR(reg)); |
---|
[f610e83f] | 401 | /* |
---|
| 402 | * start read cycle |
---|
| 403 | */ |
---|
| 404 | reg_ptr->miimcom = 0; |
---|
[1e86d1e] | 405 | reg_ptr->miimcom = TSEC_MIIMCOM_READ; |
---|
[f610e83f] | 406 | |
---|
| 407 | /* |
---|
| 408 | * wait for cycle to terminate |
---|
| 409 | */ |
---|
| 410 | do { |
---|
| 411 | rtems_task_wake_after(2); |
---|
[1e86d1e] | 412 | } while (0 != (reg_ptr->miimind & TSEC_MIIMIND_BUSY)); |
---|
[f610e83f] | 413 | reg_ptr->miimcom = 0; |
---|
| 414 | /* |
---|
| 415 | * fetch read data, if available |
---|
| 416 | */ |
---|
| 417 | if (pval != NULL) { |
---|
| 418 | *pval = reg_ptr->miimstat; |
---|
| 419 | } |
---|
| 420 | return 0; |
---|
| 421 | } |
---|
| 422 | |
---|
| 423 | /*=========================================================================*\ |
---|
| 424 | | Function: | |
---|
| 425 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 426 | static int tsec_mdio_write |
---|
[f610e83f] | 427 | ( |
---|
| 428 | /*-------------------------------------------------------------------------*\ |
---|
| 429 | | Purpose: | |
---|
| 430 | | write register of a phy | |
---|
| 431 | +---------------------------------------------------------------------------+ |
---|
| 432 | | Input Parameters: | |
---|
| 433 | \*-------------------------------------------------------------------------*/ |
---|
| 434 | int phy, /* PHY number to access or -1 */ |
---|
| 435 | void *uarg, /* unit argument */ |
---|
| 436 | unsigned reg, /* register address */ |
---|
| 437 | uint32_t val /* write value */ |
---|
| 438 | ) |
---|
| 439 | /*-------------------------------------------------------------------------*\ |
---|
| 440 | | Return Value: | |
---|
| 441 | | 0, if ok, else error | |
---|
| 442 | \*=========================================================================*/ |
---|
| 443 | { |
---|
[1e86d1e] | 444 | struct tsec_struct *sc = uarg;/* control structure */ |
---|
[f610e83f] | 445 | |
---|
[574fb67] | 446 | /* pointer to TSEC registers */ |
---|
[1e86d1e] | 447 | volatile tsec_registers *reg_ptr = sc->mdio_ptr; |
---|
[f2c8c34] | 448 | PF("%u\n", reg); |
---|
[f610e83f] | 449 | |
---|
| 450 | /* |
---|
| 451 | * make sure we work with a valid phy |
---|
| 452 | */ |
---|
| 453 | if (phy == -1) { |
---|
| 454 | /* |
---|
| 455 | * set default phy number: 0 for TSEC1, 1 for TSEC2 |
---|
| 456 | */ |
---|
| 457 | phy = sc->phy_default; |
---|
| 458 | } |
---|
| 459 | if ( (phy < 0) || (phy > 31)) { |
---|
| 460 | /* |
---|
| 461 | * invalid phy number |
---|
| 462 | */ |
---|
| 463 | return EINVAL; |
---|
| 464 | } |
---|
| 465 | /* |
---|
[359e537] | 466 | * set PHY/reg address |
---|
[f610e83f] | 467 | */ |
---|
[1e86d1e] | 468 | reg_ptr->miimadd = (TSEC_MIIMADD_PHY(phy) |
---|
| 469 | | TSEC_MIIMADD_REGADDR(reg)); |
---|
[f610e83f] | 470 | /* |
---|
| 471 | * start write cycle |
---|
| 472 | */ |
---|
| 473 | reg_ptr->miimcon = val; |
---|
| 474 | |
---|
| 475 | /* |
---|
| 476 | * wait for cycle to terminate |
---|
| 477 | */ |
---|
| 478 | do { |
---|
| 479 | rtems_task_wake_after(2); |
---|
[1e86d1e] | 480 | } while (0 != (reg_ptr->miimind & TSEC_MIIMIND_BUSY)); |
---|
[f610e83f] | 481 | reg_ptr->miimcom = 0; |
---|
| 482 | return 0; |
---|
| 483 | } |
---|
| 484 | |
---|
| 485 | |
---|
| 486 | /***************************************************************************\ |
---|
| 487 | | RX receive functions | |
---|
| 488 | \***************************************************************************/ |
---|
| 489 | |
---|
| 490 | /*=========================================================================*\ |
---|
| 491 | | Function: | |
---|
| 492 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 493 | static rtems_event_set tsec_rx_wait_for_events |
---|
[f610e83f] | 494 | ( |
---|
| 495 | /*-------------------------------------------------------------------------*\ |
---|
| 496 | | Purpose: | |
---|
| 497 | | handle all rx events | |
---|
| 498 | +---------------------------------------------------------------------------+ |
---|
| 499 | | Input Parameters: | |
---|
| 500 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 501 | struct tsec_struct *sc, /* control structure */ |
---|
[f610e83f] | 502 | rtems_event_set event_mask /* events to wait for */ |
---|
| 503 | ) |
---|
| 504 | /*-------------------------------------------------------------------------*\ |
---|
| 505 | | Return Value: | |
---|
| 506 | | event set received | |
---|
| 507 | \*=========================================================================*/ |
---|
| 508 | { |
---|
| 509 | rtems_event_set events; /* events received */ |
---|
| 510 | /* |
---|
| 511 | * enable Rx interrupts, make sure this is not interrupted :-) |
---|
| 512 | */ |
---|
[509040f0] | 513 | TSEC_IMASK_SET(sc,IEVENT_RXALL,~0); |
---|
[359e537] | 514 | |
---|
[f610e83f] | 515 | /* |
---|
| 516 | * wait for events to come in |
---|
| 517 | */ |
---|
[359e537] | 518 | rtems_bsdnet_event_receive(event_mask, |
---|
| 519 | RTEMS_EVENT_ANY | RTEMS_WAIT, |
---|
| 520 | RTEMS_NO_TIMEOUT, |
---|
[f610e83f] | 521 | &events); |
---|
| 522 | return events; |
---|
| 523 | } |
---|
| 524 | |
---|
| 525 | /*=========================================================================*\ |
---|
| 526 | | Function: | |
---|
| 527 | \*-------------------------------------------------------------------------*/ |
---|
| 528 | static void mpc83xx_rxbd_alloc_clear |
---|
| 529 | ( |
---|
| 530 | /*-------------------------------------------------------------------------*\ |
---|
| 531 | | Purpose: | |
---|
| 532 | | allocate space for Rx BDs, clear them | |
---|
| 533 | +---------------------------------------------------------------------------+ |
---|
| 534 | | Input Parameters: | |
---|
| 535 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 536 | struct tsec_struct *sc /* control structure */ |
---|
[f610e83f] | 537 | ) |
---|
| 538 | /*-------------------------------------------------------------------------*\ |
---|
| 539 | | Return Value: | |
---|
| 540 | | <none> | |
---|
| 541 | \*=========================================================================*/ |
---|
| 542 | { |
---|
| 543 | char *alloc_ptr; |
---|
| 544 | PQBufferDescriptor_t *BD_ptr; |
---|
| 545 | /* |
---|
| 546 | * allocate proper space for Rx BDs |
---|
| 547 | */ |
---|
| 548 | alloc_ptr = calloc((sc->rxBdCount+1),sizeof(PQBufferDescriptor_t)); |
---|
| 549 | if (alloc_ptr == NULL) { |
---|
| 550 | rtems_panic("TSEC: cannot allocate space for Rx BDs"); |
---|
| 551 | } |
---|
| 552 | alloc_ptr = (void *)((uint32_t )((alloc_ptr + (sizeof(PQBufferDescriptor_t)-1))) |
---|
| 553 | & ~(sizeof(PQBufferDescriptor_t)-1)); |
---|
| 554 | /* |
---|
| 555 | * store pointers to certain positions in BD chain |
---|
| 556 | */ |
---|
| 557 | sc->Rx_Last_BD = ((PQBufferDescriptor_t *)alloc_ptr)+sc->rxBdCount-1; |
---|
| 558 | sc->Rx_Frst_BD = (PQBufferDescriptor_t *)alloc_ptr; |
---|
| 559 | sc->Rx_NxtUsed_BD = sc->Rx_Frst_BD; |
---|
| 560 | sc->Rx_NxtFill_BD = sc->Rx_Frst_BD; |
---|
[359e537] | 561 | |
---|
[f610e83f] | 562 | /* |
---|
| 563 | * clear all BDs |
---|
| 564 | */ |
---|
| 565 | for (BD_ptr = sc->Rx_Frst_BD; |
---|
| 566 | BD_ptr <= sc->Rx_Last_BD; |
---|
| 567 | BD_ptr++) { |
---|
| 568 | BD_ptr->status = 0; |
---|
| 569 | } |
---|
| 570 | /* |
---|
| 571 | * Init BD chain registers |
---|
| 572 | */ |
---|
| 573 | sc->reg_ptr->rbase = (uint32_t) (sc->Rx_Frst_BD); |
---|
| 574 | } |
---|
| 575 | |
---|
| 576 | /*=========================================================================*\ |
---|
| 577 | | Function: | |
---|
| 578 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 579 | static void tsec_receive_packets |
---|
[f610e83f] | 580 | ( |
---|
| 581 | /*-------------------------------------------------------------------------*\ |
---|
| 582 | | Purpose: | |
---|
| 583 | | process any received packets | |
---|
| 584 | +---------------------------------------------------------------------------+ |
---|
| 585 | | Input Parameters: | |
---|
| 586 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 587 | struct tsec_struct *sc /* control structure */ |
---|
[f610e83f] | 588 | ) |
---|
| 589 | /*-------------------------------------------------------------------------*\ |
---|
| 590 | | Return Value: | |
---|
| 591 | | <none> | |
---|
| 592 | \*=========================================================================*/ |
---|
| 593 | { |
---|
| 594 | PQBufferDescriptor_t *BD_ptr; |
---|
| 595 | struct mbuf *m,*n; |
---|
[bcd5368] | 596 | bool finished = false; |
---|
[f610e83f] | 597 | uint16_t status; |
---|
| 598 | struct ether_header *eh; |
---|
| 599 | int bd_idx; |
---|
| 600 | |
---|
| 601 | BD_ptr = sc->Rx_NxtUsed_BD; |
---|
| 602 | |
---|
[1e86d1e] | 603 | while ((0 == ((status = BD_ptr->status) & BD_EMPTY)) && |
---|
[f610e83f] | 604 | !finished && |
---|
[359e537] | 605 | (BD_ptr->buffer != NULL)) { |
---|
[f610e83f] | 606 | /* |
---|
| 607 | * get mbuf associated with BD |
---|
| 608 | */ |
---|
| 609 | bd_idx = BD_ptr - sc->Rx_Frst_BD; |
---|
| 610 | m = sc->Rx_mBuf_Ptr[bd_idx]; |
---|
| 611 | sc->Rx_mBuf_Ptr[bd_idx] = NULL; |
---|
| 612 | |
---|
| 613 | /* |
---|
| 614 | * Check that packet is valid |
---|
| 615 | */ |
---|
[1e86d1e] | 616 | if ((status & (BD_LAST | |
---|
| 617 | BD_FIRST_IN_FRAME | |
---|
| 618 | BD_LONG | |
---|
| 619 | BD_NONALIGNED | |
---|
| 620 | BD_CRC_ERROR | |
---|
| 621 | BD_OVERRUN )) |
---|
| 622 | == (BD_LAST | |
---|
| 623 | BD_FIRST_IN_FRAME ) ) { |
---|
[f610e83f] | 624 | /* |
---|
| 625 | * send mbuf of this buffer to ether_input() |
---|
| 626 | */ |
---|
[359e537] | 627 | m->m_len = m->m_pkthdr.len = (BD_ptr->length |
---|
| 628 | - sizeof(uint32_t) |
---|
[f610e83f] | 629 | - sizeof(struct ether_header)); |
---|
| 630 | eh = mtod(m, struct ether_header *); |
---|
| 631 | m->m_data += sizeof(struct ether_header); |
---|
[f2c8c34] | 632 | PF("RX[%08x] (%i)\n", BD_ptr, m->m_len); |
---|
[f610e83f] | 633 | ether_input(&sc->arpcom.ac_if,eh,m); |
---|
| 634 | } |
---|
| 635 | else { |
---|
| 636 | /* |
---|
| 637 | * throw away mbuf |
---|
| 638 | */ |
---|
| 639 | MFREE(m,n); |
---|
[fca58924] | 640 | (void) n; |
---|
[f610e83f] | 641 | } |
---|
| 642 | /* |
---|
| 643 | * mark buffer as non-allocated (for refill) |
---|
| 644 | */ |
---|
| 645 | BD_ptr->buffer = NULL; |
---|
| 646 | /* |
---|
| 647 | * Advance BD_ptr to next BD |
---|
| 648 | */ |
---|
[359e537] | 649 | BD_ptr = ((BD_ptr == sc->Rx_Last_BD) |
---|
| 650 | ? sc->Rx_Frst_BD |
---|
[f610e83f] | 651 | : BD_ptr+1); |
---|
| 652 | } |
---|
| 653 | sc->Rx_NxtUsed_BD = BD_ptr; |
---|
| 654 | } |
---|
| 655 | |
---|
| 656 | /*=========================================================================*\ |
---|
| 657 | | Function: | |
---|
| 658 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 659 | static void tsec_refill_rxbds |
---|
[f610e83f] | 660 | ( |
---|
| 661 | /*-------------------------------------------------------------------------*\ |
---|
| 662 | | Purpose: | |
---|
| 663 | | link new buffers to rx BDs | |
---|
| 664 | +---------------------------------------------------------------------------+ |
---|
| 665 | | Input Parameters: | |
---|
| 666 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 667 | struct tsec_struct *sc /* control structure */ |
---|
[f610e83f] | 668 | ) |
---|
| 669 | /*-------------------------------------------------------------------------*\ |
---|
| 670 | | Return Value: | |
---|
| 671 | | <none> | |
---|
| 672 | \*=========================================================================*/ |
---|
| 673 | { |
---|
| 674 | PQBufferDescriptor_t *BD_ptr; |
---|
| 675 | struct mbuf *m,*n; |
---|
[bcd5368] | 676 | bool finished = false; |
---|
[f610e83f] | 677 | int bd_idx; |
---|
| 678 | |
---|
| 679 | BD_ptr = sc->Rx_NxtFill_BD; |
---|
[359e537] | 680 | while ((BD_ptr->buffer == NULL) && |
---|
[f610e83f] | 681 | !finished) { |
---|
| 682 | /* |
---|
| 683 | * get new mbuf and attach a cluster |
---|
| 684 | */ |
---|
| 685 | MGETHDR(m,M_DONTWAIT,MT_DATA); |
---|
| 686 | if (m != NULL) { |
---|
| 687 | MCLGET(m,M_DONTWAIT); |
---|
| 688 | if ((m->m_flags & M_EXT) == 0) { |
---|
| 689 | MFREE(m,n); |
---|
[fca58924] | 690 | (void) n; |
---|
[f610e83f] | 691 | m = NULL; |
---|
| 692 | } |
---|
| 693 | } |
---|
| 694 | if (m == NULL) { |
---|
[bcd5368] | 695 | finished = true; |
---|
[f610e83f] | 696 | } |
---|
| 697 | else { |
---|
| 698 | bd_idx = BD_ptr - sc->Rx_Frst_BD; |
---|
| 699 | sc->Rx_mBuf_Ptr[bd_idx] = m; |
---|
| 700 | |
---|
| 701 | m->m_pkthdr.rcvif= &sc->arpcom.ac_if; |
---|
[1e86d1e] | 702 | m->m_data = TSEC_ALIGN_BUFFER(m->m_ext.ext_buf,64); |
---|
[f610e83f] | 703 | BD_ptr->buffer = m->m_data; |
---|
| 704 | BD_ptr->length = 0; |
---|
[1e86d1e] | 705 | BD_ptr->status = (BD_EMPTY |
---|
| 706 | | BD_INTERRUPT |
---|
[359e537] | 707 | | ((BD_ptr == sc->Rx_Last_BD) |
---|
[1e86d1e] | 708 | ? BD_WRAP |
---|
[f610e83f] | 709 | : 0)); |
---|
| 710 | /* |
---|
| 711 | * Advance BD_ptr to next BD |
---|
| 712 | */ |
---|
[359e537] | 713 | BD_ptr = ((BD_ptr == sc->Rx_Last_BD) |
---|
| 714 | ? sc->Rx_Frst_BD |
---|
[f610e83f] | 715 | : BD_ptr+1); |
---|
| 716 | } |
---|
| 717 | } |
---|
| 718 | sc->Rx_NxtFill_BD = BD_ptr; |
---|
| 719 | } |
---|
| 720 | |
---|
| 721 | /*=========================================================================*\ |
---|
| 722 | | Function: | |
---|
| 723 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 724 | static void tsec_rxDaemon |
---|
[f610e83f] | 725 | ( |
---|
| 726 | /*-------------------------------------------------------------------------*\ |
---|
| 727 | | Purpose: | |
---|
| 728 | | handle all rx buffers and events | |
---|
| 729 | +---------------------------------------------------------------------------+ |
---|
| 730 | | Input Parameters: | |
---|
| 731 | \*-------------------------------------------------------------------------*/ |
---|
| 732 | void * arg /* argument, is sc structure ptr */ |
---|
| 733 | ) |
---|
| 734 | /*-------------------------------------------------------------------------*\ |
---|
| 735 | | Return Value: | |
---|
| 736 | | <none> | |
---|
| 737 | \*=========================================================================*/ |
---|
| 738 | { |
---|
[1e86d1e] | 739 | struct tsec_struct *sc = |
---|
| 740 | (struct tsec_struct *)arg; |
---|
[bcd5368] | 741 | bool finished = false; |
---|
[f610e83f] | 742 | #if !defined(CLREVENT_IN_IRQ) |
---|
| 743 | uint32_t irq_events; |
---|
| 744 | #endif |
---|
| 745 | /* |
---|
| 746 | * enable Rx in MACCFG1 register |
---|
| 747 | */ |
---|
[1e86d1e] | 748 | sc->reg_ptr->maccfg1 |= TSEC_MACCFG1_RXEN; |
---|
[f610e83f] | 749 | while (!finished) { |
---|
| 750 | /* |
---|
| 751 | * fetch MBufs, associate them to RxBDs |
---|
| 752 | */ |
---|
[1e86d1e] | 753 | tsec_refill_rxbds(sc); |
---|
[f610e83f] | 754 | /* |
---|
| 755 | * wait for events to come in |
---|
| 756 | */ |
---|
[fca58924] | 757 | tsec_rx_wait_for_events(sc,INTERRUPT_EVENT); |
---|
[f610e83f] | 758 | #if !defined(CLREVENT_IN_IRQ) |
---|
| 759 | /* |
---|
| 760 | * clear any pending RX events |
---|
| 761 | */ |
---|
[1e86d1e] | 762 | irq_events = sc->reg_ptr->ievent & IEVENT_RXALL; |
---|
[f610e83f] | 763 | sc->reg_ptr->ievent = irq_events; |
---|
| 764 | #endif |
---|
| 765 | /* |
---|
| 766 | * fetch any completed buffers/packets received |
---|
| 767 | * and stuff them into the TCP/IP Stack |
---|
| 768 | */ |
---|
[1e86d1e] | 769 | tsec_receive_packets(sc); |
---|
[f610e83f] | 770 | } |
---|
| 771 | /* |
---|
| 772 | * disable Rx in MACCFG1 register |
---|
| 773 | */ |
---|
[1e86d1e] | 774 | sc->reg_ptr->maccfg1 &= ~TSEC_MACCFG1_RXEN; |
---|
[f610e83f] | 775 | /* |
---|
| 776 | * terminate daemon |
---|
| 777 | */ |
---|
| 778 | sc->rxDaemonTid = 0; |
---|
| 779 | rtems_task_delete(RTEMS_SELF); |
---|
| 780 | } |
---|
| 781 | |
---|
| 782 | /***************************************************************************\ |
---|
| 783 | | TX Transmit functions | |
---|
| 784 | \***************************************************************************/ |
---|
| 785 | |
---|
| 786 | /*=========================================================================*\ |
---|
| 787 | | Function: | |
---|
| 788 | \*-------------------------------------------------------------------------*/ |
---|
| 789 | static void mpc83xx_txbd_alloc_clear |
---|
| 790 | ( |
---|
| 791 | /*-------------------------------------------------------------------------*\ |
---|
| 792 | | Purpose: | |
---|
| 793 | | allocate space for Tx BDs, clear them | |
---|
| 794 | +---------------------------------------------------------------------------+ |
---|
| 795 | | Input Parameters: | |
---|
| 796 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 797 | struct tsec_struct *sc /* control structure */ |
---|
[f610e83f] | 798 | ) |
---|
| 799 | /*-------------------------------------------------------------------------*\ |
---|
| 800 | | Return Value: | |
---|
| 801 | | <none> | |
---|
| 802 | \*=========================================================================*/ |
---|
| 803 | { |
---|
| 804 | char *alloc_ptr; |
---|
| 805 | PQBufferDescriptor_t *BD_ptr; |
---|
| 806 | /* |
---|
| 807 | * allocate proper space for Tx BDs |
---|
| 808 | */ |
---|
| 809 | alloc_ptr = calloc((sc->txBdCount+1),sizeof(PQBufferDescriptor_t)); |
---|
| 810 | if (alloc_ptr == NULL) { |
---|
| 811 | rtems_panic("TSEC: cannot allocate space for Tx BDs"); |
---|
| 812 | } |
---|
| 813 | alloc_ptr = (void *)((uint32_t )((alloc_ptr + (sizeof(PQBufferDescriptor_t)-1))) |
---|
| 814 | & ~(sizeof(PQBufferDescriptor_t)-1)); |
---|
| 815 | /* |
---|
| 816 | * store pointers to certain positions in BD chain |
---|
| 817 | */ |
---|
| 818 | sc->Tx_Last_BD = ((PQBufferDescriptor_t *)alloc_ptr)+sc->txBdCount-1; |
---|
| 819 | sc->Tx_Frst_BD = (PQBufferDescriptor_t *)alloc_ptr; |
---|
| 820 | sc->Tx_NxtUsed_BD = sc->Tx_Frst_BD; |
---|
| 821 | sc->Tx_NxtFill_BD = sc->Tx_Frst_BD; |
---|
[359e537] | 822 | |
---|
[f610e83f] | 823 | /* |
---|
| 824 | * clear all BDs |
---|
| 825 | */ |
---|
| 826 | for (BD_ptr = sc->Tx_Frst_BD; |
---|
| 827 | BD_ptr <= sc->Tx_Last_BD; |
---|
| 828 | BD_ptr++) { |
---|
| 829 | BD_ptr->status = 0; |
---|
| 830 | } |
---|
| 831 | /* |
---|
| 832 | * Init BD chain registers |
---|
| 833 | */ |
---|
| 834 | sc->reg_ptr->tbase = (uint32_t)(sc->Tx_Frst_BD); |
---|
| 835 | } |
---|
| 836 | |
---|
| 837 | /*=========================================================================*\ |
---|
| 838 | | Function: | |
---|
| 839 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 840 | static void tsec_tx_start |
---|
[f610e83f] | 841 | ( |
---|
| 842 | /*-------------------------------------------------------------------------*\ |
---|
| 843 | | Purpose: | |
---|
| 844 | | start transmission | |
---|
| 845 | +---------------------------------------------------------------------------+ |
---|
| 846 | | Input Parameters: | |
---|
| 847 | \*-------------------------------------------------------------------------*/ |
---|
| 848 | struct ifnet *ifp |
---|
| 849 | ) |
---|
| 850 | /*-------------------------------------------------------------------------*\ |
---|
| 851 | | Return Value: | |
---|
| 852 | | <none> | |
---|
| 853 | \*=========================================================================*/ |
---|
| 854 | { |
---|
[1e86d1e] | 855 | struct tsec_struct *sc = ifp->if_softc; |
---|
[f610e83f] | 856 | |
---|
| 857 | ifp->if_flags |= IFF_OACTIVE; |
---|
| 858 | |
---|
[26e90fb1] | 859 | rtems_bsdnet_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); |
---|
[f610e83f] | 860 | } |
---|
| 861 | |
---|
| 862 | /*=========================================================================*\ |
---|
| 863 | | Function: | |
---|
| 864 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 865 | static rtems_event_set tsec_tx_wait_for_events |
---|
[f610e83f] | 866 | ( |
---|
| 867 | /*-------------------------------------------------------------------------*\ |
---|
| 868 | | Purpose: | |
---|
| 869 | | handle all tx events | |
---|
| 870 | +---------------------------------------------------------------------------+ |
---|
| 871 | | Input Parameters: | |
---|
| 872 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 873 | struct tsec_struct *sc, /* control structure */ |
---|
[f610e83f] | 874 | rtems_event_set event_mask /* events to wait for */ |
---|
| 875 | ) |
---|
| 876 | /*-------------------------------------------------------------------------*\ |
---|
| 877 | | Return Value: | |
---|
| 878 | | event set received | |
---|
| 879 | \*=========================================================================*/ |
---|
| 880 | { |
---|
| 881 | rtems_event_set events; /* events received */ |
---|
| 882 | /* |
---|
| 883 | * enable Tx interrupts, make sure this is not interrupted :-) |
---|
| 884 | */ |
---|
[509040f0] | 885 | TSEC_IMASK_SET(sc,IEVENT_TXALL,~0); |
---|
[359e537] | 886 | |
---|
[f610e83f] | 887 | /* |
---|
| 888 | * wait for events to come in |
---|
| 889 | */ |
---|
[359e537] | 890 | rtems_bsdnet_event_receive(event_mask, |
---|
| 891 | RTEMS_EVENT_ANY | RTEMS_WAIT, |
---|
| 892 | RTEMS_NO_TIMEOUT, |
---|
[f610e83f] | 893 | &events); |
---|
| 894 | return events; |
---|
| 895 | } |
---|
| 896 | |
---|
| 897 | /*=========================================================================*\ |
---|
| 898 | | Function: | |
---|
| 899 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 900 | static void tsec_tx_retire |
---|
[f610e83f] | 901 | ( |
---|
| 902 | /*-------------------------------------------------------------------------*\ |
---|
| 903 | | Purpose: | |
---|
| 904 | | handle all tx events | |
---|
| 905 | +---------------------------------------------------------------------------+ |
---|
| 906 | | Input Parameters: | |
---|
| 907 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 908 | struct tsec_struct *sc /* control structure */ |
---|
[f610e83f] | 909 | ) |
---|
| 910 | /*-------------------------------------------------------------------------*\ |
---|
| 911 | | Return Value: | |
---|
| 912 | | <none> | |
---|
| 913 | \*=========================================================================*/ |
---|
| 914 | { |
---|
| 915 | PQBufferDescriptor_t *RetBD; |
---|
| 916 | RetBD = sc->Tx_NxtUsed_BD; |
---|
| 917 | int bd_idx; |
---|
| 918 | struct mbuf *m,*n; |
---|
| 919 | /* |
---|
| 920 | * check next BDs to be empty |
---|
| 921 | */ |
---|
| 922 | while ((RetBD->buffer != NULL) /* BD is filled */ |
---|
[1e86d1e] | 923 | && (0 == (RetBD->status & BD_READY ))) {/* BD no longer ready*/ |
---|
[f610e83f] | 924 | |
---|
| 925 | bd_idx = RetBD - sc->Tx_Frst_BD; |
---|
| 926 | m = sc->Tx_mBuf_Ptr[bd_idx]; |
---|
| 927 | sc->Tx_mBuf_Ptr[bd_idx] = NULL; |
---|
| 928 | |
---|
| 929 | MFREE(m,n); |
---|
[fca58924] | 930 | (void) n; |
---|
[f610e83f] | 931 | RetBD->buffer = NULL; |
---|
| 932 | /* |
---|
| 933 | * Advance CurrBD to next BD |
---|
| 934 | */ |
---|
[359e537] | 935 | RetBD = ((RetBD == sc->Tx_Last_BD) |
---|
| 936 | ? sc->Tx_Frst_BD |
---|
[f610e83f] | 937 | : RetBD+1); |
---|
| 938 | } |
---|
| 939 | sc->Tx_NxtUsed_BD = RetBD; |
---|
| 940 | } |
---|
| 941 | |
---|
| 942 | /*=========================================================================*\ |
---|
| 943 | | Function: | |
---|
| 944 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 945 | static void tsec_sendpacket |
---|
[f610e83f] | 946 | ( |
---|
| 947 | /*-------------------------------------------------------------------------*\ |
---|
| 948 | | Purpose: | |
---|
| 949 | | handle all tx events | |
---|
| 950 | +---------------------------------------------------------------------------+ |
---|
| 951 | | Input Parameters: | |
---|
| 952 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 953 | struct tsec_struct *sc, /* control structure */ |
---|
[f610e83f] | 954 | struct mbuf *m /* start of packet to send */ |
---|
| 955 | ) |
---|
| 956 | /*-------------------------------------------------------------------------*\ |
---|
| 957 | | Return Value: | |
---|
| 958 | | <none> | |
---|
| 959 | \*=========================================================================*/ |
---|
| 960 | { |
---|
| 961 | PQBufferDescriptor_t *FrstBD = NULL; |
---|
| 962 | PQBufferDescriptor_t *CurrBD; |
---|
| 963 | uint16_t status; |
---|
| 964 | struct mbuf *l = NULL; /* ptr to last non-freed (non-empty) mbuf */ |
---|
| 965 | int bd_idx; |
---|
| 966 | /* |
---|
| 967 | * get next Tx BD |
---|
| 968 | */ |
---|
| 969 | CurrBD = sc->Tx_NxtFill_BD; |
---|
| 970 | while (m) { |
---|
| 971 | if(m->m_len == 0) { |
---|
| 972 | /* |
---|
| 973 | * Just toss empty mbufs |
---|
| 974 | */ |
---|
| 975 | struct mbuf *n; |
---|
| 976 | MFREE(m, n); |
---|
[359e537] | 977 | m = n; |
---|
[f610e83f] | 978 | if(l != NULL) { |
---|
| 979 | l->m_next = m; |
---|
| 980 | } |
---|
| 981 | } |
---|
| 982 | else { |
---|
| 983 | /* |
---|
| 984 | * this mbuf is non-empty, so send it |
---|
| 985 | */ |
---|
| 986 | /* |
---|
[359e537] | 987 | * Is CurrBD still in Use/not yet retired? |
---|
[f610e83f] | 988 | */ |
---|
| 989 | while (CurrBD->buffer != NULL) { |
---|
| 990 | /* |
---|
| 991 | * Then try to retire it |
---|
| 992 | * and to return its mbuf |
---|
| 993 | */ |
---|
[1e86d1e] | 994 | tsec_tx_retire(sc); |
---|
[f610e83f] | 995 | if (CurrBD->buffer != NULL) { |
---|
| 996 | /* |
---|
| 997 | * Wait for anything to happen... |
---|
| 998 | */ |
---|
[1e86d1e] | 999 | tsec_tx_wait_for_events(sc,INTERRUPT_EVENT); |
---|
[f610e83f] | 1000 | } |
---|
| 1001 | } |
---|
[1e86d1e] | 1002 | status = ((BD_PAD_CRC | BD_TX_CRC) |
---|
[359e537] | 1003 | | ((m->m_next == NULL) |
---|
[1e86d1e] | 1004 | ? BD_LAST | BD_INTERRUPT |
---|
[f610e83f] | 1005 | : 0) |
---|
[1e86d1e] | 1006 | | ((CurrBD == sc->Tx_Last_BD) ? BD_WRAP : 0)); |
---|
[359e537] | 1007 | |
---|
[f610e83f] | 1008 | /* |
---|
| 1009 | * link buffer to BD |
---|
| 1010 | */ |
---|
| 1011 | CurrBD->buffer = mtod(m, void *); |
---|
| 1012 | CurrBD->length = (uint32_t)m->m_len; |
---|
| 1013 | l = m; /* remember: we use this mbuf */ |
---|
[f2c8c34] | 1014 | PF("TX[%08x] (%i)\n", CurrBD, m->m_len); |
---|
[f610e83f] | 1015 | |
---|
| 1016 | bd_idx = CurrBD - sc->Tx_Frst_BD; |
---|
| 1017 | sc->Tx_mBuf_Ptr[bd_idx] = m; |
---|
| 1018 | |
---|
| 1019 | m = m->m_next; /* advance to next mbuf of this packet */ |
---|
| 1020 | /* |
---|
| 1021 | * is this the first BD of the packet? |
---|
[359e537] | 1022 | * then don't set it to "READY" state, |
---|
[f610e83f] | 1023 | * and remember this BD position |
---|
| 1024 | */ |
---|
| 1025 | if (FrstBD == NULL) { |
---|
| 1026 | FrstBD = CurrBD; |
---|
| 1027 | } |
---|
| 1028 | else { |
---|
[1e86d1e] | 1029 | status |= BD_READY; |
---|
[f610e83f] | 1030 | } |
---|
| 1031 | CurrBD->status = status; |
---|
| 1032 | /* |
---|
| 1033 | * Advance CurrBD to next BD |
---|
| 1034 | */ |
---|
[359e537] | 1035 | CurrBD = ((CurrBD == sc->Tx_Last_BD) |
---|
| 1036 | ? sc->Tx_Frst_BD |
---|
[f610e83f] | 1037 | : CurrBD+1); |
---|
| 1038 | } |
---|
| 1039 | } |
---|
| 1040 | /* |
---|
[359e537] | 1041 | * mbuf chain of this packet |
---|
| 1042 | * has been translated |
---|
[f610e83f] | 1043 | * to BD chain, so set first BD ready now |
---|
| 1044 | */ |
---|
| 1045 | if (FrstBD != NULL) { |
---|
[1e86d1e] | 1046 | FrstBD->status |= BD_READY; |
---|
[f610e83f] | 1047 | } |
---|
| 1048 | sc->Tx_NxtFill_BD = CurrBD; |
---|
| 1049 | /* |
---|
| 1050 | * wake up transmitter (clear TSTAT[THLT]) |
---|
| 1051 | */ |
---|
[1e86d1e] | 1052 | sc->reg_ptr->tstat = TSEC_TSTAT_THLT; |
---|
[f610e83f] | 1053 | } |
---|
| 1054 | |
---|
| 1055 | /*=========================================================================*\ |
---|
| 1056 | | Function: | |
---|
| 1057 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1058 | static void tsec_txDaemon |
---|
[f610e83f] | 1059 | ( |
---|
| 1060 | /*-------------------------------------------------------------------------*\ |
---|
| 1061 | | Purpose: | |
---|
| 1062 | | handle all tx events | |
---|
| 1063 | +---------------------------------------------------------------------------+ |
---|
| 1064 | | Input Parameters: | |
---|
| 1065 | \*-------------------------------------------------------------------------*/ |
---|
| 1066 | void * arg /* argument, is sc structure ptr */ |
---|
| 1067 | ) |
---|
| 1068 | /*-------------------------------------------------------------------------*\ |
---|
| 1069 | | Return Value: | |
---|
| 1070 | | <none> | |
---|
| 1071 | \*=========================================================================*/ |
---|
| 1072 | { |
---|
[1e86d1e] | 1073 | struct tsec_struct *sc = |
---|
| 1074 | (struct tsec_struct *)arg; |
---|
[f610e83f] | 1075 | struct ifnet *ifp = &sc->arpcom.ac_if; |
---|
| 1076 | struct mbuf *m; |
---|
[bcd5368] | 1077 | bool finished = false; |
---|
[f610e83f] | 1078 | #if !defined(CLREVENT_IN_IRQ) |
---|
| 1079 | uint32_t irq_events; |
---|
| 1080 | #endif |
---|
| 1081 | |
---|
| 1082 | /* |
---|
| 1083 | * enable Tx in MACCFG1 register |
---|
| 1084 | * FIXME: make this irq save |
---|
| 1085 | */ |
---|
[1e86d1e] | 1086 | sc->reg_ptr->maccfg1 |= TSEC_MACCFG1_TXEN; |
---|
[f610e83f] | 1087 | while (!finished) { |
---|
| 1088 | /* |
---|
| 1089 | * wait for events to come in |
---|
| 1090 | */ |
---|
[fca58924] | 1091 | tsec_tx_wait_for_events(sc, |
---|
[359e537] | 1092 | START_TRANSMIT_EVENT |
---|
[f610e83f] | 1093 | | INTERRUPT_EVENT); |
---|
| 1094 | #if !defined(CLREVENT_IN_IRQ) |
---|
| 1095 | /* |
---|
| 1096 | * clear any pending TX events |
---|
| 1097 | */ |
---|
[1e86d1e] | 1098 | irq_events = sc->reg_ptr->ievent & IEVENT_TXALL; |
---|
[f610e83f] | 1099 | sc->reg_ptr->ievent = irq_events; |
---|
| 1100 | #endif |
---|
| 1101 | /* |
---|
| 1102 | * retire any sent tx BDs |
---|
| 1103 | */ |
---|
[1e86d1e] | 1104 | tsec_tx_retire(sc); |
---|
[f610e83f] | 1105 | /* |
---|
| 1106 | * Send packets till queue is empty |
---|
| 1107 | */ |
---|
| 1108 | do { |
---|
| 1109 | /* |
---|
| 1110 | * Get the next mbuf chain to transmit. |
---|
| 1111 | */ |
---|
| 1112 | IF_DEQUEUE(&ifp->if_snd, m); |
---|
[359e537] | 1113 | |
---|
[f610e83f] | 1114 | if (m) { |
---|
[1e86d1e] | 1115 | tsec_sendpacket(sc,m); |
---|
[f610e83f] | 1116 | } |
---|
| 1117 | } while (m != NULL); |
---|
| 1118 | |
---|
[359e537] | 1119 | ifp->if_flags &= ~IFF_OACTIVE; |
---|
[f610e83f] | 1120 | } |
---|
| 1121 | /* |
---|
| 1122 | * disable Tx in MACCFG1 register |
---|
| 1123 | */ |
---|
[1e86d1e] | 1124 | sc->reg_ptr->maccfg1 &= ~TSEC_MACCFG1_TXEN; |
---|
[f610e83f] | 1125 | /* |
---|
| 1126 | * terminate daemon |
---|
| 1127 | */ |
---|
| 1128 | sc->txDaemonTid = 0; |
---|
| 1129 | rtems_task_delete(RTEMS_SELF); |
---|
| 1130 | } |
---|
| 1131 | |
---|
| 1132 | /***************************************************************************\ |
---|
| 1133 | | Interrupt handlers and management routines | |
---|
| 1134 | \***************************************************************************/ |
---|
| 1135 | |
---|
| 1136 | /*=========================================================================*\ |
---|
| 1137 | | Function: | |
---|
| 1138 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1139 | static void tsec_tx_irq_handler |
---|
[f610e83f] | 1140 | ( |
---|
| 1141 | /*-------------------------------------------------------------------------*\ |
---|
| 1142 | | Purpose: | |
---|
| 1143 | | handle tx interrupts | |
---|
| 1144 | +---------------------------------------------------------------------------+ |
---|
| 1145 | | Input Parameters: | |
---|
| 1146 | \*-------------------------------------------------------------------------*/ |
---|
| 1147 | rtems_irq_hdl_param handle /* handle, is sc structure ptr */ |
---|
| 1148 | ) |
---|
| 1149 | /*-------------------------------------------------------------------------*\ |
---|
| 1150 | | Return Value: | |
---|
| 1151 | | <none> | |
---|
| 1152 | \*=========================================================================*/ |
---|
| 1153 | { |
---|
[1e86d1e] | 1154 | struct tsec_struct *sc = |
---|
| 1155 | (struct tsec_struct *)handle; |
---|
[f610e83f] | 1156 | #if defined(CLREVENT_IN_IRQ) |
---|
| 1157 | uint32_t irq_events; |
---|
| 1158 | #endif |
---|
| 1159 | |
---|
[f2c8c34] | 1160 | PF("TXIRQ\n"); |
---|
[f610e83f] | 1161 | sc->txInterrupts++; |
---|
| 1162 | /* |
---|
| 1163 | * disable tx interrupts |
---|
| 1164 | */ |
---|
[509040f0] | 1165 | TSEC_IMASK_SET(sc,IEVENT_TXALL,0); |
---|
[f610e83f] | 1166 | |
---|
| 1167 | #if defined(CLREVENT_IN_IRQ) |
---|
| 1168 | /* |
---|
| 1169 | * clear any pending TX events |
---|
| 1170 | */ |
---|
[1e86d1e] | 1171 | irq_events = sc->reg_ptr->ievent & IEVENT_TXALL; |
---|
[f610e83f] | 1172 | sc->reg_ptr->ievent = irq_events; |
---|
| 1173 | #endif |
---|
| 1174 | /* |
---|
| 1175 | * wake up tx Daemon |
---|
| 1176 | */ |
---|
[26e90fb1] | 1177 | rtems_bsdnet_event_send(sc->txDaemonTid, INTERRUPT_EVENT); |
---|
[f610e83f] | 1178 | } |
---|
| 1179 | |
---|
| 1180 | /*=========================================================================*\ |
---|
| 1181 | | Function: | |
---|
| 1182 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1183 | static void tsec_rx_irq_handler |
---|
[f610e83f] | 1184 | ( |
---|
| 1185 | /*-------------------------------------------------------------------------*\ |
---|
| 1186 | | Purpose: | |
---|
| 1187 | | handle rx interrupts | |
---|
| 1188 | +---------------------------------------------------------------------------+ |
---|
| 1189 | | Input Parameters: | |
---|
| 1190 | \*-------------------------------------------------------------------------*/ |
---|
| 1191 | rtems_irq_hdl_param handle /* handle, is sc structure */ |
---|
| 1192 | ) |
---|
| 1193 | /*-------------------------------------------------------------------------*\ |
---|
| 1194 | | Return Value: | |
---|
| 1195 | | <none> | |
---|
| 1196 | \*=========================================================================*/ |
---|
| 1197 | { |
---|
[1e86d1e] | 1198 | struct tsec_struct *sc = |
---|
| 1199 | (struct tsec_struct *)handle; |
---|
[f610e83f] | 1200 | #if defined(CLREVENT_IN_IRQ) |
---|
| 1201 | uint32_t irq_events; |
---|
| 1202 | #endif |
---|
| 1203 | |
---|
| 1204 | sc->rxInterrupts++; |
---|
[f2c8c34] | 1205 | PF("RXIRQ\n"); |
---|
[f610e83f] | 1206 | /* |
---|
| 1207 | * disable rx interrupts |
---|
| 1208 | */ |
---|
[509040f0] | 1209 | TSEC_IMASK_SET(sc,IEVENT_RXALL,0); |
---|
[f610e83f] | 1210 | #if defined(CLREVENT_IN_IRQ) |
---|
| 1211 | /* |
---|
| 1212 | * clear any pending RX events |
---|
| 1213 | */ |
---|
[1e86d1e] | 1214 | irq_events = sc->reg_ptr->ievent & IEVENT_RXALL; |
---|
[f610e83f] | 1215 | sc->reg_ptr->ievent = irq_events; |
---|
| 1216 | #endif |
---|
| 1217 | /* |
---|
| 1218 | * wake up rx Daemon< |
---|
| 1219 | */ |
---|
[26e90fb1] | 1220 | rtems_bsdnet_event_send(sc->rxDaemonTid, INTERRUPT_EVENT); |
---|
[f610e83f] | 1221 | } |
---|
| 1222 | |
---|
| 1223 | |
---|
| 1224 | /*=========================================================================*\ |
---|
| 1225 | | Function: | |
---|
| 1226 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1227 | static void tsec_err_irq_handler |
---|
[f610e83f] | 1228 | ( |
---|
| 1229 | /*-------------------------------------------------------------------------*\ |
---|
| 1230 | | Purpose: | |
---|
| 1231 | | handle error interrupts | |
---|
| 1232 | +---------------------------------------------------------------------------+ |
---|
| 1233 | | Input Parameters: | |
---|
| 1234 | \*-------------------------------------------------------------------------*/ |
---|
| 1235 | rtems_irq_hdl_param handle /* handle, is sc structure */ |
---|
| 1236 | ) |
---|
| 1237 | /*-------------------------------------------------------------------------*\ |
---|
| 1238 | | Return Value: | |
---|
| 1239 | | <none> | |
---|
| 1240 | \*=========================================================================*/ |
---|
| 1241 | { |
---|
[1e86d1e] | 1242 | struct tsec_struct *sc = |
---|
| 1243 | (struct tsec_struct *)handle; |
---|
[f2c8c34] | 1244 | PF("ERIRQ\n"); |
---|
[f610e83f] | 1245 | /* |
---|
[55a685b] | 1246 | * clear error events in IEVENT |
---|
[f610e83f] | 1247 | */ |
---|
[1e86d1e] | 1248 | sc->reg_ptr->ievent = IEVENT_ERRALL; |
---|
[f610e83f] | 1249 | /* |
---|
[55a685b] | 1250 | * has Rx been stopped? then restart it |
---|
[f610e83f] | 1251 | */ |
---|
[1e86d1e] | 1252 | if (0 != (sc->reg_ptr->rstat & TSEC_RSTAT_QHLT)) { |
---|
[55a685b] | 1253 | sc->rxErrors++; |
---|
[1e86d1e] | 1254 | sc->reg_ptr->rstat = TSEC_RSTAT_QHLT; |
---|
[55a685b] | 1255 | } |
---|
[f610e83f] | 1256 | /* |
---|
[55a685b] | 1257 | * has Tx been stopped? then restart it |
---|
[f610e83f] | 1258 | */ |
---|
[1e86d1e] | 1259 | if (0 != (sc->reg_ptr->tstat & TSEC_TSTAT_THLT)) { |
---|
[55a685b] | 1260 | sc->txErrors++; |
---|
[1e86d1e] | 1261 | sc->reg_ptr->tstat = TSEC_TSTAT_THLT; |
---|
[55a685b] | 1262 | } |
---|
[f610e83f] | 1263 | } |
---|
| 1264 | |
---|
| 1265 | |
---|
| 1266 | /*=========================================================================*\ |
---|
| 1267 | | Function: | |
---|
| 1268 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1269 | static uint32_t tsec_irq_mask |
---|
[f610e83f] | 1270 | ( |
---|
| 1271 | /*-------------------------------------------------------------------------*\ |
---|
| 1272 | | Purpose: | |
---|
| 1273 | | determine irq mask for given interrupt number | |
---|
| 1274 | +---------------------------------------------------------------------------+ |
---|
| 1275 | | Input Parameters: | |
---|
[359e537] | 1276 | \*-------------------------------------------------------------------------*/ |
---|
[f610e83f] | 1277 | int irqnum, |
---|
[1e86d1e] | 1278 | struct tsec_struct *sc |
---|
[f610e83f] | 1279 | ) |
---|
| 1280 | /*-------------------------------------------------------------------------*\ |
---|
| 1281 | | Return Value: | |
---|
| 1282 | | interrupt mask (for ievent/imask register) | |
---|
| 1283 | \*=========================================================================*/ |
---|
| 1284 | { |
---|
| 1285 | return ((irqnum == sc->irq_num_tx) |
---|
[1e86d1e] | 1286 | ? IEVENT_TXALL |
---|
[f610e83f] | 1287 | : ((irqnum == sc->irq_num_rx) |
---|
[1e86d1e] | 1288 | ? IEVENT_RXALL |
---|
[f610e83f] | 1289 | : ((irqnum == sc->irq_num_err) |
---|
[1e86d1e] | 1290 | ? IEVENT_ERRALL |
---|
[f610e83f] | 1291 | : 0))); |
---|
| 1292 | } |
---|
| 1293 | /*=========================================================================*\ |
---|
| 1294 | | Function: | |
---|
| 1295 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1296 | static void tsec_irq_on |
---|
[f610e83f] | 1297 | ( |
---|
| 1298 | /*-------------------------------------------------------------------------*\ |
---|
| 1299 | | Purpose: | |
---|
| 1300 | | enable interrupts in TSEC mask register | |
---|
| 1301 | +---------------------------------------------------------------------------+ |
---|
| 1302 | | Input Parameters: | |
---|
| 1303 | \*-------------------------------------------------------------------------*/ |
---|
| 1304 | const |
---|
| 1305 | rtems_irq_connect_data *irq_conn_data /* irq connect data */ |
---|
| 1306 | ) |
---|
| 1307 | /*-------------------------------------------------------------------------*\ |
---|
| 1308 | | Return Value: | |
---|
| 1309 | | <none> | |
---|
| 1310 | \*=========================================================================*/ |
---|
| 1311 | { |
---|
[1e86d1e] | 1312 | struct tsec_struct *sc = |
---|
| 1313 | (struct tsec_struct *)(irq_conn_data->handle); |
---|
[f610e83f] | 1314 | |
---|
[509040f0] | 1315 | TSEC_IMASK_SET(sc, |
---|
[1e86d1e] | 1316 | tsec_irq_mask(irq_conn_data->name,sc), |
---|
[f610e83f] | 1317 | ~0); |
---|
| 1318 | } |
---|
| 1319 | |
---|
| 1320 | /*=========================================================================*\ |
---|
| 1321 | | Function: | |
---|
| 1322 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1323 | static void tsec_irq_off |
---|
[f610e83f] | 1324 | ( |
---|
| 1325 | /*-------------------------------------------------------------------------*\ |
---|
| 1326 | | Purpose: | |
---|
| 1327 | | disable TX interrupts in TSEC mask register | |
---|
| 1328 | +---------------------------------------------------------------------------+ |
---|
| 1329 | | Input Parameters: | |
---|
| 1330 | \*-------------------------------------------------------------------------*/ |
---|
| 1331 | const |
---|
| 1332 | rtems_irq_connect_data *irq_conn_data /* irq connect data */ |
---|
| 1333 | ) |
---|
| 1334 | /*-------------------------------------------------------------------------*\ |
---|
| 1335 | | Return Value: | |
---|
| 1336 | | <none> | |
---|
| 1337 | \*=========================================================================*/ |
---|
| 1338 | { |
---|
[1e86d1e] | 1339 | struct tsec_struct *sc = |
---|
| 1340 | (struct tsec_struct *)irq_conn_data->handle; |
---|
[f610e83f] | 1341 | |
---|
[509040f0] | 1342 | TSEC_IMASK_SET(sc, |
---|
[1e86d1e] | 1343 | tsec_irq_mask(irq_conn_data->name,sc), |
---|
[f610e83f] | 1344 | 0); |
---|
| 1345 | } |
---|
| 1346 | |
---|
| 1347 | /*=========================================================================*\ |
---|
| 1348 | | Function: | |
---|
| 1349 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1350 | static int tsec_irq_isOn |
---|
[f610e83f] | 1351 | ( |
---|
| 1352 | /*-------------------------------------------------------------------------*\ |
---|
| 1353 | | Purpose: | |
---|
| 1354 | | check state of interrupts in TSEC mask register | |
---|
| 1355 | +---------------------------------------------------------------------------+ |
---|
| 1356 | | Input Parameters: | |
---|
| 1357 | \*-------------------------------------------------------------------------*/ |
---|
| 1358 | const |
---|
| 1359 | rtems_irq_connect_data *irq_conn_data /* irq connect data */ |
---|
| 1360 | ) |
---|
| 1361 | /*-------------------------------------------------------------------------*\ |
---|
| 1362 | | Return Value: | |
---|
| 1363 | | <none> | |
---|
| 1364 | \*=========================================================================*/ |
---|
| 1365 | { |
---|
[1e86d1e] | 1366 | struct tsec_struct *sc = |
---|
| 1367 | (struct tsec_struct *)irq_conn_data->handle; |
---|
[f610e83f] | 1368 | |
---|
[359e537] | 1369 | return (0 != (sc->reg_ptr->imask |
---|
[1e86d1e] | 1370 | & tsec_irq_mask(irq_conn_data->name,sc))); |
---|
[f610e83f] | 1371 | } |
---|
| 1372 | |
---|
| 1373 | /*=========================================================================*\ |
---|
| 1374 | | Function: | |
---|
| 1375 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1376 | static void tsec_install_irq_handlers |
---|
[f610e83f] | 1377 | ( |
---|
| 1378 | /*-------------------------------------------------------------------------*\ |
---|
| 1379 | | Purpose: | |
---|
| 1380 | | (un-)install the interrupt handlers | |
---|
| 1381 | +---------------------------------------------------------------------------+ |
---|
| 1382 | | Input Parameters: | |
---|
| 1383 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1384 | struct tsec_struct *sc, /* ptr to control structure */ |
---|
[bcd5368] | 1385 | bool install /* true: install, false: remove */ |
---|
[f610e83f] | 1386 | ) |
---|
| 1387 | /*-------------------------------------------------------------------------*\ |
---|
| 1388 | | Return Value: | |
---|
| 1389 | | <none> | |
---|
| 1390 | \*=========================================================================*/ |
---|
| 1391 | { |
---|
[bcd5368] | 1392 | size_t i; |
---|
[f610e83f] | 1393 | |
---|
| 1394 | rtems_irq_connect_data irq_conn_data[3] = { |
---|
| 1395 | { |
---|
| 1396 | sc->irq_num_tx, |
---|
[1e86d1e] | 1397 | tsec_tx_irq_handler, /* rtems_irq_hdl */ |
---|
[f610e83f] | 1398 | (rtems_irq_hdl_param)sc, /* (rtems_irq_hdl_param) */ |
---|
[1e86d1e] | 1399 | tsec_irq_on, /* (rtems_irq_enable) */ |
---|
| 1400 | tsec_irq_off, /* (rtems_irq_disable) */ |
---|
| 1401 | tsec_irq_isOn /* (rtems_irq_is_enabled) */ |
---|
[f610e83f] | 1402 | },{ |
---|
| 1403 | sc->irq_num_rx, |
---|
[1e86d1e] | 1404 | tsec_rx_irq_handler, /* rtems_irq_hdl */ |
---|
[f610e83f] | 1405 | (rtems_irq_hdl_param)sc, /* (rtems_irq_hdl_param) */ |
---|
[1e86d1e] | 1406 | tsec_irq_on, /* (rtems_irq_enable) */ |
---|
| 1407 | tsec_irq_off, /* (rtems_irq_disable) */ |
---|
| 1408 | tsec_irq_isOn /* (rtems_irq_is_enabled) */ |
---|
[f610e83f] | 1409 | },{ |
---|
| 1410 | sc->irq_num_err, |
---|
[1e86d1e] | 1411 | tsec_err_irq_handler, /* rtems_irq_hdl */ |
---|
[f610e83f] | 1412 | (rtems_irq_hdl_param)sc, /* (rtems_irq_hdl_param) */ |
---|
[1e86d1e] | 1413 | tsec_irq_on, /* (rtems_irq_enable) */ |
---|
| 1414 | tsec_irq_off, /* (rtems_irq_disable) */ |
---|
| 1415 | tsec_irq_isOn /* (rtems_irq_is_enabled) */ |
---|
[f610e83f] | 1416 | } |
---|
| 1417 | }; |
---|
| 1418 | |
---|
| 1419 | /* |
---|
| 1420 | * (un-)install handler for Tx/Rx/Error |
---|
| 1421 | */ |
---|
| 1422 | for (i = 0; |
---|
| 1423 | i < sizeof(irq_conn_data)/sizeof(irq_conn_data[0]); |
---|
| 1424 | i++) { |
---|
| 1425 | if (install) { |
---|
| 1426 | if (!BSP_install_rtems_irq_handler (&irq_conn_data[i])) { |
---|
| 1427 | rtems_panic("TSEC: cannot install IRQ handler"); |
---|
| 1428 | } |
---|
| 1429 | } |
---|
| 1430 | else { |
---|
| 1431 | if (!BSP_remove_rtems_irq_handler (&irq_conn_data[i])) { |
---|
| 1432 | rtems_panic("TSEC: cannot uninstall IRQ handler"); |
---|
| 1433 | } |
---|
| 1434 | } |
---|
| 1435 | } |
---|
| 1436 | } |
---|
| 1437 | |
---|
| 1438 | /***************************************************************************\ |
---|
| 1439 | | Initialization and interface routines | |
---|
| 1440 | \***************************************************************************/ |
---|
| 1441 | |
---|
| 1442 | /*=========================================================================*\ |
---|
| 1443 | | Function: | |
---|
| 1444 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1445 | static void tsec_init |
---|
[f610e83f] | 1446 | ( |
---|
| 1447 | /*-------------------------------------------------------------------------*\ |
---|
| 1448 | | Purpose: | |
---|
| 1449 | | initialize the driver and the hardware | |
---|
| 1450 | +---------------------------------------------------------------------------+ |
---|
| 1451 | | Input Parameters: | |
---|
| 1452 | \*-------------------------------------------------------------------------*/ |
---|
| 1453 | void *arg /* argument pointer, contains *sc */ |
---|
| 1454 | ) |
---|
| 1455 | /*-------------------------------------------------------------------------*\ |
---|
| 1456 | | Return Value: | |
---|
| 1457 | | zero, if success | |
---|
| 1458 | \*=========================================================================*/ |
---|
| 1459 | { |
---|
[1e86d1e] | 1460 | struct tsec_struct *sc = (struct tsec_struct *)arg; |
---|
[f610e83f] | 1461 | struct ifnet *ifp = &sc->arpcom.ac_if; |
---|
| 1462 | /* |
---|
| 1463 | * check, whether device is not yet running |
---|
| 1464 | */ |
---|
| 1465 | if (0 == sc->rxDaemonTid) { |
---|
| 1466 | /* |
---|
| 1467 | * allocate rx/tx BDs |
---|
| 1468 | */ |
---|
| 1469 | mpc83xx_rxbd_alloc_clear(sc); |
---|
| 1470 | mpc83xx_txbd_alloc_clear(sc); |
---|
| 1471 | /* |
---|
| 1472 | * allocate storage for mbuf ptrs |
---|
| 1473 | */ |
---|
| 1474 | sc->Rx_mBuf_Ptr = calloc(sc->rxBdCount,sizeof(struct mbuf *)); |
---|
[359e537] | 1475 | sc->Tx_mBuf_Ptr = calloc(sc->txBdCount,sizeof(struct mbuf *)); |
---|
[f610e83f] | 1476 | if ((sc->Rx_mBuf_Ptr == NULL) || |
---|
| 1477 | (sc->Tx_mBuf_Ptr == NULL)) { |
---|
| 1478 | rtems_panic("TSEC: cannot allocate buffers for mbuf management"); |
---|
[359e537] | 1479 | |
---|
[f610e83f] | 1480 | } |
---|
| 1481 | |
---|
| 1482 | /* |
---|
| 1483 | * initialize TSEC hardware: |
---|
| 1484 | * - set interrupt coalescing to BDCount/8, Time of 8 frames |
---|
| 1485 | * - enable DMA snooping |
---|
| 1486 | */ |
---|
[1e86d1e] | 1487 | tsec_hwinit(sc); |
---|
[f610e83f] | 1488 | /* |
---|
| 1489 | * init access to phys |
---|
| 1490 | */ |
---|
[1e86d1e] | 1491 | tsec_mdio_init(sc); |
---|
[f610e83f] | 1492 | /* |
---|
| 1493 | * Start driver tasks |
---|
| 1494 | */ |
---|
[359e537] | 1495 | sc->txDaemonTid = rtems_bsdnet_newproc("TStx", |
---|
| 1496 | 4096, |
---|
[1e86d1e] | 1497 | tsec_txDaemon, |
---|
[f610e83f] | 1498 | sc); |
---|
[359e537] | 1499 | sc->rxDaemonTid = rtems_bsdnet_newproc("TSrx", 4096, |
---|
[1e86d1e] | 1500 | tsec_rxDaemon, |
---|
[f610e83f] | 1501 | sc); |
---|
| 1502 | /* |
---|
| 1503 | * install interrupt handlers |
---|
| 1504 | */ |
---|
[1e86d1e] | 1505 | tsec_install_irq_handlers(sc,true); |
---|
[f610e83f] | 1506 | } |
---|
| 1507 | /* |
---|
| 1508 | * Set flags appropriately |
---|
| 1509 | */ |
---|
| 1510 | if(ifp->if_flags & IFF_PROMISC) { |
---|
[1e86d1e] | 1511 | sc->reg_ptr->rctrl |= TSEC_RCTRL_PROM; |
---|
[f610e83f] | 1512 | } |
---|
| 1513 | else { |
---|
[1e86d1e] | 1514 | sc->reg_ptr->rctrl &= ~TSEC_RCTRL_PROM; |
---|
[f610e83f] | 1515 | } |
---|
| 1516 | |
---|
[c2bc9ef] | 1517 | #if defined(MPC83XX_BOARD_HSC_CM01) |
---|
[59be902] | 1518 | /* |
---|
| 1519 | * for HSC CM01: we need to configure the PHY to use maximum skew adjust |
---|
| 1520 | */ |
---|
[359e537] | 1521 | |
---|
[1e86d1e] | 1522 | tsec_mdio_write(-1,sc,23,0x0100); |
---|
[59be902] | 1523 | #endif |
---|
| 1524 | |
---|
[f610e83f] | 1525 | /* |
---|
| 1526 | * init timer so the "watchdog function gets called periodically |
---|
| 1527 | */ |
---|
| 1528 | ifp->if_timer = 1; |
---|
| 1529 | /* |
---|
| 1530 | * Tell the world that we're running. |
---|
| 1531 | */ |
---|
| 1532 | ifp->if_flags |= IFF_RUNNING; |
---|
| 1533 | } |
---|
| 1534 | |
---|
| 1535 | /*=========================================================================*\ |
---|
| 1536 | | Function: | |
---|
| 1537 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1538 | static void tsec_off |
---|
[f610e83f] | 1539 | ( |
---|
| 1540 | /*-------------------------------------------------------------------------*\ |
---|
| 1541 | | Purpose: | |
---|
| 1542 | | deinitialize the driver and the hardware | |
---|
| 1543 | +---------------------------------------------------------------------------+ |
---|
| 1544 | | Input Parameters: | |
---|
| 1545 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1546 | struct tsec_struct *sc /* ptr to control structure */ |
---|
[f610e83f] | 1547 | ) |
---|
| 1548 | /*-------------------------------------------------------------------------*\ |
---|
| 1549 | | Return Value: | |
---|
| 1550 | | <none> | |
---|
| 1551 | \*=========================================================================*/ |
---|
| 1552 | { |
---|
| 1553 | /* |
---|
[55a685b] | 1554 | * deinitialize driver? |
---|
[f610e83f] | 1555 | */ |
---|
| 1556 | } |
---|
| 1557 | |
---|
| 1558 | /*=========================================================================*\ |
---|
| 1559 | | Function: | |
---|
| 1560 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1561 | static void tsec_stats |
---|
[f610e83f] | 1562 | ( |
---|
| 1563 | /*-------------------------------------------------------------------------*\ |
---|
| 1564 | | Purpose: | |
---|
[55a685b] | 1565 | | print statistics | |
---|
[f610e83f] | 1566 | +---------------------------------------------------------------------------+ |
---|
| 1567 | | Input Parameters: | |
---|
| 1568 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1569 | struct tsec_struct *sc /* ptr to control structure */ |
---|
[f610e83f] | 1570 | ) |
---|
| 1571 | /*-------------------------------------------------------------------------*\ |
---|
| 1572 | | Return Value: | |
---|
| 1573 | | <none> | |
---|
| 1574 | \*=========================================================================*/ |
---|
| 1575 | { |
---|
[06280c35] | 1576 | if (sc->phy_default >= 0) { |
---|
| 1577 | int media; |
---|
| 1578 | int result; |
---|
| 1579 | /* |
---|
| 1580 | * fetch/print media info |
---|
| 1581 | */ |
---|
| 1582 | media = IFM_MAKEWORD(0,0,0,sc->phy_default); /* fetch from default phy */ |
---|
| 1583 | |
---|
| 1584 | result = tsec_ioctl(&(sc->arpcom.ac_if), |
---|
| 1585 | SIOCGIFMEDIA, |
---|
| 1586 | (caddr_t)&media); |
---|
| 1587 | if (result == 0) { |
---|
| 1588 | rtems_ifmedia2str(media,NULL,0); |
---|
| 1589 | printf ("\n"); |
---|
| 1590 | } else { |
---|
| 1591 | printf ("PHY communication error\n"); |
---|
| 1592 | } |
---|
[f610e83f] | 1593 | } |
---|
[41d7c0fe] | 1594 | #if 0 /* print all PHY registers */ |
---|
[42bf1b9] | 1595 | { |
---|
| 1596 | int reg; |
---|
| 1597 | uint32_t reg_val; |
---|
| 1598 | printf("****** PHY register values****\n"); |
---|
| 1599 | for (reg = 0;reg <= 31;reg++) { |
---|
[1e86d1e] | 1600 | tsec_mdio_read(-1,sc,reg,®_val); |
---|
[42bf1b9] | 1601 | printf("%02d:0x%04x%c",reg,reg_val, |
---|
| 1602 | (((reg % 4) == 3) ? '\n' : ' ')); |
---|
| 1603 | } |
---|
| 1604 | } |
---|
[359e537] | 1605 | #endif |
---|
[f610e83f] | 1606 | /* |
---|
| 1607 | * print some statistics |
---|
| 1608 | */ |
---|
[55a685b] | 1609 | printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); |
---|
| 1610 | printf (" Rx Errors:%-8lu", sc->rxErrors); |
---|
[359e537] | 1611 | printf (" Rx packets:%-8lu\n", |
---|
[1e86d1e] | 1612 | sc->reg_ptr->rmon_mib[TSEC_RMON_RPKT]); |
---|
[359e537] | 1613 | printf (" Rx broadcasts:%-8lu", |
---|
[1e86d1e] | 1614 | sc->reg_ptr->rmon_mib[TSEC_RMON_RBCA]); |
---|
[359e537] | 1615 | printf (" Rx multicasts:%-8lu", |
---|
[1e86d1e] | 1616 | sc->reg_ptr->rmon_mib[TSEC_RMON_RMCA]); |
---|
[55a685b] | 1617 | printf (" Giant:%-8lu\n", |
---|
[1e86d1e] | 1618 | sc->reg_ptr->rmon_mib[TSEC_RMON_ROVR]); |
---|
[55a685b] | 1619 | printf (" Non-octet:%-8lu", |
---|
[1e86d1e] | 1620 | sc->reg_ptr->rmon_mib[TSEC_RMON_RALN]); |
---|
[55a685b] | 1621 | printf (" Bad CRC:%-8lu", |
---|
[1e86d1e] | 1622 | sc->reg_ptr->rmon_mib[TSEC_RMON_RFCS]); |
---|
[55a685b] | 1623 | printf (" Overrun:%-8lu\n", |
---|
[1e86d1e] | 1624 | sc->reg_ptr->rmon_mib[TSEC_RMON_RDRP]); |
---|
[359e537] | 1625 | |
---|
[55a685b] | 1626 | printf (" Tx Interrupts:%-8lu", sc->txInterrupts); |
---|
| 1627 | printf (" Tx Errors:%-8lu", sc->txErrors); |
---|
[359e537] | 1628 | printf (" Tx packets:%-8lu\n", |
---|
[1e86d1e] | 1629 | sc->reg_ptr->rmon_mib[TSEC_RMON_TPKT]); |
---|
[55a685b] | 1630 | printf (" Deferred:%-8lu", |
---|
[1e86d1e] | 1631 | sc->reg_ptr->rmon_mib[TSEC_RMON_TDFR]); |
---|
[55a685b] | 1632 | printf (" Late Collision:%-8lu", |
---|
[1e86d1e] | 1633 | sc->reg_ptr->rmon_mib[TSEC_RMON_TLCL]); |
---|
[55a685b] | 1634 | printf ("Retransmit Limit:%-8lu\n", |
---|
[1e86d1e] | 1635 | sc->reg_ptr->rmon_mib[TSEC_RMON_TEDF]); |
---|
[55a685b] | 1636 | printf (" Underrun:%-8lu\n", |
---|
[1e86d1e] | 1637 | sc->reg_ptr->rmon_mib[TSEC_RMON_TUND]); |
---|
[f610e83f] | 1638 | } |
---|
| 1639 | |
---|
| 1640 | /*=========================================================================*\ |
---|
| 1641 | | Function: | |
---|
| 1642 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1643 | static int tsec_ioctl |
---|
[f610e83f] | 1644 | ( |
---|
| 1645 | /*-------------------------------------------------------------------------*\ |
---|
| 1646 | | Purpose: | |
---|
| 1647 | | perform io control functions | |
---|
| 1648 | +---------------------------------------------------------------------------+ |
---|
| 1649 | | Input Parameters: | |
---|
| 1650 | \*-------------------------------------------------------------------------*/ |
---|
| 1651 | struct ifnet *ifp, /* interface information */ |
---|
| 1652 | ioctl_command_t command, /* ioctl command code */ |
---|
| 1653 | caddr_t data /* optional data */ |
---|
| 1654 | ) |
---|
| 1655 | /*-------------------------------------------------------------------------*\ |
---|
| 1656 | | Return Value: | |
---|
| 1657 | | zero, if success | |
---|
| 1658 | \*=========================================================================*/ |
---|
| 1659 | { |
---|
[1e86d1e] | 1660 | struct tsec_struct *sc = ifp->if_softc; |
---|
[f610e83f] | 1661 | int error = 0; |
---|
| 1662 | |
---|
| 1663 | switch(command) { |
---|
| 1664 | /* |
---|
| 1665 | * access PHY via MII |
---|
| 1666 | */ |
---|
| 1667 | case SIOCGIFMEDIA: |
---|
| 1668 | case SIOCSIFMEDIA: |
---|
| 1669 | rtems_mii_ioctl (&(sc->mdio_info),sc,command,(void *)data); |
---|
| 1670 | break; |
---|
| 1671 | case SIOCGIFADDR: |
---|
| 1672 | case SIOCSIFADDR: |
---|
| 1673 | /* |
---|
| 1674 | * pass through to general ether_ioctl |
---|
| 1675 | */ |
---|
| 1676 | ether_ioctl(ifp, command, data); |
---|
| 1677 | break; |
---|
| 1678 | |
---|
| 1679 | case SIOCSIFFLAGS: |
---|
| 1680 | /* |
---|
| 1681 | * adjust active state |
---|
| 1682 | */ |
---|
| 1683 | if (ifp->if_flags & IFF_RUNNING) { |
---|
[1e86d1e] | 1684 | tsec_off(sc); |
---|
[f610e83f] | 1685 | } |
---|
| 1686 | if (ifp->if_flags & IFF_UP) { |
---|
[1e86d1e] | 1687 | tsec_init(sc); |
---|
[f610e83f] | 1688 | } |
---|
| 1689 | break; |
---|
| 1690 | |
---|
| 1691 | case SIO_RTEMS_SHOW_STATS: |
---|
| 1692 | /* |
---|
| 1693 | * show interface statistics |
---|
| 1694 | */ |
---|
[1e86d1e] | 1695 | tsec_stats(sc); |
---|
[f610e83f] | 1696 | break; |
---|
| 1697 | |
---|
| 1698 | /* |
---|
[55a685b] | 1699 | * All sorts of multicast commands need to be added here! |
---|
[f610e83f] | 1700 | */ |
---|
| 1701 | default: |
---|
| 1702 | error = EINVAL; |
---|
| 1703 | break; |
---|
| 1704 | } |
---|
| 1705 | |
---|
| 1706 | return error; |
---|
| 1707 | } |
---|
| 1708 | |
---|
| 1709 | /*=========================================================================*\ |
---|
| 1710 | | Function: | |
---|
| 1711 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1712 | static int tsec_mode_adapt |
---|
[f610e83f] | 1713 | ( |
---|
| 1714 | /*-------------------------------------------------------------------------*\ |
---|
| 1715 | | Purpose: | |
---|
| 1716 | | init the PHY and adapt TSEC settings | |
---|
| 1717 | +---------------------------------------------------------------------------+ |
---|
| 1718 | | Input Parameters: | |
---|
| 1719 | \*-------------------------------------------------------------------------*/ |
---|
| 1720 | struct ifnet *ifp |
---|
| 1721 | ) |
---|
| 1722 | /*-------------------------------------------------------------------------*\ |
---|
| 1723 | | Return Value: | |
---|
| 1724 | | 0, if success | |
---|
| 1725 | \*=========================================================================*/ |
---|
| 1726 | { |
---|
[574fb67] | 1727 | int result = 0; |
---|
[1e86d1e] | 1728 | struct tsec_struct *sc = ifp->if_softc; |
---|
[574fb67] | 1729 | int media = IFM_MAKEWORD( 0, 0, 0, sc->phy_default); |
---|
[f610e83f] | 1730 | |
---|
[f2c8c34] | 1731 | /* In case no PHY is available stop now */ |
---|
| 1732 | if (sc->phy_default < 0) { |
---|
| 1733 | return 0; |
---|
| 1734 | } |
---|
| 1735 | |
---|
[f610e83f] | 1736 | /* |
---|
| 1737 | * fetch media status |
---|
| 1738 | */ |
---|
[1e86d1e] | 1739 | result = tsec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media); |
---|
[f610e83f] | 1740 | if (result != 0) { |
---|
| 1741 | return result; |
---|
| 1742 | } |
---|
[f2c8c34] | 1743 | |
---|
[f610e83f] | 1744 | /* |
---|
| 1745 | * status is unchanged? then do nothing |
---|
| 1746 | */ |
---|
| 1747 | if (media == sc->media_state) { |
---|
| 1748 | return 0; |
---|
| 1749 | } |
---|
| 1750 | /* |
---|
| 1751 | * otherwise: for the first call, try to negotiate mode |
---|
| 1752 | */ |
---|
| 1753 | if (sc->media_state == 0) { |
---|
| 1754 | /* |
---|
| 1755 | * set media status: set auto negotiation -> start auto-negotiation |
---|
| 1756 | */ |
---|
| 1757 | media = IFM_MAKEWORD(0,IFM_AUTO,0,sc->phy_default); |
---|
[1e86d1e] | 1758 | result = tsec_ioctl(ifp,SIOCSIFMEDIA,(caddr_t)&media); |
---|
[f610e83f] | 1759 | if (result != 0) { |
---|
| 1760 | return result; |
---|
| 1761 | } |
---|
| 1762 | /* |
---|
[06280c35] | 1763 | * check auto-negotiation status |
---|
[f610e83f] | 1764 | */ |
---|
[06280c35] | 1765 | media = IFM_MAKEWORD(0,0,0,sc->phy_default); |
---|
| 1766 | result = tsec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media); |
---|
| 1767 | if (result != 0 || IFM_NONE == IFM_SUBTYPE(media)) { |
---|
| 1768 | return result; |
---|
| 1769 | } |
---|
[f610e83f] | 1770 | } |
---|
| 1771 | |
---|
| 1772 | /* |
---|
| 1773 | * now set HW according to media results: |
---|
| 1774 | */ |
---|
| 1775 | /* |
---|
[42bf1b9] | 1776 | * if we are 1000MBit, then switch IF to byte mode |
---|
[f610e83f] | 1777 | */ |
---|
| 1778 | if (IFM_1000_T == IFM_SUBTYPE(media)) { |
---|
[359e537] | 1779 | sc->reg_ptr->maccfg2 = |
---|
[1e86d1e] | 1780 | ((sc->reg_ptr->maccfg2 & ~TSEC_MACCFG2_IFMODE_MSK) |
---|
| 1781 | | TSEC_MACCFG2_IFMODE_BYT); |
---|
[f610e83f] | 1782 | } |
---|
| 1783 | else { |
---|
[359e537] | 1784 | sc->reg_ptr->maccfg2 = |
---|
[1e86d1e] | 1785 | ((sc->reg_ptr->maccfg2 & ~TSEC_MACCFG2_IFMODE_MSK) |
---|
| 1786 | | TSEC_MACCFG2_IFMODE_NIB); |
---|
[f610e83f] | 1787 | } |
---|
[42bf1b9] | 1788 | /* |
---|
| 1789 | * if we are 10MBit, then switch rate to 10M |
---|
| 1790 | */ |
---|
| 1791 | if (IFM_10_T == IFM_SUBTYPE(media)) { |
---|
[1e86d1e] | 1792 | sc->reg_ptr->ecntrl &= ~TSEC_ECNTRL_R100M; |
---|
[42bf1b9] | 1793 | } |
---|
| 1794 | else { |
---|
[1e86d1e] | 1795 | sc->reg_ptr->ecntrl |= TSEC_ECNTRL_R100M; |
---|
[42bf1b9] | 1796 | } |
---|
[f610e83f] | 1797 | /* |
---|
| 1798 | * if we are half duplex then switch to half duplex |
---|
| 1799 | */ |
---|
| 1800 | if (0 == (IFM_FDX & IFM_OPTIONS(media))) { |
---|
[1e86d1e] | 1801 | sc->reg_ptr->maccfg2 &= ~TSEC_MACCFG2_FULLDUPLEX; |
---|
[f610e83f] | 1802 | } |
---|
| 1803 | else { |
---|
[1e86d1e] | 1804 | sc->reg_ptr->maccfg2 |= TSEC_MACCFG2_FULLDUPLEX; |
---|
[359e537] | 1805 | } |
---|
[f610e83f] | 1806 | /* |
---|
| 1807 | * store current media state for future compares |
---|
| 1808 | */ |
---|
| 1809 | sc->media_state = media; |
---|
| 1810 | |
---|
| 1811 | return 0; |
---|
| 1812 | } |
---|
| 1813 | |
---|
| 1814 | /*=========================================================================*\ |
---|
| 1815 | | Function: | |
---|
| 1816 | \*-------------------------------------------------------------------------*/ |
---|
[1e86d1e] | 1817 | static void tsec_watchdog |
---|
[f610e83f] | 1818 | ( |
---|
| 1819 | /*-------------------------------------------------------------------------*\ |
---|
| 1820 | | Purpose: | |
---|
| 1821 | | periodically poll the PHY. if mode has changed, | |
---|
| 1822 | | then adjust the TSEC settings | |
---|
| 1823 | +---------------------------------------------------------------------------+ |
---|
| 1824 | | Input Parameters: | |
---|
| 1825 | \*-------------------------------------------------------------------------*/ |
---|
| 1826 | struct ifnet *ifp |
---|
| 1827 | ) |
---|
| 1828 | /*-------------------------------------------------------------------------*\ |
---|
| 1829 | | Return Value: | |
---|
| 1830 | | 1, if success | |
---|
| 1831 | \*=========================================================================*/ |
---|
| 1832 | { |
---|
[1e86d1e] | 1833 | tsec_mode_adapt(ifp); |
---|
[359e537] | 1834 | ifp->if_timer = TSEC_WATCHDOG_TIMEOUT; |
---|
[f610e83f] | 1835 | } |
---|
| 1836 | |
---|
[f2c8c34] | 1837 | static int tsec_driver_attach(struct rtems_bsdnet_ifconfig *config) |
---|
[f610e83f] | 1838 | { |
---|
[f2c8c34] | 1839 | tsec_config *tsec_cfg = config->drv_ctrl; |
---|
| 1840 | int unitNumber = tsec_cfg->unit_number; |
---|
| 1841 | char *unitName = tsec_cfg->unit_name; |
---|
[1e86d1e] | 1842 | struct tsec_struct *sc; |
---|
[f610e83f] | 1843 | struct ifnet *ifp; |
---|
| 1844 | |
---|
| 1845 | /* |
---|
| 1846 | * Is driver free? |
---|
| 1847 | */ |
---|
[1e86d1e] | 1848 | if ((unitNumber <= 0) || (unitNumber > TSEC_COUNT)) { |
---|
[f610e83f] | 1849 | |
---|
| 1850 | printk ("Bad TSEC unit number.\n"); |
---|
| 1851 | return 0; |
---|
| 1852 | |
---|
| 1853 | } |
---|
| 1854 | |
---|
| 1855 | sc = &tsec_driver[unitNumber - 1]; |
---|
| 1856 | ifp = &sc->arpcom.ac_if; |
---|
| 1857 | |
---|
| 1858 | if(ifp->if_softc != NULL) { |
---|
| 1859 | printk ("Driver already in use.\n"); |
---|
| 1860 | return 0; |
---|
| 1861 | } |
---|
| 1862 | |
---|
| 1863 | /* |
---|
| 1864 | * Process options |
---|
| 1865 | */ |
---|
| 1866 | if(config->hardware_address) { |
---|
| 1867 | memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); |
---|
| 1868 | } |
---|
| 1869 | else { |
---|
| 1870 | rtems_panic("TSEC: No Ethernet address specified!\n"); |
---|
| 1871 | } |
---|
| 1872 | |
---|
| 1873 | sc->rxBdCount = (config->rbuf_count > 0) ? config->rbuf_count : RX_BUF_COUNT; |
---|
| 1874 | sc->txBdCount = (config->xbuf_count > 0) ? config->xbuf_count : TX_BUF_COUNT; |
---|
| 1875 | sc->acceptBroadcast = !config->ignore_broadcast; |
---|
| 1876 | |
---|
| 1877 | /* get pointer to TSEC register block */ |
---|
[f2c8c34] | 1878 | sc->reg_ptr = tsec_cfg->reg_ptr; |
---|
| 1879 | sc->mdio_ptr = tsec_cfg->mdio_ptr; |
---|
[574fb67] | 1880 | |
---|
[f2c8c34] | 1881 | /* IRQ numbers */ |
---|
| 1882 | sc->irq_num_tx = tsec_cfg->irq_num_tx; |
---|
| 1883 | sc->irq_num_rx = tsec_cfg->irq_num_rx; |
---|
| 1884 | sc->irq_num_err = tsec_cfg->irq_num_err; |
---|
[574fb67] | 1885 | |
---|
[f610e83f] | 1886 | /* |
---|
| 1887 | * setup info about mdio interface |
---|
| 1888 | */ |
---|
[1e86d1e] | 1889 | sc->mdio_info.mdio_r = tsec_mdio_read; |
---|
| 1890 | sc->mdio_info.mdio_w = tsec_mdio_write; |
---|
[f610e83f] | 1891 | sc->mdio_info.has_gmii = 1; /* we support gigabit IF */ |
---|
[574fb67] | 1892 | |
---|
[f2c8c34] | 1893 | /* PHY address */ |
---|
| 1894 | sc->phy_default = tsec_cfg->phy_default; |
---|
[574fb67] | 1895 | |
---|
[f610e83f] | 1896 | /* |
---|
| 1897 | * Set up network interface values |
---|
| 1898 | */ |
---|
| 1899 | ifp->if_softc = sc; |
---|
| 1900 | ifp->if_unit = unitNumber; |
---|
| 1901 | ifp->if_name = unitName; |
---|
| 1902 | ifp->if_mtu = (config->mtu > 0) ? config->mtu : ETHERMTU; |
---|
[1e86d1e] | 1903 | ifp->if_init = tsec_init; |
---|
| 1904 | ifp->if_ioctl = tsec_ioctl; |
---|
| 1905 | ifp->if_start = tsec_tx_start; |
---|
[f610e83f] | 1906 | ifp->if_output = ether_output; |
---|
[1e86d1e] | 1907 | ifp->if_watchdog = tsec_watchdog; /* XXX: timer is set in "init" */ |
---|
[f610e83f] | 1908 | |
---|
| 1909 | ifp->if_flags = (config->ignore_broadcast) ? 0 : IFF_BROADCAST; |
---|
| 1910 | /*ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;*/ |
---|
| 1911 | |
---|
| 1912 | if(ifp->if_snd.ifq_maxlen == 0) { |
---|
| 1913 | ifp->if_snd.ifq_maxlen = ifqmaxlen; |
---|
| 1914 | } |
---|
| 1915 | |
---|
| 1916 | /* |
---|
| 1917 | * Attach the interface |
---|
| 1918 | */ |
---|
| 1919 | if_attach(ifp); |
---|
| 1920 | |
---|
| 1921 | ether_ifattach(ifp); |
---|
| 1922 | |
---|
| 1923 | return 1; |
---|
| 1924 | } |
---|
| 1925 | |
---|
[1e86d1e] | 1926 | int tsec_driver_attach_detach( |
---|
| 1927 | struct rtems_bsdnet_ifconfig *config, |
---|
| 1928 | int attaching |
---|
[f610e83f] | 1929 | ) |
---|
| 1930 | { |
---|
| 1931 | if (attaching) { |
---|
[f2c8c34] | 1932 | return tsec_driver_attach(config); |
---|
[1e86d1e] | 1933 | } else { |
---|
[f610e83f] | 1934 | return 0; |
---|
| 1935 | } |
---|
| 1936 | } |
---|