[81d914d8] | 1 | /* |
---|
[050249d] | 2 | * Gaisler Research ethernet MAC driver |
---|
| 3 | * adapted from Opencores driver by Marko Isomaki |
---|
[81d914d8] | 4 | * |
---|
| 5 | * The license and distribution terms for this file may be |
---|
| 6 | * found in found in the file LICENSE in this distribution or at |
---|
[2697be56] | 7 | * http://www.rtems.com/license/LICENSE. |
---|
[81d914d8] | 8 | * |
---|
| 9 | * $Id$ |
---|
[050249d] | 10 | * |
---|
| 11 | * 2007-09-07, Ported GBIT support from 4.6.5 |
---|
[81d914d8] | 12 | */ |
---|
| 13 | |
---|
| 14 | #include <rtems.h> |
---|
| 15 | |
---|
| 16 | #define GRETH_SUPPORTED |
---|
| 17 | #include <bsp.h> |
---|
| 18 | |
---|
| 19 | #include <inttypes.h> |
---|
| 20 | #include <errno.h> |
---|
[050249d] | 21 | #include <rtems/bspIo.h> |
---|
[81d914d8] | 22 | #include <stdlib.h> |
---|
| 23 | #include <stdio.h> |
---|
| 24 | #include <stdarg.h> |
---|
| 25 | #include <rtems/error.h> |
---|
| 26 | #include <rtems/rtems_bsdnet.h> |
---|
| 27 | #include "greth.h" |
---|
| 28 | |
---|
| 29 | #include <sys/param.h> |
---|
| 30 | #include <sys/mbuf.h> |
---|
| 31 | |
---|
| 32 | #include <sys/socket.h> |
---|
| 33 | #include <sys/sockio.h> |
---|
| 34 | #include <net/if.h> |
---|
| 35 | #include <netinet/in.h> |
---|
| 36 | #include <netinet/if_ether.h> |
---|
| 37 | |
---|
| 38 | #ifdef malloc |
---|
| 39 | #undef malloc |
---|
| 40 | #endif |
---|
| 41 | #ifdef free |
---|
| 42 | #undef free |
---|
| 43 | #endif |
---|
| 44 | |
---|
[7f247f3] | 45 | #if defined(__m68k__) |
---|
| 46 | extern m68k_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int ); |
---|
| 47 | #else |
---|
[ac5b81c3] | 48 | extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int ); |
---|
[7f247f3] | 49 | #endif |
---|
[a612b50] | 50 | |
---|
[050249d] | 51 | |
---|
| 52 | /* #define GRETH_DEBUG */ |
---|
[81d914d8] | 53 | |
---|
| 54 | #ifdef CPU_U32_FIX |
---|
| 55 | extern void ipalign(struct mbuf *m); |
---|
| 56 | #endif |
---|
| 57 | |
---|
| 58 | /* |
---|
| 59 | * Number of OCs supported by this driver |
---|
| 60 | */ |
---|
| 61 | #define NOCDRIVER 1 |
---|
| 62 | |
---|
| 63 | /* |
---|
| 64 | * Receive buffer size -- Allow for a full ethernet packet including CRC |
---|
| 65 | */ |
---|
| 66 | #define RBUF_SIZE 1518 |
---|
| 67 | |
---|
| 68 | #define ET_MINLEN 64 /* minimum message length */ |
---|
| 69 | |
---|
| 70 | /* |
---|
| 71 | * RTEMS event used by interrupt handler to signal driver tasks. |
---|
| 72 | * This must not be any of the events used by the network task synchronization. |
---|
| 73 | */ |
---|
| 74 | #define INTERRUPT_EVENT RTEMS_EVENT_1 |
---|
| 75 | |
---|
| 76 | /* |
---|
| 77 | * RTEMS event used to start transmit daemon. |
---|
| 78 | * This must not be the same as INTERRUPT_EVENT. |
---|
| 79 | */ |
---|
| 80 | #define START_TRANSMIT_EVENT RTEMS_EVENT_2 |
---|
| 81 | |
---|
| 82 | /* event to send when tx buffers become available */ |
---|
| 83 | #define GRETH_TX_WAIT_EVENT RTEMS_EVENT_3 |
---|
| 84 | |
---|
| 85 | /* suspend when all TX descriptors exhausted */ |
---|
| 86 | /* |
---|
| 87 | #define GRETH_SUSPEND_NOTXBUF |
---|
| 88 | */ |
---|
| 89 | |
---|
| 90 | #if (MCLBYTES < RBUF_SIZE) |
---|
| 91 | # error "Driver must have MCLBYTES > RBUF_SIZE" |
---|
| 92 | #endif |
---|
| 93 | |
---|
[050249d] | 94 | /* 4s Autonegotiation Timeout */ |
---|
| 95 | #ifndef GRETH_AUTONEGO_TIMEOUT_MS |
---|
| 96 | #define GRETH_AUTONEGO_TIMEOUT_MS 4000 |
---|
| 97 | #endif |
---|
| 98 | |
---|
| 99 | /* For optimizing the autonegotiation time */ |
---|
| 100 | #define GRETH_AUTONEGO_PRINT_TIME |
---|
| 101 | |
---|
[81d914d8] | 102 | /* Ethernet buffer descriptor */ |
---|
| 103 | |
---|
| 104 | typedef struct _greth_rxtxdesc { |
---|
| 105 | volatile uint32_t ctrl; /* Length and status */ |
---|
| 106 | uint32_t *addr; /* Buffer pointer */ |
---|
| 107 | } greth_rxtxdesc; |
---|
| 108 | |
---|
[050249d] | 109 | |
---|
[81d914d8] | 110 | /* |
---|
| 111 | * Per-device data |
---|
| 112 | */ |
---|
| 113 | struct greth_softc |
---|
| 114 | { |
---|
| 115 | |
---|
| 116 | struct arpcom arpcom; |
---|
[3495c57] | 117 | |
---|
[81d914d8] | 118 | greth_regs *regs; |
---|
[3495c57] | 119 | |
---|
[81d914d8] | 120 | int acceptBroadcast; |
---|
| 121 | rtems_id rxDaemonTid; |
---|
| 122 | rtems_id txDaemonTid; |
---|
[3495c57] | 123 | |
---|
[81d914d8] | 124 | unsigned int tx_ptr; |
---|
[050249d] | 125 | unsigned int tx_dptr; |
---|
| 126 | unsigned int tx_cnt; |
---|
[81d914d8] | 127 | unsigned int rx_ptr; |
---|
| 128 | unsigned int txbufs; |
---|
| 129 | unsigned int rxbufs; |
---|
| 130 | greth_rxtxdesc *txdesc; |
---|
| 131 | greth_rxtxdesc *rxdesc; |
---|
| 132 | struct mbuf **rxmbuf; |
---|
[050249d] | 133 | struct mbuf **txmbuf; |
---|
[81d914d8] | 134 | rtems_vector_number vector; |
---|
[3495c57] | 135 | |
---|
[050249d] | 136 | /*Status*/ |
---|
| 137 | struct phy_device_info phydev; |
---|
| 138 | int fd; |
---|
| 139 | int sp; |
---|
| 140 | int gb; |
---|
| 141 | int gbit_mac; |
---|
| 142 | int auto_neg; |
---|
| 143 | unsigned int auto_neg_time; |
---|
[3495c57] | 144 | |
---|
[81d914d8] | 145 | /* |
---|
| 146 | * Statistics |
---|
| 147 | */ |
---|
| 148 | unsigned long rxInterrupts; |
---|
[3495c57] | 149 | |
---|
[81d914d8] | 150 | unsigned long rxPackets; |
---|
| 151 | unsigned long rxLengthError; |
---|
| 152 | unsigned long rxNonOctet; |
---|
| 153 | unsigned long rxBadCRC; |
---|
| 154 | unsigned long rxOverrun; |
---|
[3495c57] | 155 | |
---|
[81d914d8] | 156 | unsigned long txInterrupts; |
---|
[3495c57] | 157 | |
---|
[81d914d8] | 158 | unsigned long txDeferred; |
---|
| 159 | unsigned long txHeartbeat; |
---|
| 160 | unsigned long txLateCollision; |
---|
| 161 | unsigned long txRetryLimit; |
---|
| 162 | unsigned long txUnderrun; |
---|
[050249d] | 163 | |
---|
[81d914d8] | 164 | }; |
---|
| 165 | |
---|
| 166 | static struct greth_softc greth; |
---|
| 167 | |
---|
| 168 | static char *almalloc(int sz) |
---|
| 169 | { |
---|
| 170 | char *tmp; |
---|
| 171 | tmp = calloc(1,2*sz); |
---|
[c48572d9] | 172 | tmp = (char *) (((uintptr_t)tmp+sz) & ~(sz -1)); |
---|
[81d914d8] | 173 | return(tmp); |
---|
| 174 | } |
---|
| 175 | |
---|
| 176 | /* GRETH interrupt handler */ |
---|
| 177 | |
---|
| 178 | static rtems_isr |
---|
| 179 | greth_interrupt_handler (rtems_vector_number v) |
---|
| 180 | { |
---|
[050249d] | 181 | uint32_t status; |
---|
| 182 | /* read and clear interrupt cause */ |
---|
[3495c57] | 183 | |
---|
[050249d] | 184 | status = greth.regs->status; |
---|
| 185 | greth.regs->status = status; |
---|
[3495c57] | 186 | |
---|
[050249d] | 187 | /* Frame received? */ |
---|
| 188 | if (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ)) |
---|
| 189 | { |
---|
| 190 | greth.rxInterrupts++; |
---|
| 191 | rtems_event_send (greth.rxDaemonTid, INTERRUPT_EVENT); |
---|
| 192 | } |
---|
[81d914d8] | 193 | #ifdef GRETH_SUSPEND_NOTXBUF |
---|
[050249d] | 194 | if (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ)) |
---|
| 195 | { |
---|
| 196 | greth.txInterrupts++; |
---|
| 197 | rtems_event_send (greth.txDaemonTid, GRETH_TX_WAIT_EVENT); |
---|
| 198 | } |
---|
[81d914d8] | 199 | #endif |
---|
[050249d] | 200 | /* |
---|
| 201 | #ifdef __leon__ |
---|
| 202 | LEON_Clear_interrupt(v-0x10); |
---|
| 203 | #endif |
---|
| 204 | */ |
---|
[81d914d8] | 205 | } |
---|
| 206 | |
---|
[050249d] | 207 | static uint32_t read_mii(uint32_t phy_addr, uint32_t reg_addr) |
---|
[81d914d8] | 208 | { |
---|
| 209 | while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {} |
---|
[050249d] | 210 | greth.regs->mdio_ctrl = (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_READ; |
---|
[81d914d8] | 211 | while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {} |
---|
| 212 | if (!(greth.regs->mdio_ctrl & GRETH_MDIO_LINKFAIL)) |
---|
| 213 | return((greth.regs->mdio_ctrl >> 16) & 0xFFFF); |
---|
| 214 | else { |
---|
| 215 | printf("greth: failed to read mii\n"); |
---|
| 216 | return (0); |
---|
| 217 | } |
---|
| 218 | } |
---|
| 219 | |
---|
[050249d] | 220 | static void write_mii(uint32_t phy_addr, uint32_t reg_addr, uint32_t data) |
---|
[81d914d8] | 221 | { |
---|
| 222 | while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {} |
---|
[050249d] | 223 | greth.regs->mdio_ctrl = |
---|
| 224 | ((data & 0xFFFF) << 16) | (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_WRITE; |
---|
[81d914d8] | 225 | while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {} |
---|
| 226 | } |
---|
[050249d] | 227 | |
---|
[3495c57] | 228 | static void print_init_info(struct greth_softc *sc) |
---|
[050249d] | 229 | { |
---|
| 230 | printf("greth: driver attached\n"); |
---|
| 231 | printf("**** PHY ****\n"); |
---|
| 232 | printf("Vendor: %x Device: %x Revision: %d\n",sc->phydev.vendor, sc->phydev.device, sc->phydev.rev); |
---|
| 233 | printf("Current Operating Mode: "); |
---|
| 234 | if (sc->gb) { |
---|
| 235 | printf("1000 Mbit "); |
---|
| 236 | } else if (sc->sp) { |
---|
| 237 | printf("100 Mbit "); |
---|
| 238 | } else { |
---|
| 239 | printf("10 Mbit "); |
---|
| 240 | } |
---|
| 241 | if (sc->fd) { |
---|
| 242 | printf("Full Duplex\n"); |
---|
| 243 | } else { |
---|
| 244 | printf("Half Duplex\n"); |
---|
| 245 | } |
---|
| 246 | #ifdef GRETH_AUTONEGO_PRINT_TIME |
---|
| 247 | if ( sc->auto_neg ){ |
---|
| 248 | printf("Autonegotiation Time: %dms\n",sc->auto_neg_time); |
---|
| 249 | } |
---|
| 250 | #endif |
---|
| 251 | } |
---|
| 252 | |
---|
| 253 | |
---|
[81d914d8] | 254 | /* |
---|
| 255 | * Initialize the ethernet hardware |
---|
| 256 | */ |
---|
| 257 | static void |
---|
| 258 | greth_initialize_hardware (struct greth_softc *sc) |
---|
| 259 | { |
---|
| 260 | struct mbuf *m; |
---|
| 261 | int i; |
---|
[050249d] | 262 | int phyaddr; |
---|
| 263 | int phyctrl; |
---|
| 264 | int phystatus; |
---|
| 265 | int tmp1; |
---|
| 266 | int tmp2; |
---|
| 267 | unsigned int msecs; |
---|
[57674ef] | 268 | struct timeval tstart, tnow; |
---|
[1fe0257] | 269 | int anegtout; |
---|
[050249d] | 270 | |
---|
[81d914d8] | 271 | greth_regs *regs; |
---|
| 272 | |
---|
| 273 | regs = sc->regs; |
---|
[3495c57] | 274 | |
---|
[81d914d8] | 275 | /* Reset the controller. */ |
---|
| 276 | greth.rxInterrupts = 0; |
---|
| 277 | greth.rxPackets = 0; |
---|
| 278 | |
---|
| 279 | regs->ctrl = 0; |
---|
| 280 | regs->ctrl = GRETH_CTRL_RST; /* Reset ON */ |
---|
| 281 | regs->ctrl = 0; /* Reset OFF */ |
---|
[3495c57] | 282 | |
---|
[050249d] | 283 | /* Check if mac is gbit capable*/ |
---|
[3495c57] | 284 | sc->gbit_mac = (regs->ctrl >> 27) & 1; |
---|
| 285 | |
---|
[050249d] | 286 | /* Get the phy address which assumed to have been set |
---|
| 287 | correctly with the reset value in hardware*/ |
---|
| 288 | phyaddr = (regs->mdio_ctrl >> 11) & 0x1F; |
---|
| 289 | |
---|
| 290 | /* get phy control register default values */ |
---|
| 291 | while ((phyctrl = read_mii(phyaddr, 0)) & 0x8000) {} |
---|
[3495c57] | 292 | |
---|
[050249d] | 293 | /* reset PHY and wait for completion */ |
---|
| 294 | write_mii(phyaddr, 0, 0x8000 | phyctrl); |
---|
| 295 | |
---|
| 296 | while ((read_mii(phyaddr, 0)) & 0x8000) {} |
---|
[3495c57] | 297 | |
---|
| 298 | /* Check if PHY is autoneg capable and then determine operating mode, |
---|
[050249d] | 299 | otherwise force it to 10 Mbit halfduplex */ |
---|
| 300 | sc->gb = 0; |
---|
| 301 | sc->fd = 0; |
---|
| 302 | sc->sp = 0; |
---|
| 303 | sc->auto_neg = 0; |
---|
| 304 | sc->auto_neg_time = 0; |
---|
[1fe0257] | 305 | /* the anegtout variable is needed because print cannot be done before mac has |
---|
| 306 | been reconfigured due to a possible deadlock situation if rtems |
---|
| 307 | is run through the edcl with uart polling (-u)*/ |
---|
| 308 | anegtout = 0; |
---|
[050249d] | 309 | if ((phyctrl >> 12) & 1) { |
---|
| 310 | /*wait for auto negotiation to complete*/ |
---|
| 311 | msecs = 0; |
---|
| 312 | sc->auto_neg = 1; |
---|
[57674ef] | 313 | if ( rtems_clock_get_tod_timeval(&tstart) == RTEMS_NOT_DEFINED){ |
---|
[050249d] | 314 | /* Not inited, set to epoch */ |
---|
| 315 | rtems_time_of_day time; |
---|
| 316 | time.year = 1988; |
---|
| 317 | time.month = 1; |
---|
| 318 | time.day = 1; |
---|
| 319 | time.hour = 0; |
---|
| 320 | time.minute = 0; |
---|
| 321 | time.second = 0; |
---|
| 322 | time.ticks = 0; |
---|
| 323 | rtems_clock_set(&time); |
---|
| 324 | |
---|
[57674ef] | 325 | tstart.tv_sec = 0; |
---|
| 326 | tstart.tv_usec = 0; |
---|
| 327 | rtems_clock_get_tod_timeval(&tstart); |
---|
[050249d] | 328 | } |
---|
| 329 | while (!(((phystatus = read_mii(phyaddr, 1)) >> 5) & 1)) { |
---|
[57674ef] | 330 | if ( rtems_clock_get_tod_timeval(&tnow) != RTEMS_SUCCESSFUL ) |
---|
| 331 | printk("rtems_clock_get_tod_timeval failed\n\r"); |
---|
| 332 | msecs = (tnow.tv_sec-tstart.tv_sec)*1000+(tnow.tv_usec-tstart.tv_usec)/1000; |
---|
[050249d] | 333 | if ( msecs > GRETH_AUTONEGO_TIMEOUT_MS ){ |
---|
| 334 | sc->auto_neg_time = msecs; |
---|
[1fe0257] | 335 | anegtout = 1 |
---|
[050249d] | 336 | tmp1 = read_mii(phyaddr, 0); |
---|
| 337 | sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1); |
---|
| 338 | sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1); |
---|
| 339 | sc->fd = (phyctrl >> 8) & 1; |
---|
| 340 | goto auto_neg_done; |
---|
| 341 | } |
---|
| 342 | } |
---|
| 343 | sc->auto_neg_time = msecs; |
---|
| 344 | sc->phydev.adv = read_mii(phyaddr, 4); |
---|
| 345 | sc->phydev.part = read_mii(phyaddr, 5); |
---|
| 346 | if ((phystatus >> 8) & 1) { |
---|
| 347 | sc->phydev.extadv = read_mii(phyaddr, 9); |
---|
| 348 | sc->phydev.extpart = read_mii(phyaddr, 10); |
---|
| 349 | if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000FD) && |
---|
| 350 | (sc->phydev.extpart & GRETH_MII_EXTPRT_1000FD)) { |
---|
| 351 | sc->gb = 1; |
---|
| 352 | sc->fd = 1; |
---|
| 353 | } |
---|
| 354 | if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000HD) && |
---|
| 355 | (sc->phydev.extpart & GRETH_MII_EXTPRT_1000HD)) { |
---|
| 356 | sc->gb = 1; |
---|
| 357 | sc->fd = 0; |
---|
| 358 | } |
---|
| 359 | } |
---|
| 360 | if ((sc->gb == 0) || ((sc->gb == 1) && (sc->gbit_mac == 0))) { |
---|
| 361 | if ( (sc->phydev.adv & GRETH_MII_100TXFD) && |
---|
| 362 | (sc->phydev.part & GRETH_MII_100TXFD)) { |
---|
| 363 | sc->sp = 1; |
---|
| 364 | sc->fd = 1; |
---|
| 365 | } |
---|
| 366 | if ( (sc->phydev.adv & GRETH_MII_100TXHD) && |
---|
| 367 | (sc->phydev.part & GRETH_MII_100TXHD)) { |
---|
| 368 | sc->sp = 1; |
---|
| 369 | sc->fd = 0; |
---|
| 370 | } |
---|
| 371 | if ( (sc->phydev.adv & GRETH_MII_10FD) && |
---|
| 372 | (sc->phydev.part & GRETH_MII_10FD)) { |
---|
| 373 | sc->fd = 1; |
---|
| 374 | } |
---|
| 375 | } |
---|
| 376 | } |
---|
| 377 | auto_neg_done: |
---|
| 378 | sc->phydev.vendor = 0; |
---|
| 379 | sc->phydev.device = 0; |
---|
| 380 | sc->phydev.rev = 0; |
---|
| 381 | phystatus = read_mii(phyaddr, 1); |
---|
[3495c57] | 382 | |
---|
[050249d] | 383 | /*Read out PHY info if extended registers are available */ |
---|
[3495c57] | 384 | if (phystatus & 1) { |
---|
[050249d] | 385 | tmp1 = read_mii(phyaddr, 2); |
---|
| 386 | tmp2 = read_mii(phyaddr, 3); |
---|
| 387 | |
---|
| 388 | sc->phydev.vendor = (tmp1 << 6) | ((tmp2 >> 10) & 0x3F); |
---|
| 389 | sc->phydev.rev = tmp2 & 0xF; |
---|
| 390 | sc->phydev.device = (tmp2 >> 4) & 0x3F; |
---|
| 391 | } |
---|
| 392 | |
---|
| 393 | /* Force to 10 mbit half duplex if the 10/100 MAC is used with a 1000 PHY*/ |
---|
| 394 | /*check if marvell 88EE1111 PHY. Needs special reset handling */ |
---|
| 395 | if ((phystatus & 1) && (sc->phydev.vendor == 0x005043) && (sc->phydev.device == 0x0C)) { |
---|
| 396 | if (((sc->gb) && !(sc->gbit_mac)) || !((phyctrl >> 12) & 1)) { |
---|
| 397 | write_mii(phyaddr, 0, sc->sp << 13); |
---|
| 398 | write_mii(phyaddr, 0, 0x8000); |
---|
| 399 | sc->gb = 0; |
---|
| 400 | sc->sp = 0; |
---|
| 401 | sc->fd = 0; |
---|
| 402 | } |
---|
| 403 | } else { |
---|
| 404 | if (((sc->gb) && !(sc->gbit_mac)) || !((phyctrl >> 12) & 1)) { |
---|
| 405 | write_mii(phyaddr, 0, sc->sp << 13); |
---|
| 406 | sc->gb = 0; |
---|
| 407 | sc->sp = 0; |
---|
| 408 | sc->fd = 0; |
---|
| 409 | } |
---|
| 410 | } |
---|
| 411 | while ((read_mii(phyaddr, 0)) & 0x8000) {} |
---|
| 412 | |
---|
| 413 | regs->ctrl = 0; |
---|
| 414 | regs->ctrl = GRETH_CTRL_RST; /* Reset ON */ |
---|
| 415 | regs->ctrl = 0; |
---|
[81d914d8] | 416 | |
---|
| 417 | /* Initialize rx/tx descriptor pointers */ |
---|
| 418 | sc->txdesc = (greth_rxtxdesc *) almalloc(1024); |
---|
| 419 | sc->rxdesc = (greth_rxtxdesc *) almalloc(1024); |
---|
| 420 | sc->tx_ptr = 0; |
---|
[050249d] | 421 | sc->tx_dptr = 0; |
---|
| 422 | sc->tx_cnt = 0; |
---|
[81d914d8] | 423 | sc->rx_ptr = 0; |
---|
[c48572d9] | 424 | regs->txdesc = (uintptr_t) sc->txdesc; |
---|
| 425 | regs->rxdesc = (uintptr_t) sc->rxdesc; |
---|
[3495c57] | 426 | |
---|
[81d914d8] | 427 | sc->rxmbuf = calloc(sc->rxbufs, sizeof(*sc->rxmbuf)); |
---|
[050249d] | 428 | sc->txmbuf = calloc(sc->txbufs, sizeof(*sc->txmbuf)); |
---|
[81d914d8] | 429 | |
---|
| 430 | for (i = 0; i < sc->txbufs; i++) |
---|
| 431 | { |
---|
[050249d] | 432 | sc->txdesc[i].ctrl = 0; |
---|
| 433 | if (!(sc->gbit_mac)) { |
---|
| 434 | sc->txdesc[i].addr = malloc(GRETH_MAXBUF_LEN); |
---|
| 435 | } |
---|
[81d914d8] | 436 | #ifdef GRETH_DEBUG |
---|
[050249d] | 437 | /* printf("TXBUF: %08x\n", (int) sc->txdesc[i].addr); */ |
---|
[81d914d8] | 438 | #endif |
---|
| 439 | } |
---|
| 440 | for (i = 0; i < sc->rxbufs; i++) |
---|
| 441 | { |
---|
| 442 | |
---|
| 443 | MGETHDR (m, M_WAIT, MT_DATA); |
---|
| 444 | MCLGET (m, M_WAIT); |
---|
[050249d] | 445 | if (sc->gbit_mac) |
---|
| 446 | m->m_data += 2; |
---|
[81d914d8] | 447 | m->m_pkthdr.rcvif = &sc->arpcom.ac_if; |
---|
| 448 | sc->rxmbuf[i] = m; |
---|
| 449 | sc->rxdesc[i].addr = (uint32_t *) mtod(m, uint32_t *); |
---|
| 450 | sc->rxdesc[i].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ; |
---|
| 451 | #ifdef GRETH_DEBUG |
---|
[050249d] | 452 | /* printf("RXBUF: %08x\n", (int) sc->rxdesc[i].addr); */ |
---|
[81d914d8] | 453 | #endif |
---|
| 454 | } |
---|
| 455 | sc->rxdesc[sc->rxbufs - 1].ctrl |= GRETH_RXD_WRAP; |
---|
| 456 | |
---|
| 457 | /* set ethernet address. */ |
---|
[3495c57] | 458 | regs->mac_addr_msb = |
---|
[81d914d8] | 459 | sc->arpcom.ac_enaddr[0] << 8 | sc->arpcom.ac_enaddr[1]; |
---|
[c48572d9] | 460 | |
---|
| 461 | uint32_t mac_addr_lsb; |
---|
| 462 | mac_addr_lsb = sc->arpcom.ac_enaddr[2]; |
---|
| 463 | mac_addr_lsb <<= 8; |
---|
| 464 | mac_addr_lsb |= sc->arpcom.ac_enaddr[3]; |
---|
| 465 | mac_addr_lsb <<= 8; |
---|
| 466 | mac_addr_lsb |= sc->arpcom.ac_enaddr[4]; |
---|
| 467 | mac_addr_lsb <<= 8; |
---|
| 468 | mac_addr_lsb |= sc->arpcom.ac_enaddr[5]; |
---|
| 469 | regs->mac_addr_lsb = mac_addr_lsb; |
---|
[81d914d8] | 470 | |
---|
| 471 | /* install interrupt vector */ |
---|
| 472 | set_vector(greth_interrupt_handler, sc->vector, 1); |
---|
| 473 | |
---|
| 474 | /* clear all pending interrupts */ |
---|
| 475 | |
---|
| 476 | regs->status = 0xffffffff; |
---|
| 477 | |
---|
| 478 | #ifdef GRETH_SUSPEND_NOTXBUF |
---|
| 479 | regs->ctrl |= GRETH_CTRL_TXIRQ; |
---|
| 480 | #endif |
---|
| 481 | |
---|
[050249d] | 482 | regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8); |
---|
[1fe0257] | 483 | |
---|
| 484 | if (anegtout) { |
---|
| 485 | printk("Auto negotiation timed out. Selecting default config\n\r"); |
---|
| 486 | } |
---|
| 487 | |
---|
[050249d] | 488 | print_init_info(sc); |
---|
[81d914d8] | 489 | } |
---|
| 490 | |
---|
| 491 | static void |
---|
| 492 | greth_rxDaemon (void *arg) |
---|
| 493 | { |
---|
| 494 | struct ether_header *eh; |
---|
| 495 | struct greth_softc *dp = (struct greth_softc *) &greth; |
---|
| 496 | struct ifnet *ifp = &dp->arpcom.ac_if; |
---|
| 497 | struct mbuf *m; |
---|
| 498 | unsigned int len, len_status, bad; |
---|
| 499 | rtems_event_set events; |
---|
[3495c57] | 500 | |
---|
[81d914d8] | 501 | for (;;) |
---|
| 502 | { |
---|
| 503 | rtems_bsdnet_event_receive (INTERRUPT_EVENT, |
---|
| 504 | RTEMS_WAIT | RTEMS_EVENT_ANY, |
---|
| 505 | RTEMS_NO_TIMEOUT, &events); |
---|
[3495c57] | 506 | |
---|
[81d914d8] | 507 | #ifdef GRETH_ETH_DEBUG |
---|
| 508 | printf ("r\n"); |
---|
| 509 | #endif |
---|
[050249d] | 510 | while (!((len_status = |
---|
| 511 | dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE)) |
---|
[81d914d8] | 512 | { |
---|
[050249d] | 513 | bad = 0; |
---|
| 514 | if (len_status & GRETH_RXD_TOOLONG) |
---|
| 515 | { |
---|
| 516 | dp->rxLengthError++; |
---|
| 517 | bad = 1; |
---|
| 518 | } |
---|
| 519 | if (len_status & GRETH_RXD_DRIBBLE) |
---|
| 520 | { |
---|
| 521 | dp->rxNonOctet++; |
---|
| 522 | bad = 1; |
---|
| 523 | } |
---|
| 524 | if (len_status & GRETH_RXD_CRCERR) |
---|
| 525 | { |
---|
| 526 | dp->rxBadCRC++; |
---|
| 527 | bad = 1; |
---|
| 528 | } |
---|
| 529 | if (len_status & GRETH_RXD_OVERRUN) |
---|
| 530 | { |
---|
| 531 | dp->rxOverrun++; |
---|
| 532 | bad = 1; |
---|
| 533 | } |
---|
| 534 | if (len_status & GRETH_RXD_LENERR) |
---|
| 535 | { |
---|
| 536 | dp->rxLengthError++; |
---|
| 537 | bad = 1; |
---|
| 538 | } |
---|
| 539 | if (!bad) |
---|
| 540 | { |
---|
| 541 | /* pass on the packet in the receive buffer */ |
---|
| 542 | len = len_status & 0x7FF; |
---|
| 543 | m = dp->rxmbuf[dp->rx_ptr]; |
---|
| 544 | #ifdef GRETH_DEBUG |
---|
| 545 | int i; |
---|
| 546 | printf("RX: 0x%08x, Len: %d : ", (int) m->m_data, len); |
---|
| 547 | for (i=0; i<len; i++) |
---|
| 548 | printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff); |
---|
| 549 | printf("\n"); |
---|
| 550 | #endif |
---|
| 551 | m->m_len = m->m_pkthdr.len = |
---|
| 552 | len - sizeof (struct ether_header); |
---|
| 553 | |
---|
| 554 | eh = mtod (m, struct ether_header *); |
---|
| 555 | m->m_data += sizeof (struct ether_header); |
---|
[81d914d8] | 556 | #ifdef CPU_U32_FIX |
---|
[050249d] | 557 | if(!(dp->gbit_mac)) |
---|
| 558 | ipalign(m); /* Align packet on 32-bit boundary */ |
---|
[81d914d8] | 559 | #endif |
---|
[050249d] | 560 | |
---|
| 561 | ether_input (ifp, eh, m); |
---|
| 562 | MGETHDR (m, M_WAIT, MT_DATA); |
---|
| 563 | MCLGET (m, M_WAIT); |
---|
| 564 | if (dp->gbit_mac) |
---|
| 565 | m->m_data += 2; |
---|
| 566 | dp->rxmbuf[dp->rx_ptr] = m; |
---|
| 567 | m->m_pkthdr.rcvif = ifp; |
---|
| 568 | dp->rxdesc[dp->rx_ptr].addr = |
---|
| 569 | (uint32_t *) mtod (m, uint32_t *); |
---|
| 570 | dp->rxPackets++; |
---|
| 571 | } |
---|
| 572 | if (dp->rx_ptr == dp->rxbufs - 1) { |
---|
| 573 | dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ | GRETH_RXD_WRAP; |
---|
| 574 | } else { |
---|
| 575 | dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ; |
---|
| 576 | } |
---|
| 577 | dp->regs->ctrl |= GRETH_CTRL_RXEN; |
---|
| 578 | dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs; |
---|
[81d914d8] | 579 | } |
---|
| 580 | } |
---|
[3495c57] | 581 | |
---|
[81d914d8] | 582 | } |
---|
| 583 | |
---|
| 584 | static int inside = 0; |
---|
| 585 | static void |
---|
| 586 | sendpacket (struct ifnet *ifp, struct mbuf *m) |
---|
| 587 | { |
---|
| 588 | struct greth_softc *dp = ifp->if_softc; |
---|
| 589 | unsigned char *temp; |
---|
| 590 | struct mbuf *n; |
---|
| 591 | unsigned int len; |
---|
[3495c57] | 592 | |
---|
[81d914d8] | 593 | /*printf("Send packet entered\n");*/ |
---|
| 594 | if (inside) printf ("error: sendpacket re-entered!!\n"); |
---|
| 595 | inside = 1; |
---|
| 596 | /* |
---|
| 597 | * Waiting for Transmitter ready |
---|
| 598 | */ |
---|
| 599 | n = m; |
---|
| 600 | |
---|
| 601 | while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE) |
---|
| 602 | { |
---|
| 603 | #ifdef GRETH_SUSPEND_NOTXBUF |
---|
| 604 | dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ; |
---|
| 605 | rtems_event_set events; |
---|
| 606 | rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT, |
---|
| 607 | RTEMS_WAIT | RTEMS_EVENT_ANY, |
---|
| 608 | TOD_MILLISECONDS_TO_TICKS(500), &events); |
---|
| 609 | #endif |
---|
| 610 | } |
---|
| 611 | |
---|
| 612 | len = 0; |
---|
| 613 | temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr; |
---|
| 614 | #ifdef GRETH_DEBUG |
---|
[050249d] | 615 | printf("TXD: 0x%08x : BUF: 0x%08x\n", (int) m->m_data, (int) temp); |
---|
[81d914d8] | 616 | #endif |
---|
| 617 | for (;;) |
---|
[050249d] | 618 | { |
---|
[81d914d8] | 619 | #ifdef GRETH_DEBUG |
---|
[050249d] | 620 | int i; |
---|
| 621 | printf("MBUF: 0x%08x : ", (int) m->m_data); |
---|
| 622 | for (i=0;i<m->m_len;i++) |
---|
| 623 | printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff); |
---|
| 624 | printf("\n"); |
---|
[81d914d8] | 625 | #endif |
---|
[050249d] | 626 | len += m->m_len; |
---|
| 627 | if (len <= RBUF_SIZE) |
---|
| 628 | memcpy ((void *) temp, (char *) m->m_data, m->m_len); |
---|
| 629 | temp += m->m_len; |
---|
| 630 | if ((m = m->m_next) == NULL) |
---|
| 631 | break; |
---|
| 632 | } |
---|
[3495c57] | 633 | |
---|
[81d914d8] | 634 | m_freem (n); |
---|
[3495c57] | 635 | |
---|
[81d914d8] | 636 | /* don't send long packets */ |
---|
| 637 | |
---|
| 638 | if (len <= GRETH_MAXBUF_LEN) { |
---|
[050249d] | 639 | if (dp->tx_ptr < dp->txbufs-1) { |
---|
| 640 | dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | len; |
---|
| 641 | } else { |
---|
[3495c57] | 642 | dp->txdesc[dp->tx_ptr].ctrl = |
---|
[050249d] | 643 | GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len; |
---|
| 644 | } |
---|
| 645 | dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN; |
---|
| 646 | dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs; |
---|
[81d914d8] | 647 | } |
---|
| 648 | inside = 0; |
---|
| 649 | } |
---|
| 650 | |
---|
[050249d] | 651 | |
---|
| 652 | static void |
---|
| 653 | sendpacket_gbit (struct ifnet *ifp, struct mbuf *m) |
---|
| 654 | { |
---|
| 655 | struct greth_softc *dp = ifp->if_softc; |
---|
| 656 | unsigned int len; |
---|
| 657 | |
---|
| 658 | /*printf("Send packet entered\n");*/ |
---|
| 659 | if (inside) printf ("error: sendpacket re-entered!!\n"); |
---|
| 660 | inside = 1; |
---|
| 661 | /* |
---|
| 662 | * Waiting for Transmitter ready |
---|
| 663 | */ |
---|
[3495c57] | 664 | |
---|
[050249d] | 665 | len = 0; |
---|
| 666 | #ifdef GRETH_DEBUG |
---|
| 667 | printf("TXD: 0x%08x\n", (int) m->m_data); |
---|
| 668 | #endif |
---|
| 669 | for (;;) |
---|
| 670 | { |
---|
| 671 | while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE) |
---|
| 672 | { |
---|
| 673 | #ifdef GRETH_SUSPEND_NOTXBUF |
---|
| 674 | dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ; |
---|
| 675 | rtems_event_set events; |
---|
| 676 | rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT, |
---|
| 677 | RTEMS_WAIT | RTEMS_EVENT_ANY, |
---|
| 678 | TOD_MILLISECONDS_TO_TICKS(500), &events); |
---|
| 679 | #endif |
---|
| 680 | } |
---|
| 681 | #ifdef GRETH_DEBUG |
---|
| 682 | int i; |
---|
| 683 | printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len); |
---|
| 684 | for (i=0; i<m->m_len; i++) |
---|
| 685 | printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff); |
---|
| 686 | printf("\n"); |
---|
| 687 | #endif |
---|
| 688 | len += m->m_len; |
---|
| 689 | dp->txdesc[dp->tx_ptr].addr = (uint32_t *)m->m_data; |
---|
| 690 | if (dp->tx_ptr < dp->txbufs-1) { |
---|
| 691 | if ((m->m_next) == NULL) { |
---|
| 692 | dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len; |
---|
[3495c57] | 693 | break; |
---|
[050249d] | 694 | } else { |
---|
| 695 | dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len; |
---|
| 696 | } |
---|
| 697 | } else { |
---|
| 698 | if ((m->m_next) == NULL) { |
---|
[3495c57] | 699 | dp->txdesc[dp->tx_ptr].ctrl = |
---|
[050249d] | 700 | GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len; |
---|
| 701 | break; |
---|
| 702 | } else { |
---|
[3495c57] | 703 | dp->txdesc[dp->tx_ptr].ctrl = |
---|
[050249d] | 704 | GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len; |
---|
| 705 | } |
---|
| 706 | } |
---|
| 707 | dp->txmbuf[dp->tx_ptr] = m; |
---|
| 708 | dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs; |
---|
| 709 | dp->tx_cnt++; |
---|
| 710 | m = m->m_next; |
---|
[3495c57] | 711 | |
---|
[050249d] | 712 | } |
---|
| 713 | dp->txmbuf[dp->tx_ptr] = m; |
---|
| 714 | dp->tx_cnt++; |
---|
| 715 | dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN; |
---|
| 716 | dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs; |
---|
| 717 | inside = 0; |
---|
| 718 | } |
---|
| 719 | |
---|
[81d914d8] | 720 | /* |
---|
| 721 | * Driver transmit daemon |
---|
| 722 | */ |
---|
| 723 | void |
---|
| 724 | greth_txDaemon (void *arg) |
---|
| 725 | { |
---|
| 726 | struct greth_softc *sc = (struct greth_softc *) arg; |
---|
| 727 | struct ifnet *ifp = &sc->arpcom.ac_if; |
---|
| 728 | struct mbuf *m; |
---|
| 729 | rtems_event_set events; |
---|
[3495c57] | 730 | |
---|
[81d914d8] | 731 | for (;;) |
---|
[050249d] | 732 | { |
---|
| 733 | /* |
---|
| 734 | * Wait for packet |
---|
| 735 | */ |
---|
[3495c57] | 736 | |
---|
[050249d] | 737 | rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, |
---|
| 738 | RTEMS_EVENT_ANY | RTEMS_WAIT, |
---|
| 739 | RTEMS_NO_TIMEOUT, &events); |
---|
[81d914d8] | 740 | #ifdef GRETH_DEBUG |
---|
[050249d] | 741 | printf ("t\n"); |
---|
[81d914d8] | 742 | #endif |
---|
[3495c57] | 743 | |
---|
[050249d] | 744 | /* |
---|
| 745 | * Send packets till queue is empty |
---|
| 746 | */ |
---|
[3495c57] | 747 | |
---|
| 748 | |
---|
[050249d] | 749 | for (;;) |
---|
| 750 | { |
---|
| 751 | /* |
---|
| 752 | * Get the next mbuf chain to transmit. |
---|
| 753 | */ |
---|
| 754 | IF_DEQUEUE (&ifp->if_snd, m); |
---|
| 755 | if (!m) |
---|
| 756 | break; |
---|
| 757 | sendpacket(ifp, m); |
---|
| 758 | } |
---|
| 759 | ifp->if_flags &= ~IFF_OACTIVE; |
---|
| 760 | } |
---|
| 761 | } |
---|
[81d914d8] | 762 | |
---|
[050249d] | 763 | /* |
---|
| 764 | * Driver transmit daemon |
---|
| 765 | */ |
---|
| 766 | void |
---|
| 767 | greth_txDaemon_gbit (void *arg) |
---|
| 768 | { |
---|
| 769 | struct greth_softc *sc = (struct greth_softc *) arg; |
---|
| 770 | struct ifnet *ifp = &sc->arpcom.ac_if; |
---|
| 771 | struct mbuf *m; |
---|
| 772 | rtems_event_set events; |
---|
[3495c57] | 773 | |
---|
[050249d] | 774 | for (;;) |
---|
| 775 | { |
---|
| 776 | /* |
---|
| 777 | * Wait for packet |
---|
| 778 | */ |
---|
[3495c57] | 779 | |
---|
[050249d] | 780 | rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, |
---|
| 781 | RTEMS_EVENT_ANY | RTEMS_WAIT, |
---|
| 782 | RTEMS_NO_TIMEOUT, &events); |
---|
| 783 | #ifdef GRETH_DEBUG |
---|
| 784 | printf ("t\n"); |
---|
| 785 | #endif |
---|
[3495c57] | 786 | |
---|
[050249d] | 787 | /* |
---|
| 788 | * Send packets till queue is empty |
---|
| 789 | */ |
---|
| 790 | for (;;) |
---|
[81d914d8] | 791 | { |
---|
[050249d] | 792 | while((sc->tx_cnt > 0) && !(sc->txdesc[sc->tx_dptr].ctrl & GRETH_TXD_ENABLE)) { |
---|
| 793 | m_free(sc->txmbuf[sc->tx_dptr]); |
---|
| 794 | sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs; |
---|
| 795 | sc->tx_cnt--; |
---|
| 796 | } |
---|
| 797 | /* |
---|
| 798 | * Get the next mbuf chain to transmit. |
---|
| 799 | */ |
---|
| 800 | IF_DEQUEUE (&ifp->if_snd, m); |
---|
| 801 | if (!m) |
---|
| 802 | break; |
---|
| 803 | sendpacket_gbit(ifp, m); |
---|
| 804 | } |
---|
| 805 | ifp->if_flags &= ~IFF_OACTIVE; |
---|
| 806 | } |
---|
[81d914d8] | 807 | } |
---|
| 808 | |
---|
| 809 | |
---|
| 810 | static void |
---|
| 811 | greth_start (struct ifnet *ifp) |
---|
| 812 | { |
---|
| 813 | struct greth_softc *sc = ifp->if_softc; |
---|
[3495c57] | 814 | |
---|
[81d914d8] | 815 | ifp->if_flags |= IFF_OACTIVE; |
---|
| 816 | rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); |
---|
[3495c57] | 817 | |
---|
[81d914d8] | 818 | } |
---|
| 819 | |
---|
| 820 | /* |
---|
| 821 | * Initialize and start the device |
---|
| 822 | */ |
---|
| 823 | static void |
---|
| 824 | greth_init (void *arg) |
---|
| 825 | { |
---|
| 826 | struct greth_softc *sc = arg; |
---|
| 827 | struct ifnet *ifp = &sc->arpcom.ac_if; |
---|
| 828 | |
---|
| 829 | if (sc->txDaemonTid == 0) |
---|
| 830 | { |
---|
| 831 | |
---|
| 832 | /* |
---|
| 833 | * Set up GRETH hardware |
---|
| 834 | */ |
---|
| 835 | greth_initialize_hardware (sc); |
---|
| 836 | |
---|
| 837 | /* |
---|
| 838 | * Start driver tasks |
---|
| 839 | */ |
---|
| 840 | sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096, |
---|
| 841 | greth_rxDaemon, sc); |
---|
[050249d] | 842 | if (sc->gbit_mac) { |
---|
| 843 | sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096, |
---|
| 844 | greth_txDaemon_gbit, sc); |
---|
| 845 | } else { |
---|
| 846 | sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096, |
---|
| 847 | greth_txDaemon, sc); |
---|
| 848 | } |
---|
[3495c57] | 849 | |
---|
[81d914d8] | 850 | } |
---|
| 851 | |
---|
| 852 | /* |
---|
| 853 | * Tell the world that we're running. |
---|
| 854 | */ |
---|
| 855 | ifp->if_flags |= IFF_RUNNING; |
---|
| 856 | |
---|
| 857 | } |
---|
| 858 | |
---|
| 859 | /* |
---|
| 860 | * Stop the device |
---|
| 861 | */ |
---|
| 862 | static void |
---|
| 863 | greth_stop (struct greth_softc *sc) |
---|
| 864 | { |
---|
| 865 | struct ifnet *ifp = &sc->arpcom.ac_if; |
---|
| 866 | |
---|
| 867 | ifp->if_flags &= ~IFF_RUNNING; |
---|
| 868 | |
---|
| 869 | sc->regs->ctrl = 0; /* RX/TX OFF */ |
---|
| 870 | sc->regs->ctrl = GRETH_CTRL_RST; /* Reset ON */ |
---|
| 871 | sc->regs->ctrl = 0; /* Reset OFF */ |
---|
| 872 | } |
---|
| 873 | |
---|
| 874 | |
---|
| 875 | /* |
---|
| 876 | * Show interface statistics |
---|
| 877 | */ |
---|
| 878 | static void |
---|
| 879 | greth_stats (struct greth_softc *sc) |
---|
| 880 | { |
---|
| 881 | printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); |
---|
| 882 | printf (" Rx Packets:%-8lu", sc->rxPackets); |
---|
| 883 | printf (" Length:%-8lu", sc->rxLengthError); |
---|
| 884 | printf (" Non-octet:%-8lu\n", sc->rxNonOctet); |
---|
| 885 | printf (" Bad CRC:%-8lu", sc->rxBadCRC); |
---|
| 886 | printf (" Overrun:%-8lu", sc->rxOverrun); |
---|
| 887 | printf (" Tx Interrupts:%-8lu", sc->txInterrupts); |
---|
| 888 | } |
---|
| 889 | |
---|
| 890 | /* |
---|
| 891 | * Driver ioctl handler |
---|
| 892 | */ |
---|
| 893 | static int |
---|
[a612b50] | 894 | greth_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data) |
---|
[81d914d8] | 895 | { |
---|
| 896 | struct greth_softc *sc = ifp->if_softc; |
---|
| 897 | int error = 0; |
---|
| 898 | |
---|
| 899 | switch (command) |
---|
| 900 | { |
---|
| 901 | case SIOCGIFADDR: |
---|
| 902 | case SIOCSIFADDR: |
---|
| 903 | ether_ioctl (ifp, command, data); |
---|
| 904 | break; |
---|
| 905 | |
---|
| 906 | case SIOCSIFFLAGS: |
---|
| 907 | switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) |
---|
| 908 | { |
---|
| 909 | case IFF_RUNNING: |
---|
| 910 | greth_stop (sc); |
---|
| 911 | break; |
---|
| 912 | |
---|
| 913 | case IFF_UP: |
---|
| 914 | greth_init (sc); |
---|
| 915 | break; |
---|
| 916 | |
---|
| 917 | case IFF_UP | IFF_RUNNING: |
---|
| 918 | greth_stop (sc); |
---|
| 919 | greth_init (sc); |
---|
| 920 | break; |
---|
| 921 | default: |
---|
| 922 | break; |
---|
| 923 | } |
---|
| 924 | break; |
---|
| 925 | |
---|
| 926 | case SIO_RTEMS_SHOW_STATS: |
---|
| 927 | greth_stats (sc); |
---|
| 928 | break; |
---|
| 929 | |
---|
| 930 | /* |
---|
| 931 | * FIXME: All sorts of multicast commands need to be added here! |
---|
| 932 | */ |
---|
| 933 | default: |
---|
| 934 | error = EINVAL; |
---|
| 935 | break; |
---|
| 936 | } |
---|
| 937 | |
---|
| 938 | return error; |
---|
| 939 | } |
---|
| 940 | |
---|
| 941 | /* |
---|
| 942 | * Attach an GRETH driver to the system |
---|
| 943 | */ |
---|
| 944 | int |
---|
| 945 | rtems_greth_driver_attach (struct rtems_bsdnet_ifconfig *config, |
---|
| 946 | greth_configuration_t *chip) |
---|
| 947 | { |
---|
| 948 | struct greth_softc *sc; |
---|
| 949 | struct ifnet *ifp; |
---|
| 950 | int mtu; |
---|
| 951 | int unitNumber; |
---|
| 952 | char *unitName; |
---|
| 953 | |
---|
| 954 | /* parse driver name */ |
---|
| 955 | if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0) |
---|
| 956 | return 0; |
---|
| 957 | |
---|
| 958 | sc = &greth; |
---|
| 959 | ifp = &sc->arpcom.ac_if; |
---|
| 960 | memset (sc, 0, sizeof (*sc)); |
---|
| 961 | |
---|
| 962 | if (config->hardware_address) |
---|
| 963 | { |
---|
| 964 | memcpy (sc->arpcom.ac_enaddr, config->hardware_address, |
---|
| 965 | ETHER_ADDR_LEN); |
---|
| 966 | } |
---|
| 967 | else |
---|
| 968 | { |
---|
| 969 | memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN); |
---|
| 970 | } |
---|
| 971 | |
---|
| 972 | if (config->mtu) |
---|
| 973 | mtu = config->mtu; |
---|
| 974 | else |
---|
| 975 | mtu = ETHERMTU; |
---|
| 976 | |
---|
| 977 | sc->acceptBroadcast = !config->ignore_broadcast; |
---|
| 978 | sc->regs = (void *) chip->base_address; |
---|
| 979 | sc->vector = chip->vector; |
---|
| 980 | sc->txbufs = chip->txd_count; |
---|
| 981 | sc->rxbufs = chip->rxd_count; |
---|
[3495c57] | 982 | |
---|
[81d914d8] | 983 | /* |
---|
| 984 | * Set up network interface values |
---|
| 985 | */ |
---|
| 986 | ifp->if_softc = sc; |
---|
| 987 | ifp->if_unit = unitNumber; |
---|
| 988 | ifp->if_name = unitName; |
---|
| 989 | ifp->if_mtu = mtu; |
---|
| 990 | ifp->if_init = greth_init; |
---|
| 991 | ifp->if_ioctl = greth_ioctl; |
---|
| 992 | ifp->if_start = greth_start; |
---|
| 993 | ifp->if_output = ether_output; |
---|
| 994 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; |
---|
| 995 | if (ifp->if_snd.ifq_maxlen == 0) |
---|
| 996 | ifp->if_snd.ifq_maxlen = ifqmaxlen; |
---|
| 997 | |
---|
| 998 | /* |
---|
| 999 | * Attach the interface |
---|
| 1000 | */ |
---|
| 1001 | if_attach (ifp); |
---|
| 1002 | ether_ifattach (ifp); |
---|
| 1003 | |
---|
| 1004 | #ifdef GRETH_DEBUG |
---|
| 1005 | printf ("GRETH : driver has been attached\n"); |
---|
| 1006 | #endif |
---|
| 1007 | return 1; |
---|
| 1008 | }; |
---|
| 1009 | |
---|