[c932d85] | 1 | /* |
---|
| 2 | ******************************************************************* |
---|
| 3 | ******************************************************************* |
---|
| 4 | ** ** |
---|
| 5 | ** RTEMS/KA9Q DRIVER FOR NATIONAL DP83932 `SONIC' ** |
---|
| 6 | ** SYSTEMS-ORIENTED NETWORK INTERFACE CONTROLLER ** |
---|
| 7 | ** ** |
---|
| 8 | ******************************************************************* |
---|
| 9 | ******************************************************************* |
---|
| 10 | */ |
---|
| 11 | |
---|
| 12 | /* |
---|
| 13 | * $Revision$ $Date$ $Author$ |
---|
| 14 | * $State$ |
---|
| 15 | */ |
---|
| 16 | |
---|
| 17 | /* |
---|
| 18 | * References: |
---|
| 19 | * 1) DP83932C-20/25/33 MHz SONIC(TM) Systems-Oriented Network Interface |
---|
| 20 | * Controller data sheet. TL/F/10492, RRD-B30M105, National Semiconductor, |
---|
| 21 | * 1995. |
---|
| 22 | * |
---|
| 23 | * 2) Software Driver Programmer's Guide for the DP83932 SONIC(TM), |
---|
| 24 | * Application Note 746, Wesley Lee and Mike Lui, TL/F/11140, |
---|
| 25 | * RRD-B30M75, National Semiconductor, March, 1991. |
---|
| 26 | * |
---|
| 27 | * 3) SVME/DMV-171 Single Board Computer Documentation Package, #805905, |
---|
| 28 | * DY 4 Systems Inc., Kanata, Ontario, September, 1996. |
---|
| 29 | */ |
---|
| 30 | #include "sonic.h" |
---|
| 31 | |
---|
| 32 | #include <rtems/error.h> |
---|
| 33 | #include <ka9q/rtems_ka9q.h> |
---|
| 34 | #include <ka9q/global.h> |
---|
| 35 | #include <ka9q/domain.h> |
---|
| 36 | #include <ka9q/enet.h> |
---|
| 37 | #include <ka9q/iface.h> |
---|
| 38 | #include <ka9q/netuser.h> |
---|
| 39 | #include <ka9q/trace.h> |
---|
| 40 | #include <ka9q/commands.h> |
---|
| 41 | |
---|
[fa655207] | 42 | /* |
---|
| 43 | * XXX |
---|
| 44 | */ |
---|
| 45 | |
---|
| 46 | #include <dmv170.h> |
---|
| 47 | |
---|
[c932d85] | 48 | /* |
---|
| 49 | * Number of devices supported by this driver |
---|
| 50 | */ |
---|
| 51 | #ifndef NSONIC |
---|
| 52 | # define NSONIC 1 |
---|
| 53 | #endif |
---|
| 54 | |
---|
| 55 | /* |
---|
| 56 | * Default location of device registers |
---|
| 57 | */ |
---|
| 58 | #ifndef SONIC_BASE_ADDRESS |
---|
| 59 | # define SONIC_BASE_ADDRESS 0xF3000000 |
---|
| 60 | # warning "Using default SONIC_BASE_ADDRESS." |
---|
| 61 | #endif |
---|
| 62 | |
---|
| 63 | /* |
---|
| 64 | * Default interrupt vector |
---|
| 65 | */ |
---|
| 66 | #ifndef SONIC_VECTOR |
---|
| 67 | # define SONIC_VECTOR 1 |
---|
| 68 | # warning "Using default SONIC_VECTOR." |
---|
| 69 | #endif |
---|
| 70 | |
---|
| 71 | /* |
---|
| 72 | * Default device configuration register values |
---|
| 73 | * Conservative, generic values. |
---|
| 74 | * DCR: |
---|
| 75 | * No extended bus mode |
---|
| 76 | * Unlatched bus retry |
---|
| 77 | * Programmable outputs unused |
---|
| 78 | * Asynchronous bus mode |
---|
| 79 | * User definable pins unused |
---|
| 80 | * No wait states (access time controlled by DTACK*) |
---|
| 81 | * 32-bit DMA |
---|
| 82 | * Empty/Fill DMA mode |
---|
| 83 | * Maximum Transmit/Receive FIFO |
---|
| 84 | * DC2: |
---|
| 85 | * Extended programmable outputs unused |
---|
| 86 | * Normal HOLD request |
---|
| 87 | * Packet compress output unused |
---|
| 88 | * No reject on CAM match |
---|
| 89 | */ |
---|
| 90 | #ifndef SONIC_DCR |
---|
| 91 | # define SONIC_DCR (DCR_DW | DCR_TFT1 | DCR_TFT0) |
---|
| 92 | #endif |
---|
| 93 | #ifndef SONIC_DC2 |
---|
| 94 | # define SONIC_DC2 (0) |
---|
| 95 | #endif |
---|
| 96 | |
---|
| 97 | /* |
---|
| 98 | * Default sizes of transmit and receive descriptor areas |
---|
| 99 | */ |
---|
| 100 | #define RDA_COUNT 20 |
---|
| 101 | #define TDA_COUNT 10 |
---|
| 102 | |
---|
| 103 | /* |
---|
| 104 | * |
---|
| 105 | * As suggested by National Application Note 746, make the |
---|
| 106 | * receive resource area bigger than the receive descriptor area. |
---|
| 107 | */ |
---|
| 108 | #define RRA_EXTRA_COUNT 3 |
---|
| 109 | |
---|
| 110 | /* |
---|
| 111 | * RTEMS event used by interrupt handler to signal daemons. |
---|
| 112 | */ |
---|
| 113 | #define INTERRUPT_EVENT RTEMS_EVENT_1 |
---|
| 114 | |
---|
| 115 | /* |
---|
| 116 | * Largest Ethernet frame. |
---|
| 117 | */ |
---|
| 118 | #define MAXIMUM_FRAME_SIZE 1518 |
---|
| 119 | |
---|
| 120 | /* |
---|
| 121 | * Receive buffer size. |
---|
| 122 | * Allow for a pointer, plus a full ethernet frame (including Frame |
---|
| 123 | * Check Sequence) rounded up to a 4-byte boundary. |
---|
| 124 | */ |
---|
| 125 | #define RBUF_SIZE ((sizeof (void *) + (MAXIMUM_FRAME_SIZE) + 3) & ~3) |
---|
| 126 | #define RBUF_WC ((((MAXIMUM_FRAME_SIZE) + 3) & ~3) / 2) |
---|
| 127 | |
---|
| 128 | /* |
---|
| 129 | * Macros for manipulating 32-bit pointers as 16-bit fragments |
---|
| 130 | */ |
---|
| 131 | #define LSW(p) ((rtems_unsigned16)((rtems_unsigned32)(p))) |
---|
| 132 | #define MSW(p) ((rtems_unsigned16)((rtems_unsigned32)(p) >> 16)) |
---|
| 133 | #define PTR(m,l) ((void*)(((rtems_unsigned16)(m)<<16)|(rtems_unsigned16)(l))) |
---|
| 134 | |
---|
| 135 | /* |
---|
| 136 | * Hardware-specific storage |
---|
| 137 | */ |
---|
| 138 | struct sonic { |
---|
| 139 | /* |
---|
| 140 | * Connection to KA9Q |
---|
| 141 | */ |
---|
| 142 | struct iface *iface; |
---|
| 143 | |
---|
| 144 | /* |
---|
| 145 | * Default location of device registers |
---|
| 146 | * ===CACHE=== |
---|
| 147 | * This area must be non-cacheable, guarded. |
---|
| 148 | */ |
---|
| 149 | volatile struct SonicRegisters *sonic; |
---|
| 150 | |
---|
| 151 | /* |
---|
| 152 | * Interrupt vector |
---|
| 153 | */ |
---|
| 154 | rtems_vector_number vector; |
---|
| 155 | |
---|
| 156 | /* |
---|
| 157 | * Task waiting for transmit resources |
---|
| 158 | */ |
---|
| 159 | rtems_id txWaitTid; |
---|
| 160 | |
---|
| 161 | /* |
---|
| 162 | * Receive resource area |
---|
| 163 | */ |
---|
| 164 | int rdaCount; |
---|
| 165 | ReceiveResourcePointer_t rsa; |
---|
| 166 | |
---|
| 167 | /* |
---|
| 168 | * Transmit descriptors |
---|
| 169 | */ |
---|
| 170 | int tdaCount; |
---|
| 171 | TransmitDescriptorPointer_t tdaHead; /* Last filled */ |
---|
| 172 | TransmitDescriptorPointer_t tdaTail; /* Next to retire */ |
---|
| 173 | int tdaActiveCount; |
---|
| 174 | |
---|
| 175 | /* |
---|
| 176 | * Statistics |
---|
| 177 | */ |
---|
| 178 | unsigned long rxInterrupts; |
---|
| 179 | unsigned long rxMissed; |
---|
| 180 | unsigned long rxGiant; |
---|
| 181 | unsigned long rxNonOctet; |
---|
| 182 | unsigned long rxBadCRC; |
---|
| 183 | unsigned long rxCollision; |
---|
| 184 | |
---|
| 185 | unsigned long txInterrupts; |
---|
| 186 | unsigned long txSingleCollision; |
---|
| 187 | unsigned long txMultipleCollision; |
---|
| 188 | unsigned long txCollision; |
---|
| 189 | unsigned long txDeferred; |
---|
| 190 | unsigned long txUnderrun; |
---|
| 191 | unsigned long txLateCollision; |
---|
| 192 | unsigned long txExcessiveCollision; |
---|
| 193 | unsigned long txExcessiveDeferral; |
---|
| 194 | unsigned long txLostCarrier; |
---|
| 195 | unsigned long txRawWait; |
---|
| 196 | }; |
---|
| 197 | static struct sonic sonic[NSONIC]; |
---|
| 198 | |
---|
| 199 | /* |
---|
| 200 | ****************************************************************** |
---|
| 201 | * * |
---|
| 202 | * Support Routines * |
---|
| 203 | * * |
---|
| 204 | ****************************************************************** |
---|
| 205 | */ |
---|
| 206 | |
---|
| 207 | /* |
---|
| 208 | * Allocate non-cacheable memory on a single 64k page. |
---|
| 209 | * Very simple minded -- just keeps trying till the memory is on a single page. |
---|
| 210 | */ |
---|
| 211 | static void * |
---|
| 212 | sonic_allocate (unsigned int nbytes) |
---|
| 213 | { |
---|
| 214 | void *p; |
---|
| 215 | unsigned long a1, a2; |
---|
| 216 | |
---|
| 217 | for (;;) { |
---|
| 218 | /* |
---|
| 219 | * ===CACHE=== |
---|
| 220 | * Change malloc to malloc_noncacheable_guarded. |
---|
| 221 | */ |
---|
| 222 | p = malloc (nbytes); |
---|
| 223 | if (p == NULL) |
---|
| 224 | rtems_panic ("No memory!"); |
---|
| 225 | a1 = (unsigned long)p; |
---|
| 226 | a2 = a1 + nbytes - 1; |
---|
| 227 | if ((a1 >> 16) == (a2 >> 16)) |
---|
| 228 | break; |
---|
| 229 | } |
---|
| 230 | return p; |
---|
| 231 | } |
---|
| 232 | |
---|
| 233 | /* |
---|
| 234 | * Shut down the interface. |
---|
| 235 | * This is a pretty simple-minded routine. It doesn't worry |
---|
| 236 | * about cleaning up mbufs, shutting down daemons, etc. |
---|
| 237 | */ |
---|
| 238 | static int |
---|
| 239 | sonic_stop (struct iface *iface) |
---|
| 240 | { |
---|
| 241 | int i; |
---|
| 242 | struct sonic *dp = &sonic[iface->dev]; |
---|
| 243 | volatile struct SonicRegisters *rp = dp->sonic; |
---|
| 244 | |
---|
| 245 | /* |
---|
| 246 | * Stop the transmitter and receiver. |
---|
| 247 | */ |
---|
| 248 | rp->cr = CR_HTX | CR_RXDIS; |
---|
| 249 | |
---|
| 250 | /* |
---|
| 251 | * Wait for things to stop. |
---|
| 252 | * For safety's sake, there is an alternate exit. |
---|
| 253 | */ |
---|
| 254 | i = 0; |
---|
| 255 | while (rp->cr & (CR_RXEN | CR_TXP)) { |
---|
| 256 | if (++i == 10000) |
---|
| 257 | break; |
---|
| 258 | } |
---|
| 259 | |
---|
| 260 | /* |
---|
| 261 | * Reset the device |
---|
| 262 | */ |
---|
| 263 | rp->cr = CR_RST; |
---|
| 264 | rp->imr = 0; |
---|
| 265 | return 0; |
---|
| 266 | } |
---|
| 267 | |
---|
| 268 | /* |
---|
| 269 | * Show interface statistics |
---|
| 270 | */ |
---|
| 271 | static void |
---|
| 272 | sonic_show (struct iface *iface) |
---|
| 273 | { |
---|
| 274 | struct sonic *dp = &sonic[iface->dev]; |
---|
| 275 | |
---|
| 276 | printf (" Rx Interrupts:%-8lu", dp->rxInterrupts); |
---|
| 277 | printf (" Giant:%-8lu", dp->rxGiant); |
---|
| 278 | printf (" Non-octet:%-8lu\n", dp->rxNonOctet); |
---|
| 279 | printf (" Bad CRC:%-8lu", dp->rxBadCRC); |
---|
| 280 | printf (" Collision:%-8lu", dp->rxCollision); |
---|
| 281 | printf (" Missed:%-8lu\n", dp->rxMissed); |
---|
| 282 | |
---|
| 283 | printf ( " Tx Interrupts:%-8lu", dp->txInterrupts); |
---|
| 284 | printf ( " Deferred:%-8lu", dp->txDeferred); |
---|
| 285 | printf (" Lost Carrier:%-8lu\n", dp->txLostCarrier); |
---|
| 286 | printf ( "Single Collisions:%-8lu", dp->txSingleCollision); |
---|
| 287 | printf ( "Multiple Collisions:%-8lu", dp->txMultipleCollision); |
---|
| 288 | printf ("Excessive Collisions:%-8lu\n", dp->txExcessiveCollision); |
---|
| 289 | printf ( " Total Collisions:%-8lu", dp->txCollision); |
---|
| 290 | printf ( " Late Collision:%-8lu", dp->txLateCollision); |
---|
| 291 | printf (" Underrun:%-8lu\n", dp->txUnderrun); |
---|
| 292 | printf ( " Raw output wait:%-8lu\n", dp->txRawWait); |
---|
| 293 | } |
---|
| 294 | |
---|
| 295 | /* |
---|
| 296 | ****************************************************************** |
---|
| 297 | * * |
---|
| 298 | * Interrupt Handler * |
---|
| 299 | * * |
---|
| 300 | ****************************************************************** |
---|
| 301 | */ |
---|
| 302 | static rtems_isr |
---|
| 303 | sonic_interrupt_handler (rtems_vector_number v) |
---|
| 304 | { |
---|
| 305 | struct sonic *dp = sonic; |
---|
| 306 | volatile struct SonicRegisters *rp; |
---|
| 307 | |
---|
| 308 | #if (NSONIC > 1) |
---|
| 309 | /* |
---|
| 310 | * Find the device which requires service |
---|
| 311 | */ |
---|
| 312 | for (;;) { |
---|
| 313 | if (dp->vector == v) |
---|
| 314 | break; |
---|
| 315 | if (++dp == &sonic[NSONIC]) |
---|
| 316 | return; /* Spurious interrupt? */ |
---|
| 317 | } |
---|
| 318 | #endif /* NSONIC > 1 */ |
---|
| 319 | |
---|
| 320 | /* |
---|
| 321 | * Get pointer to SONIC registers |
---|
| 322 | */ |
---|
| 323 | rp = dp->sonic; |
---|
| 324 | |
---|
| 325 | /* |
---|
| 326 | * Packet received or receive buffer area exceeded? |
---|
| 327 | */ |
---|
| 328 | if ((rp->imr & (IMR_PRXEN | IMR_RBAEEN)) |
---|
| 329 | && (rp->isr & (ISR_PKTRX | ISR_RBAE))) { |
---|
| 330 | rp->imr &= ~(IMR_PRXEN | IMR_RBAEEN); |
---|
| 331 | dp->rxInterrupts++; |
---|
| 332 | rtems_event_send (dp->iface->rxproc, INTERRUPT_EVENT); |
---|
| 333 | } |
---|
| 334 | |
---|
| 335 | /* |
---|
| 336 | * Packet started, transmitter done or transmitter error? |
---|
| 337 | */ |
---|
| 338 | if ((rp->imr & (IMR_PINTEN | IMR_PTXEN | IMR_TXEREN)) |
---|
| 339 | && (rp->isr & (ISR_PINT | ISR_TXDN | ISR_TXER))) { |
---|
| 340 | rp->imr &= ~(IMR_PINTEN | IMR_PTXEN | IMR_TXEREN); |
---|
| 341 | dp->txInterrupts++; |
---|
| 342 | rtems_event_send (dp->txWaitTid, INTERRUPT_EVENT); |
---|
| 343 | } |
---|
| 344 | } |
---|
| 345 | |
---|
| 346 | /* |
---|
| 347 | ****************************************************************** |
---|
| 348 | * * |
---|
| 349 | * Transmitter Routines * |
---|
| 350 | * * |
---|
| 351 | ****************************************************************** |
---|
| 352 | */ |
---|
| 353 | |
---|
| 354 | /* |
---|
| 355 | * Soak up transmit descriptors that have been sent. |
---|
| 356 | */ |
---|
| 357 | static void |
---|
| 358 | sonic_retire_tda (struct sonic *dp) |
---|
| 359 | { |
---|
| 360 | rtems_unsigned16 status; |
---|
| 361 | unsigned int collisions; |
---|
| 362 | |
---|
| 363 | /* |
---|
| 364 | * Repeat for all completed transmit descriptors. |
---|
| 365 | */ |
---|
| 366 | while ((dp->tdaActiveCount != 0) |
---|
| 367 | && ((status = dp->tdaTail->status) != 0)) { |
---|
| 368 | /* |
---|
| 369 | * Check for errors which stop the transmitter. |
---|
| 370 | */ |
---|
| 371 | if (status & (TDA_STATUS_EXD | |
---|
| 372 | TDA_STATUS_EXC | |
---|
| 373 | TDA_STATUS_FU | |
---|
| 374 | TDA_STATUS_BCM)) { |
---|
| 375 | /* |
---|
| 376 | * Restart the transmitter if there are |
---|
| 377 | * packets waiting to go. |
---|
| 378 | */ |
---|
| 379 | rtems_unsigned16 link; |
---|
| 380 | link = *(dp->tdaTail->linkp); |
---|
| 381 | |
---|
| 382 | if ((link & TDA_LINK_EOL) == 0) { |
---|
| 383 | volatile struct SonicRegisters *rp = dp->sonic; |
---|
| 384 | |
---|
| 385 | rp->ctda = link; |
---|
| 386 | rp->cr = CR_TXP; |
---|
| 387 | } |
---|
| 388 | } |
---|
| 389 | |
---|
| 390 | /* |
---|
| 391 | * Update network statistics |
---|
| 392 | */ |
---|
| 393 | collisions = (status & TDA_STATUS_COLLISION_MASK) >> TDA_STATUS_COLLISION_SHIFT; |
---|
| 394 | if (collisions) { |
---|
| 395 | if (collisions == 1) |
---|
| 396 | dp->txSingleCollision++; |
---|
| 397 | else |
---|
| 398 | dp->txMultipleCollision++; |
---|
| 399 | dp->txCollision += collisions; |
---|
| 400 | } |
---|
| 401 | if (status & TDA_STATUS_EXC) |
---|
| 402 | dp->txExcessiveCollision++; |
---|
| 403 | if (status & TDA_STATUS_OWC) |
---|
| 404 | dp->txLateCollision++; |
---|
| 405 | if (status & TDA_STATUS_EXD) |
---|
| 406 | dp->txExcessiveDeferral++; |
---|
| 407 | if (status & TDA_STATUS_DEF) |
---|
| 408 | dp->txDeferred++; |
---|
| 409 | if (status & TDA_STATUS_FU) |
---|
| 410 | dp->txUnderrun++; |
---|
| 411 | if (status & TDA_STATUS_CRSL) |
---|
| 412 | dp->txLostCarrier++; |
---|
| 413 | |
---|
| 414 | /* |
---|
| 415 | * Free the packet |
---|
| 416 | */ |
---|
| 417 | dp->tdaActiveCount--; |
---|
| 418 | free_p ((struct mbuf **)&dp->tdaTail->mbufp); |
---|
| 419 | |
---|
| 420 | /* |
---|
| 421 | * Move to the next transmit descriptor |
---|
| 422 | */ |
---|
| 423 | dp->tdaTail = dp->tdaTail->next; |
---|
| 424 | } |
---|
| 425 | } |
---|
| 426 | |
---|
| 427 | /* |
---|
| 428 | * Send raw packet (caller provides header). |
---|
| 429 | * This code runs in the context of the interface transmit |
---|
| 430 | * task (most packets) or in the context of the network |
---|
| 431 | * task (for ARP requests). |
---|
| 432 | */ |
---|
| 433 | static int |
---|
| 434 | sonic_raw (struct iface *iface, struct mbuf **bpp) |
---|
| 435 | { |
---|
| 436 | struct sonic *dp = &sonic[iface->dev]; |
---|
| 437 | volatile struct SonicRegisters *rp = dp->sonic; |
---|
| 438 | struct mbuf *bp; |
---|
| 439 | TransmitDescriptorPointer_t tdp; |
---|
| 440 | volatile struct TransmitDescriptorFragLink *fp; |
---|
| 441 | unsigned int packetSize; |
---|
| 442 | int i; |
---|
| 443 | static char padBuf[64]; |
---|
| 444 | |
---|
| 445 | /* |
---|
| 446 | * Update the log. |
---|
| 447 | */ |
---|
| 448 | iface->rawsndcnt++; |
---|
| 449 | iface->lastsent = secclock (); |
---|
| 450 | dump (iface, IF_TRACE_OUT, *bpp); |
---|
| 451 | |
---|
| 452 | /* |
---|
| 453 | * It would not do to have two tasks active in the transmit |
---|
| 454 | * loop at the same time. |
---|
| 455 | * The blocking is simple-minded since the odds of two tasks |
---|
| 456 | * simultaneously attempting to use this code are low. The only |
---|
| 457 | * way that two tasks can try to run here is: |
---|
| 458 | * 1) Task A enters this code and ends up having to |
---|
| 459 | * wait for a transmit buffer descriptor. |
---|
| 460 | * 2) Task B gains control and tries to transmit a packet. |
---|
| 461 | * The RTEMS/KA9Q scheduling semaphore ensures that there |
---|
| 462 | * are no race conditions associated with manipulating the |
---|
| 463 | * txWaitTid variable. |
---|
| 464 | */ |
---|
| 465 | if (dp->txWaitTid) { |
---|
| 466 | dp->txRawWait++; |
---|
| 467 | while (dp->txWaitTid) |
---|
| 468 | rtems_ka9q_ppause (10); |
---|
| 469 | } |
---|
| 470 | |
---|
| 471 | /* |
---|
| 472 | * Free up transmit descriptors. |
---|
| 473 | */ |
---|
| 474 | sonic_retire_tda (dp); |
---|
| 475 | |
---|
| 476 | /* |
---|
| 477 | * Wait for transmit descriptor to become available. |
---|
| 478 | */ |
---|
| 479 | if (dp->tdaActiveCount == dp->tdaCount) { |
---|
| 480 | /* |
---|
| 481 | * Find out who we are |
---|
| 482 | */ |
---|
| 483 | if (dp->txWaitTid == 0) |
---|
| 484 | rtems_task_ident (RTEMS_SELF, 0, &dp->txWaitTid); |
---|
| 485 | |
---|
| 486 | /* |
---|
| 487 | * Clear old events. |
---|
| 488 | */ |
---|
| 489 | rp->isr = ISR_PINT | ISR_TXDN | ISR_TXER; |
---|
| 490 | |
---|
| 491 | /* |
---|
| 492 | * Wait for transmit descriptor to become available. |
---|
| 493 | * Note that the transmit descriptors are checked |
---|
| 494 | * *before* * entering the wait loop -- this catches |
---|
| 495 | * the possibility that a transmit descriptor became |
---|
| 496 | * available between the `if' the started this block, |
---|
| 497 | * and the clearing of the interrupt status register. |
---|
| 498 | */ |
---|
| 499 | sonic_retire_tda (dp); |
---|
| 500 | while (dp->tdaActiveCount == dp->tdaCount) { |
---|
| 501 | /* |
---|
| 502 | * Enable transmitter interrupts. |
---|
| 503 | */ |
---|
| 504 | rp->imr |= (IMR_PINTEN | IMR_PTXEN | IMR_TXEREN); |
---|
| 505 | |
---|
| 506 | /* |
---|
| 507 | * Wait for interrupt |
---|
| 508 | */ |
---|
| 509 | rtems_ka9q_event_receive (INTERRUPT_EVENT, |
---|
| 510 | RTEMS_WAIT|RTEMS_EVENT_ANY, |
---|
| 511 | RTEMS_NO_TIMEOUT); |
---|
| 512 | rp->isr = ISR_PINT | ISR_TXDN | ISR_TXER; |
---|
| 513 | sonic_retire_tda (dp); |
---|
| 514 | } |
---|
| 515 | } |
---|
| 516 | |
---|
| 517 | /* |
---|
| 518 | * Get the head of the packet mbuf chain. |
---|
| 519 | */ |
---|
| 520 | bp = *bpp; |
---|
| 521 | |
---|
| 522 | /* |
---|
| 523 | * Fill in the transmit descriptor fragment descriptors. |
---|
| 524 | * ===CACHE=== |
---|
| 525 | * If data cache is operating in write-back mode, flush cached |
---|
| 526 | * data to memory. |
---|
| 527 | */ |
---|
| 528 | tdp = dp->tdaHead->next; |
---|
| 529 | tdp->mbufp = bp; |
---|
| 530 | packetSize = 0; |
---|
| 531 | fp = tdp->frag; |
---|
| 532 | for (i = 0 ; i < MAXIMUM_FRAGS_PER_DESCRIPTOR ; i++, fp++) { |
---|
| 533 | fp->frag_lsw = LSW(bp->data); |
---|
| 534 | fp->frag_msw = MSW(bp->data); |
---|
| 535 | fp->frag_size = bp->cnt; |
---|
| 536 | packetSize += bp->cnt; |
---|
| 537 | |
---|
| 538 | /* |
---|
| 539 | * Break out of the loop if this mbuf is the last in the frame. |
---|
| 540 | */ |
---|
| 541 | if ((bp = bp->next) == NULL) |
---|
| 542 | break; |
---|
| 543 | } |
---|
| 544 | |
---|
| 545 | /* |
---|
| 546 | * Pad short packets. |
---|
| 547 | */ |
---|
| 548 | if ((packetSize < 64) && (i < MAXIMUM_FRAGS_PER_DESCRIPTOR)) { |
---|
| 549 | int padSize = 64 - packetSize; |
---|
| 550 | fp->frag_lsw = LSW(padBuf); |
---|
| 551 | fp->frag_msw = MSW(padBuf); |
---|
| 552 | fp->frag_size = padSize; |
---|
| 553 | packetSize += padSize; |
---|
| 554 | i++; |
---|
| 555 | fp++; |
---|
| 556 | } |
---|
| 557 | |
---|
| 558 | /* |
---|
| 559 | * Fill Transmit Descriptor |
---|
| 560 | */ |
---|
| 561 | tdp->pkt_size = packetSize; |
---|
| 562 | tdp->frag_count = i; |
---|
| 563 | tdp->status = 0; |
---|
| 564 | |
---|
| 565 | /* |
---|
| 566 | * Chain onto list and start transmission. |
---|
| 567 | */ |
---|
| 568 | tdp->linkp = &fp->frag_link; |
---|
| 569 | *tdp->linkp = LSW(tdp->next) | TDA_LINK_EOL; |
---|
| 570 | *dp->tdaHead->linkp &= ~TDA_LINK_EOL; |
---|
| 571 | rp->cr = CR_TXP; |
---|
| 572 | dp->tdaActiveCount++; |
---|
| 573 | dp->tdaHead = tdp; |
---|
| 574 | |
---|
| 575 | /* |
---|
| 576 | * Let KA9Q know the packet is on the way. |
---|
| 577 | */ |
---|
| 578 | dp->txWaitTid = 0; |
---|
| 579 | *bpp = NULL; |
---|
| 580 | return 0; |
---|
| 581 | } |
---|
| 582 | |
---|
| 583 | /* |
---|
| 584 | ****************************************************************** |
---|
| 585 | * * |
---|
| 586 | * Receiver Routines * |
---|
| 587 | * * |
---|
| 588 | ****************************************************************** |
---|
| 589 | */ |
---|
| 590 | |
---|
| 591 | /* |
---|
| 592 | * Wait for SONIC to hand over a Receive Descriptor. |
---|
| 593 | */ |
---|
| 594 | static void |
---|
| 595 | sonic_rda_wait (struct sonic *dp, ReceiveDescriptorPointer_t rdp) |
---|
| 596 | { |
---|
| 597 | int i; |
---|
| 598 | volatile struct SonicRegisters *rp = dp->sonic; |
---|
| 599 | |
---|
| 600 | /* |
---|
| 601 | * Wait for Receive Descriptor. |
---|
| 602 | * The order of the tests is very important. |
---|
| 603 | * The RDA is checked after RBAE is detected. This ensures that |
---|
| 604 | * the driver processes all RDA entries before reusing the RRA |
---|
| 605 | * entry holding the giant packet. |
---|
| 606 | * The event wait is done after the RDA and RBAE checks. This |
---|
| 607 | * catches the possibility that a Receive Descriptor became ready |
---|
| 608 | * between the call to this function and the clearing of the |
---|
| 609 | * interrupt status register bit. |
---|
| 610 | */ |
---|
| 611 | for (;;) { |
---|
| 612 | /* |
---|
| 613 | * Has a giant packet arrived? |
---|
| 614 | * The National DP83932C data sheet is very vague on what |
---|
| 615 | * happens under this condition. The description of the |
---|
| 616 | * Interrupt Status Register (Section 4.3.6) states, |
---|
| 617 | * ``Reception is aborted and the SONIC fetches the next |
---|
| 618 | * available resource descriptors in the RRA. The buffer |
---|
| 619 | * space is not re-used and an RDA is not setup for the |
---|
| 620 | * truncated packet.'' |
---|
| 621 | * I take ``Reception is aborted'' to mean that the RXEN |
---|
| 622 | * bit in the Command Register is cleared and must be set |
---|
| 623 | * by the driver to begin reception again. |
---|
| 624 | * Unfortunately, an alternative interpretation could be |
---|
| 625 | * that only reception of the current packet is aborted. |
---|
| 626 | * This would be more difficult to recover from.... |
---|
| 627 | */ |
---|
| 628 | if (rp->isr & ISR_RBAE) { |
---|
| 629 | /* |
---|
| 630 | * One more check to soak up any Receive Descriptors |
---|
| 631 | * that may already have been handed back to the driver. |
---|
| 632 | */ |
---|
| 633 | if (rdp->in_use == 0) |
---|
| 634 | break; |
---|
| 635 | |
---|
| 636 | /* |
---|
| 637 | * Check my interpretation of the SONIC manual. |
---|
| 638 | */ |
---|
| 639 | if (rp->cr & CR_RXEN) |
---|
| 640 | rtems_panic ("SONIC RBAE/RXEN"); |
---|
| 641 | |
---|
| 642 | /* |
---|
| 643 | * Update statistics |
---|
| 644 | */ |
---|
| 645 | dp->rxGiant++; |
---|
| 646 | |
---|
| 647 | /* |
---|
| 648 | * Reuse receive buffer. |
---|
| 649 | * Again, the manual is subject to interpretation. The |
---|
| 650 | * RRP register is described as, `the lower address of |
---|
| 651 | * the next descriptor the SONIC will read.'' |
---|
| 652 | * Since, acording to the ISR/RBAE notes, the SONIC has |
---|
| 653 | * ``fetched the next available resource descriptor in |
---|
| 654 | * the RRA'', I interpret this to mean that that the |
---|
| 655 | * driver has to move the RRP back *two* entries to |
---|
| 656 | * reuse the receive buffer holding the giant packet. |
---|
| 657 | */ |
---|
| 658 | for (i = 0 ; i < 2 ; i++) { |
---|
| 659 | if (rp->rrp == rp->rsa) |
---|
| 660 | rp->rrp = rp->rea; |
---|
| 661 | rp->rrp -= sizeof (ReceiveResource_t); |
---|
| 662 | } |
---|
| 663 | |
---|
| 664 | /* |
---|
| 665 | * Restart reception |
---|
| 666 | */ |
---|
| 667 | rp->isr = ISR_RBAE; |
---|
| 668 | rp->cr = CR_RXEN; |
---|
| 669 | } |
---|
| 670 | |
---|
| 671 | /* |
---|
| 672 | * Clear old packet-received events. |
---|
| 673 | */ |
---|
| 674 | rp->isr = ISR_PKTRX; |
---|
| 675 | |
---|
| 676 | /* |
---|
| 677 | * Has Receive Descriptor become available? |
---|
| 678 | */ |
---|
| 679 | if (rdp->in_use == 0) |
---|
| 680 | break; |
---|
| 681 | |
---|
| 682 | /* |
---|
| 683 | * Enable interrupts. |
---|
| 684 | */ |
---|
| 685 | rp->imr |= IMR_PRXEN | IMR_RBAEEN; |
---|
| 686 | |
---|
| 687 | /* |
---|
| 688 | * Wait for interrupt. |
---|
| 689 | */ |
---|
| 690 | rtems_ka9q_event_receive (INTERRUPT_EVENT, |
---|
| 691 | RTEMS_WAIT|RTEMS_EVENT_ANY, |
---|
| 692 | RTEMS_NO_TIMEOUT); |
---|
| 693 | } |
---|
| 694 | } |
---|
| 695 | |
---|
| 696 | /* |
---|
| 697 | * SCC reader task |
---|
| 698 | */ |
---|
| 699 | static void |
---|
| 700 | sonic_rx (int dev, void *p1, void *p2) |
---|
| 701 | { |
---|
| 702 | struct iface *iface = (struct iface *)p1; |
---|
| 703 | struct sonic *dp = (struct sonic *)p2; |
---|
| 704 | volatile struct SonicRegisters *rp = dp->sonic; |
---|
| 705 | struct mbuf *bp; |
---|
| 706 | rtems_unsigned16 status; |
---|
| 707 | ReceiveDescriptor_t *rda; |
---|
| 708 | ReceiveDescriptorPointer_t ordp, rdp; |
---|
| 709 | ReceiveResourcePointer_t rwp, rea; |
---|
| 710 | rtems_unsigned16 newMissedTally, oldMissedTally; |
---|
| 711 | int i; |
---|
| 712 | int continuousCount; |
---|
| 713 | |
---|
| 714 | /* |
---|
| 715 | * Set up list in Receive Resource Area. |
---|
| 716 | * Allocate space for incoming packets. |
---|
| 717 | */ |
---|
| 718 | rwp = dp->rsa; |
---|
| 719 | for (i = 0 ; i < (dp->rdaCount + RRA_EXTRA_COUNT) ; i++, rwp++) { |
---|
| 720 | struct mbuf **mbp; |
---|
| 721 | |
---|
| 722 | /* |
---|
| 723 | * Allocate memory for buffer. |
---|
| 724 | * Place a pointer to the mbuf at the beginning of the buffer |
---|
| 725 | * so we can find the mbuf when the SONIC returns the buffer |
---|
| 726 | * to the driver. |
---|
| 727 | */ |
---|
| 728 | bp = ambufw (RBUF_SIZE); |
---|
| 729 | mbp = (struct mbuf **)bp->data; |
---|
| 730 | bp->data += sizeof *mbp; |
---|
| 731 | *mbp = bp; |
---|
| 732 | |
---|
| 733 | /* |
---|
| 734 | * Set up RRA entry |
---|
| 735 | */ |
---|
| 736 | rwp->buff_ptr_lsw = LSW(bp->data); |
---|
| 737 | rwp->buff_ptr_msw = MSW(bp->data); |
---|
| 738 | rwp->buff_wc_lsw = RBUF_WC; |
---|
| 739 | rwp->buff_wc_msw = 0; |
---|
| 740 | } |
---|
| 741 | rea = rwp; |
---|
| 742 | |
---|
| 743 | /* |
---|
| 744 | * Set up remaining Receive Resource Area pointers |
---|
| 745 | */ |
---|
| 746 | rp->rsa = LSW(dp->rsa); |
---|
| 747 | rp->rrp = LSW(dp->rsa); |
---|
| 748 | rp->rea = LSW(rea); |
---|
| 749 | rp->rwp = LSW(rea); |
---|
| 750 | |
---|
| 751 | /* |
---|
| 752 | * Set End Of Buffer Count register to the value recommended |
---|
| 753 | * in Note 1 of Section 3.4.4.4 of the SONIC data sheet. |
---|
| 754 | */ |
---|
| 755 | rp->eobc = RBUF_WC - 2; |
---|
| 756 | |
---|
| 757 | /* |
---|
| 758 | * Set up circular linked list in Receive Descriptor Area. |
---|
| 759 | * Leaves ordp pointing at the `end' of the list and |
---|
| 760 | * rdp pointing at the `beginning' of the list. |
---|
| 761 | */ |
---|
| 762 | rda = sonic_allocate (dp->rdaCount * sizeof *rda); |
---|
| 763 | ordp = rdp = rda; |
---|
| 764 | for (i = 0 ; i < dp->rdaCount ; i++) { |
---|
| 765 | /* |
---|
| 766 | * Set up RDA entry |
---|
| 767 | */ |
---|
| 768 | if (i == (dp->rdaCount - 1)) |
---|
| 769 | rdp->next = rda; |
---|
| 770 | else |
---|
| 771 | rdp->next = (ReceiveDescriptor_t *)(rdp + 1); |
---|
| 772 | rdp->in_use = 1; |
---|
| 773 | ordp = rdp; |
---|
| 774 | rdp = rdp->next; |
---|
| 775 | ordp->link = LSW(rdp); |
---|
| 776 | } |
---|
| 777 | ordp->link |= RDA_LINK_EOL; |
---|
| 778 | rp->urda = MSW(rdp); |
---|
| 779 | rp->crda = LSW(rdp); |
---|
| 780 | |
---|
| 781 | /* |
---|
| 782 | * Start the receiver |
---|
| 783 | */ |
---|
| 784 | oldMissedTally = rp->mpt; |
---|
| 785 | rp->cr = CR_RRRA; |
---|
| 786 | rp->cr = CR_RXEN; |
---|
| 787 | |
---|
| 788 | /* |
---|
| 789 | * Input packet handling loop |
---|
| 790 | */ |
---|
| 791 | continuousCount = 0; |
---|
| 792 | for (;;) { |
---|
| 793 | /* |
---|
| 794 | * Wait till SONIC supplies a Receive Descriptor. |
---|
| 795 | */ |
---|
| 796 | if (rdp->in_use) { |
---|
| 797 | continuousCount = 0; |
---|
| 798 | sonic_rda_wait (dp, rdp); |
---|
| 799 | } |
---|
| 800 | |
---|
| 801 | /* |
---|
| 802 | * Check that packet is valid |
---|
| 803 | */ |
---|
| 804 | status = rdp->status; |
---|
| 805 | if (status & RDA_STATUS_PRX) { |
---|
| 806 | struct mbuf **mbp; |
---|
| 807 | void *p; |
---|
| 808 | |
---|
| 809 | /* |
---|
| 810 | * Get the mbuf pointer |
---|
| 811 | */ |
---|
| 812 | p = PTR(rdp->pkt_msw, rdp->pkt_lsw); |
---|
| 813 | mbp = (struct mbuf **)p - 1; |
---|
| 814 | bp = *mbp; |
---|
| 815 | |
---|
| 816 | /* |
---|
| 817 | * Pass the packet up the chain. |
---|
| 818 | * The mbuf count is reduced to remove |
---|
| 819 | * the frame check sequence at the end |
---|
| 820 | * of the packet. |
---|
| 821 | * ===CACHE=== |
---|
| 822 | * Invalidate cache entries for this memory. |
---|
| 823 | */ |
---|
| 824 | bp->cnt = rdp->byte_count - sizeof (uint32); |
---|
| 825 | net_route (iface, &bp); |
---|
| 826 | |
---|
| 827 | /* |
---|
| 828 | * Give the network code a chance to digest the |
---|
| 829 | * packet. This guards against a flurry of |
---|
| 830 | * incoming packets (usually an ARP storm) from |
---|
| 831 | * using up all the available memory. |
---|
| 832 | */ |
---|
| 833 | if (++continuousCount >= dp->rdaCount) |
---|
| 834 | kwait_null (); |
---|
| 835 | |
---|
| 836 | /* |
---|
| 837 | * Sanity check that Receive Resource Area is |
---|
| 838 | * still in sync with Receive Descriptor Area |
---|
| 839 | * The buffer reported in the Receive Descriptor |
---|
| 840 | * should be the same as the buffer in the Receive |
---|
| 841 | * Resource we are about to reuse. |
---|
| 842 | */ |
---|
| 843 | if ((LSW(p) != rwp->buff_ptr_lsw) |
---|
| 844 | || (MSW(p) != rwp->buff_ptr_msw)) |
---|
| 845 | rtems_panic ("SONIC RDA/RRA"); |
---|
| 846 | |
---|
| 847 | /* |
---|
| 848 | * Allocate a new mbuf. |
---|
| 849 | */ |
---|
| 850 | bp = ambufw (RBUF_SIZE); |
---|
| 851 | mbp = (struct mbuf **)bp->data; |
---|
| 852 | bp->data += sizeof *mbp; |
---|
| 853 | *mbp = bp; |
---|
| 854 | |
---|
| 855 | /* |
---|
| 856 | * Reuse Receive Resource. |
---|
| 857 | */ |
---|
| 858 | rwp->buff_ptr_lsw = LSW(bp->data); |
---|
| 859 | rwp->buff_ptr_msw = MSW(bp->data); |
---|
| 860 | rwp++; |
---|
| 861 | if (rwp == rea) |
---|
| 862 | rwp = dp->rsa; |
---|
| 863 | rp->rwp = LSW(rwp); |
---|
| 864 | |
---|
| 865 | /* |
---|
| 866 | * Tell the SONIC to reread the RRA. |
---|
| 867 | */ |
---|
| 868 | if (rp->isr & ISR_RBE) |
---|
| 869 | rp->isr = ISR_RBE; |
---|
| 870 | } |
---|
| 871 | else { |
---|
| 872 | if (status & RDA_STATUS_COL) |
---|
| 873 | dp->rxCollision++; |
---|
| 874 | if (status & RDA_STATUS_FAER) |
---|
| 875 | dp->rxNonOctet++; |
---|
| 876 | else if (status & RDA_STATUS_CRCR) |
---|
| 877 | dp->rxBadCRC++; |
---|
| 878 | } |
---|
| 879 | |
---|
| 880 | /* |
---|
| 881 | * Count missed packets |
---|
| 882 | */ |
---|
| 883 | newMissedTally = rp->mpt; |
---|
| 884 | if (newMissedTally != oldMissedTally) { |
---|
| 885 | dp->rxMissed += (newMissedTally - oldMissedTally) & 0xFFFF; |
---|
| 886 | newMissedTally = oldMissedTally; |
---|
| 887 | } |
---|
| 888 | |
---|
| 889 | /* |
---|
| 890 | * Move to next receive descriptor |
---|
| 891 | */ |
---|
| 892 | rdp->link |= RDA_LINK_EOL; |
---|
| 893 | rdp->in_use = 1; |
---|
| 894 | ordp->link &= ~RDA_LINK_EOL; |
---|
| 895 | ordp = rdp; |
---|
| 896 | rdp = rdp->next; |
---|
| 897 | } |
---|
| 898 | } |
---|
| 899 | |
---|
| 900 | /* |
---|
| 901 | ****************************************************************** |
---|
| 902 | * * |
---|
| 903 | * Initialization Routines * |
---|
| 904 | * * |
---|
| 905 | ****************************************************************** |
---|
| 906 | */ |
---|
| 907 | |
---|
| 908 | /* |
---|
| 909 | * Initialize the SONIC hardware |
---|
| 910 | */ |
---|
| 911 | static void |
---|
| 912 | sonic_initialize_hardware (struct sonic *dp, int broadcastFlag) |
---|
| 913 | { |
---|
| 914 | volatile struct SonicRegisters *rp = dp->sonic; |
---|
| 915 | int i; |
---|
| 916 | unsigned char *hwaddr; |
---|
| 917 | rtems_status_code sc; |
---|
| 918 | rtems_isr_entry old_handler; |
---|
| 919 | TransmitDescriptorPointer_t otdp, tdp; |
---|
| 920 | struct CamDescriptor{ |
---|
| 921 | rtems_unsigned32 cep; |
---|
| 922 | rtems_unsigned32 cap0; |
---|
| 923 | rtems_unsigned32 cap1; |
---|
| 924 | rtems_unsigned32 cap2; |
---|
| 925 | rtems_unsigned32 ce; |
---|
| 926 | }; |
---|
| 927 | volatile struct CamDescriptor *cdp; |
---|
| 928 | |
---|
| 929 | /* |
---|
| 930 | * Issue a software reset if necessary. |
---|
| 931 | */ |
---|
| 932 | if ((rp->cr & CR_RST) == 0) |
---|
| 933 | rp->cr = CR_RST; |
---|
| 934 | |
---|
| 935 | /* |
---|
| 936 | * Set up data configuration registers. |
---|
| 937 | */ |
---|
| 938 | rp->dcr = SONIC_DCR; |
---|
| 939 | rp->dcr2 = SONIC_DC2; |
---|
| 940 | |
---|
| 941 | /* |
---|
| 942 | * Remove device reset |
---|
| 943 | */ |
---|
| 944 | rp->cr = 0; |
---|
| 945 | |
---|
| 946 | /* |
---|
| 947 | * Clear outstanding interrupts. |
---|
| 948 | */ |
---|
| 949 | rp->isr = 0x7FFF; |
---|
| 950 | |
---|
| 951 | /* |
---|
| 952 | * Allocate the receive resource area. |
---|
| 953 | * In accordance with National Application Note 746, make the |
---|
| 954 | * receive resource area bigger than the receive descriptor area. |
---|
| 955 | * This has the useful side effect of making the receive resource |
---|
| 956 | * area big enough to hold the CAM descriptor area. |
---|
| 957 | */ |
---|
| 958 | dp->rsa = sonic_allocate ((dp->rdaCount + RRA_EXTRA_COUNT) * sizeof *dp->rsa); |
---|
| 959 | rp->urra = MSW(dp->rsa); |
---|
| 960 | |
---|
| 961 | /* |
---|
| 962 | * Set up the SONIC CAM with our hardware address. |
---|
| 963 | * Use the Receive Resource Area to hold the CAM Descriptor Area. |
---|
| 964 | */ |
---|
| 965 | hwaddr = dp->iface->hwaddr; |
---|
| 966 | cdp = (struct CamDescriptor *)dp->rsa; |
---|
| 967 | cdp->cep = 0; /* Fill first entry in CAM */ |
---|
| 968 | cdp->cap2 = hwaddr[0] << 8 | hwaddr[1]; |
---|
| 969 | cdp->cap1 = hwaddr[2] << 8 | hwaddr[3]; |
---|
| 970 | cdp->cap0 = hwaddr[4] << 8 | hwaddr[5]; |
---|
| 971 | cdp->ce = 0x0001; /* Enable first entry in CAM */ |
---|
| 972 | rp->cdc = 1; /* One entry in CDA */ |
---|
| 973 | rp->cdp = LSW(cdp); |
---|
| 974 | rp->cr = CR_LCAM; /* Load the CAM */ |
---|
| 975 | while (rp->cr & CR_LCAM) |
---|
| 976 | continue; |
---|
| 977 | |
---|
| 978 | /* |
---|
| 979 | * Verify that CAM was properly loaded. |
---|
| 980 | */ |
---|
| 981 | rp->cep = 0; /* Select first entry in CAM */ |
---|
| 982 | if ((rp->cap2 != cdp->cap2) |
---|
| 983 | || (rp->cap1 != cdp->cap1) |
---|
| 984 | || (rp->cap0 != cdp->cap0) |
---|
| 985 | || (rp->ce != cdp->ce)) { |
---|
| 986 | printf ("Failed to load Ethernet address into SONIC CAM.\n" |
---|
| 987 | " Wrote %04x%04x%04x - %#x\n" |
---|
| 988 | " Read %04x%04x%04x - %#x\n", |
---|
| 989 | cdp->cap2, cdp->cap1, cdp->cap0, cdp->ce, |
---|
| 990 | rp->cap2, rp->cap1, rp->cap0, rp->ce); |
---|
| 991 | rtems_panic ("SONIC LCAM"); |
---|
| 992 | } |
---|
| 993 | |
---|
| 994 | /* |
---|
| 995 | * Set up circular linked list in Transmit Descriptor Area. |
---|
| 996 | * Use the PINT bit in the transmit configuration field to |
---|
| 997 | * request an interrupt on every other transmitted packet. |
---|
| 998 | */ |
---|
| 999 | dp->tdaActiveCount = 0; |
---|
| 1000 | dp->tdaTail = sonic_allocate (dp->tdaCount * sizeof *tdp); |
---|
| 1001 | otdp = tdp = dp->tdaTail; |
---|
| 1002 | for (i = 0 ; i < dp->tdaCount ; i++) { |
---|
| 1003 | if (i & 1) |
---|
| 1004 | tdp->pkt_config = TDA_CONFIG_PINT; |
---|
| 1005 | else |
---|
| 1006 | tdp->pkt_config = 0; |
---|
| 1007 | if (i == (dp->tdaCount - 1)) |
---|
| 1008 | tdp->next = (TransmitDescriptor_t *)dp->tdaTail; |
---|
| 1009 | else |
---|
| 1010 | tdp->next = (TransmitDescriptor_t *)(tdp + 1); |
---|
| 1011 | otdp = tdp; |
---|
| 1012 | tdp = tdp->next; |
---|
| 1013 | } |
---|
| 1014 | dp->tdaHead = otdp; |
---|
| 1015 | dp->tdaHead->linkp = &dp->tdaHead->frag[0].frag_link; |
---|
| 1016 | rp->utda = MSW(dp->tdaTail); |
---|
| 1017 | rp->ctda = LSW(dp->tdaTail); |
---|
| 1018 | |
---|
| 1019 | /* |
---|
| 1020 | * Enable/disable reception of broadcast packets |
---|
| 1021 | */ |
---|
| 1022 | if (broadcastFlag) |
---|
| 1023 | rp->rcr = RCR_BRD; |
---|
| 1024 | else |
---|
| 1025 | rp->rcr = 0; |
---|
| 1026 | |
---|
| 1027 | /* |
---|
| 1028 | * Attach SONIC interrupt handler |
---|
| 1029 | */ |
---|
| 1030 | rp->imr = 0; |
---|
| 1031 | sc = rtems_interrupt_catch (sonic_interrupt_handler, dp->vector, &old_handler); |
---|
| 1032 | if (sc != RTEMS_SUCCESSFUL) |
---|
| 1033 | rtems_panic ("Can't attach SONIC interrupt handler: %s\n", |
---|
| 1034 | rtems_status_text (sc)); |
---|
| 1035 | |
---|
| 1036 | /* |
---|
| 1037 | * Remainder of hardware initialization is |
---|
| 1038 | * done by the receive and transmit daemons. |
---|
| 1039 | */ |
---|
| 1040 | } |
---|
| 1041 | |
---|
| 1042 | /* |
---|
| 1043 | * Attach an SONIC driver to the system |
---|
| 1044 | * This is the only `extern' function in the driver. |
---|
| 1045 | * |
---|
| 1046 | * argv[0]: interface label, e.g. "rtems" |
---|
| 1047 | * The remainder of the arguments are optional key/value pairs: |
---|
| 1048 | * mtu ## -- maximum transmission unit, default 1500 |
---|
| 1049 | * broadcast y/n -- accept or ignore broadcast packets, default yes |
---|
| 1050 | * rbuf ## -- Set number of receive descriptor entries |
---|
| 1051 | * tbuf ## -- Set number of transmit descriptor entries |
---|
| 1052 | * ip ###.###.###.### -- IP address |
---|
| 1053 | * ether ##:##:##:##:##:## -- Ethernet address |
---|
| 1054 | * reg ###### -- Address of SONIC device registers |
---|
| 1055 | * vector ### -- SONIC interrupt vector |
---|
| 1056 | */ |
---|
| 1057 | int |
---|
| 1058 | rtems_ka9q_driver_attach (int argc, char *argv[], void *p) |
---|
| 1059 | { |
---|
| 1060 | struct sonic *dp; |
---|
| 1061 | struct iface *iface; |
---|
| 1062 | char *cp; |
---|
| 1063 | int argIndex; |
---|
| 1064 | int broadcastFlag; |
---|
| 1065 | char cbuf[30]; |
---|
| 1066 | |
---|
| 1067 | /* |
---|
| 1068 | * Find an unused entry |
---|
| 1069 | */ |
---|
| 1070 | dp = sonic; |
---|
| 1071 | for (;;) { |
---|
| 1072 | if (dp == &sonic[NSONIC]) { |
---|
| 1073 | printf ("No more SONIC devices.\n"); |
---|
| 1074 | return -1; |
---|
| 1075 | } |
---|
| 1076 | if (dp->iface == NULL) |
---|
| 1077 | break; |
---|
| 1078 | dp++; |
---|
| 1079 | } |
---|
| 1080 | if (if_lookup (argv[0]) != NULL) { |
---|
| 1081 | printf ("Interface %s already exists\n", argv[0]); |
---|
| 1082 | return -1; |
---|
| 1083 | } |
---|
| 1084 | |
---|
| 1085 | /* |
---|
| 1086 | * Create an inteface descriptor |
---|
| 1087 | */ |
---|
| 1088 | iface = callocw (1, sizeof *iface); |
---|
| 1089 | iface->name = strdup (argv[0]); |
---|
| 1090 | iface->dev = dp - sonic;; |
---|
| 1091 | |
---|
| 1092 | /* |
---|
| 1093 | * Set default values |
---|
| 1094 | */ |
---|
| 1095 | broadcastFlag = 1; |
---|
| 1096 | dp->txWaitTid = 0; |
---|
| 1097 | dp->rdaCount = RDA_COUNT; |
---|
| 1098 | dp->tdaCount = TDA_COUNT; |
---|
| 1099 | iface->mtu = 1500; |
---|
| 1100 | iface->addr = Ip_addr; |
---|
| 1101 | iface->hwaddr = mallocw (EADDR_LEN); |
---|
| 1102 | memset (iface->hwaddr, 0x08, EADDR_LEN); |
---|
| 1103 | dp->sonic = (struct SonicRegisters *)SONIC_BASE_ADDRESS; |
---|
| 1104 | dp->vector = SONIC_VECTOR; |
---|
| 1105 | |
---|
| 1106 | /* |
---|
| 1107 | * Parse remaining arguments |
---|
| 1108 | */ |
---|
| 1109 | for (argIndex = 1 ; argIndex < (argc - 1) ; argIndex++) { |
---|
| 1110 | if (strcmp ("mtu", argv[argIndex]) == 0) { |
---|
| 1111 | iface->mtu = strtoul (argv[++argIndex], NULL, 0); |
---|
| 1112 | } |
---|
| 1113 | else if (strcmp ("broadcast", argv[argIndex]) == 0) { |
---|
| 1114 | if (*argv[++argIndex] == 'n') |
---|
| 1115 | broadcastFlag = 0; |
---|
| 1116 | } |
---|
| 1117 | else if (strcmp ("rbuf", argv[argIndex]) == 0) { |
---|
| 1118 | /* |
---|
| 1119 | * The minimum RDA count is 2. A single-entry RDA |
---|
| 1120 | * would be difficult to use since the SONIC does |
---|
| 1121 | * not release (in_use = 0) the RDA that has the |
---|
| 1122 | * EOL bit set. |
---|
| 1123 | */ |
---|
| 1124 | dp->rdaCount = strtoul (argv[++argIndex], NULL, 0); |
---|
| 1125 | if ((dp->rdaCount <= 1) || (dp->rdaCount > 200)) { |
---|
| 1126 | printf ("RDA option (%d) is invalid.\n", dp->rdaCount); |
---|
| 1127 | return -1; |
---|
| 1128 | } |
---|
| 1129 | } |
---|
| 1130 | else if (strcmp ("tbuf", argv[argIndex]) == 0) { |
---|
| 1131 | dp->tdaCount = strtoul (argv[++argIndex], NULL, 0); |
---|
| 1132 | if ((dp->tdaCount <= 1) || (dp->tdaCount > 200)) { |
---|
| 1133 | printf ("TDA option (%d) is invalid.\n", dp->tdaCount); |
---|
| 1134 | return -1; |
---|
| 1135 | } |
---|
| 1136 | } |
---|
| 1137 | else if (strcmp ("ip", argv[argIndex]) == 0) { |
---|
| 1138 | iface->addr = resolve (argv[++argIndex]); |
---|
| 1139 | } |
---|
| 1140 | else if (strcmp ("ether", argv[argIndex]) == 0) { |
---|
| 1141 | gether (iface->hwaddr, argv[++argIndex]); |
---|
| 1142 | } |
---|
| 1143 | else if (strcmp ("reg", argv[argIndex]) == 0) { |
---|
| 1144 | dp->sonic = (struct SonicRegisters *)strtoul (argv[++argIndex], NULL, 0); |
---|
| 1145 | } |
---|
| 1146 | else if (strcmp ("vector", argv[argIndex]) == 0) { |
---|
| 1147 | dp->vector = strtoul (argv[++argIndex], NULL, 0); |
---|
| 1148 | } |
---|
| 1149 | else { |
---|
| 1150 | printf ("Argument %d (%s) is invalid.\n", argIndex, argv[argIndex]); |
---|
| 1151 | return -1; |
---|
| 1152 | } |
---|
| 1153 | } |
---|
| 1154 | printf ("Ethernet address: %s\n", pether (cbuf, iface->hwaddr)); |
---|
| 1155 | iface->raw = sonic_raw; |
---|
| 1156 | iface->stop = sonic_stop; |
---|
| 1157 | iface->show = sonic_show; |
---|
| 1158 | dp->iface = iface; |
---|
| 1159 | setencap (iface, "Ethernet"); |
---|
| 1160 | |
---|
| 1161 | /* |
---|
| 1162 | * Set up SONIC hardware |
---|
| 1163 | */ |
---|
| 1164 | sonic_initialize_hardware (dp, broadcastFlag); |
---|
| 1165 | |
---|
| 1166 | /* |
---|
| 1167 | * Chain onto list of interfaces |
---|
| 1168 | */ |
---|
| 1169 | iface->next = Ifaces; |
---|
| 1170 | Ifaces = iface; |
---|
| 1171 | |
---|
| 1172 | /* |
---|
| 1173 | * Start I/O daemons |
---|
| 1174 | */ |
---|
| 1175 | cp = if_name (iface, " tx"); |
---|
| 1176 | iface->txproc = newproc (cp, 2048, if_tx, iface->dev, iface, NULL, 0); |
---|
| 1177 | free (cp); |
---|
| 1178 | cp = if_name (iface, " rx"); |
---|
| 1179 | iface->rxproc = newproc (cp, 2048, sonic_rx, iface->dev, iface, dp, 0); |
---|
| 1180 | free (cp); |
---|
| 1181 | return 0; |
---|
| 1182 | } |
---|