|
|
1.1 ! root 1: /* $Id: am7990.c,v 1.3 2007/03/25 21:18:50 fredette Exp $ */ ! 2: ! 3: /* ic/am7990.c - implementation of Am7990 emulation: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2006 Matt Fredette ! 7: * All rights reserved. ! 8: * ! 9: * Redistribution and use in source and binary forms, with or without ! 10: * modification, are permitted provided that the following conditions ! 11: * are met: ! 12: * 1. Redistributions of source code must retain the above copyright ! 13: * notice, this list of conditions and the following disclaimer. ! 14: * 2. Redistributions in binary form must reproduce the above copyright ! 15: * notice, this list of conditions and the following disclaimer in the ! 16: * documentation and/or other materials provided with the distribution. ! 17: * 3. All advertising materials mentioning features or use of this software ! 18: * must display the following acknowledgement: ! 19: * This product includes software developed by Matt Fredette. ! 20: * 4. The name of the author may not be used to endorse or promote products ! 21: * derived from this software without specific prior written permission. ! 22: * ! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ! 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ! 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ! 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ! 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ! 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ! 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ! 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ! 33: * POSSIBILITY OF SUCH DAMAGE. ! 34: */ ! 35: ! 36: #include <tme/common.h> ! 37: _TME_RCSID("$Id: am7990.c,v 1.3 2007/03/25 21:18:50 fredette Exp $"); ! 38: ! 39: /* includes: */ ! 40: #include <tme/generic/bus-device.h> ! 41: #include <tme/generic/ethernet.h> ! 42: ! 43: /* macros: */ ! 44: ! 45: /* CSR0: */ ! 46: #define TME_AM7990_CSR0_ERR TME_BIT(15) ! 47: #define TME_AM7990_CSR0_BABL TME_BIT(14) ! 48: #define TME_AM7990_CSR0_CERR TME_BIT(13) ! 49: #define TME_AM7990_CSR0_MISS TME_BIT(12) ! 50: #define TME_AM7990_CSR0_MERR TME_BIT(11) ! 51: #define TME_AM7990_CSR0_RINT TME_BIT(10) ! 52: #define TME_AM7990_CSR0_TINT TME_BIT(9) ! 53: #define TME_AM7990_CSR0_IDON TME_BIT(8) ! 54: #define TME_AM7990_CSR0_INTR TME_BIT(7) ! 55: #define TME_AM7990_CSR0_INEA TME_BIT(6) ! 56: #define TME_AM7990_CSR0_RXON TME_BIT(5) ! 57: #define TME_AM7990_CSR0_TXON TME_BIT(4) ! 58: #define TME_AM7990_CSR0_TDMD TME_BIT(3) ! 59: #define TME_AM7990_CSR0_STOP TME_BIT(2) ! 60: #define TME_AM7990_CSR0_STRT TME_BIT(1) ! 61: #define TME_AM7990_CSR0_INIT TME_BIT(0) ! 62: #define TME_AM7990_CSR0_READ_ONLY \ ! 63: (TME_AM7990_CSR0_ERR \ ! 64: | TME_AM7990_CSR0_INTR \ ! 65: | TME_AM7990_CSR0_RXON \ ! 66: | TME_AM7990_CSR0_TXON) ! 67: #define TME_AM7990_CSR0_WRITE_ONE_TO_CLEAR \ ! 68: (TME_AM7990_CSR0_BABL \ ! 69: | TME_AM7990_CSR0_CERR \ ! 70: | TME_AM7990_CSR0_MISS \ ! 71: | TME_AM7990_CSR0_MERR \ ! 72: | TME_AM7990_CSR0_RINT \ ! 73: | TME_AM7990_CSR0_TINT \ ! 74: | TME_AM7990_CSR0_IDON) ! 75: #define TME_AM7990_CSR0_WRITE_ONE_ONLY \ ! 76: (TME_AM7990_CSR0_TDMD \ ! 77: | TME_AM7990_CSR0_STOP \ ! 78: | TME_AM7990_CSR0_STRT \ ! 79: | TME_AM7990_CSR0_INIT) ! 80: ! 81: /* CSR3: */ ! 82: #define TME_AM7990_CSR3_BSWAP TME_BIT(2) ! 83: #define TME_AM7990_CSR3_ACON TME_BIT(1) ! 84: #define TME_AM7990_CSR3_BCON TME_BIT(0) ! 85: ! 86: /* Mode: */ ! 87: #define TME_AM7990_MODE_PROM TME_BIT(15) ! 88: #define TME_AM7990_MODE_EMBA TME_BIT(7) ! 89: #define TME_AM7990_MODE_INTL TME_BIT(6) ! 90: #define TME_AM7990_MODE_DRTY TME_BIT(5) ! 91: #define TME_AM7990_MODE_COLL TME_BIT(4) ! 92: #define TME_AM7990_MODE_DTCR TME_BIT(3) ! 93: #define TME_AM7990_MODE_LOOP TME_BIT(2) ! 94: #define TME_AM7990_MODE_DTX TME_BIT(1) ! 95: #define TME_AM7990_MODE_DRX TME_BIT(0) ! 96: ! 97: /* a Descriptor Ring Pointer: */ ! 98: #define TME_AM7990_DRP_XDRA (0x00fffff8) ! 99: #define TME_AM7990_DRP_XLEN_LOG2 (0xe0000000) ! 100: ! 101: /* a descriptor table entry: */ ! 102: #define TME_AM7990_DTE_OFFSET_XMD0 (0 * sizeof(tme_uint16_t)) ! 103: #define TME_AM7990_DTE_OFFSET_XMD1 (1 * sizeof(tme_uint16_t)) ! 104: #define TME_AM7990_DTE_OFFSET_XMD2 (2 * sizeof(tme_uint16_t)) ! 105: #define TME_AM7990_DTE_OFFSET_XMD3 (3 * sizeof(tme_uint16_t)) ! 106: #define TME_AM7990_DTE_SIZE (4 * sizeof(tme_uint16_t)) ! 107: ! 108: /* common parts of TMD1 and RMD1: */ ! 109: #define TME_AM7990_XMD1_OWN TME_BIT(15) ! 110: #define TME_AM7990_XMD1_ERR TME_BIT(14) ! 111: #define TME_AM7990_XMD1_STP TME_BIT(9) ! 112: #define TME_AM7990_XMD1_ENP TME_BIT(8) ! 113: #define TME_AM7990_XMD1_HADR (0x00ff) ! 114: ! 115: /* common parts of TMD2 and RMD2: */ ! 116: #define TME_AM7990_XMD2_BCNT (0x0fff) ! 117: ! 118: /* TMD1: */ ! 119: #define TME_AM7990_TMD1_ADD_FCS TME_BIT(13) ! 120: ! 121: /* TMD3: */ ! 122: #define TME_AM7990_TMD3_BUFF TME_BIT(15) ! 123: ! 124: /* RMD1: */ ! 125: #define TME_AM7990_RMD1_BUFF TME_BIT(10) ! 126: ! 127: /* the callout flags: */ ! 128: #define TME_AM7990_CALLOUTS_RUNNING TME_BIT(0) ! 129: #define TME_AM7990_CALLOUTS_MASK (-2) ! 130: #define TME_AM7990_CALLOUT_RECEIVE TME_BIT(1) ! 131: #define TME_AM7990_CALLOUT_TRANSMIT_SCAN TME_BIT(2) ! 132: #define TME_AM7990_CALLOUT_CONFIG TME_BIT(3) ! 133: #define TME_AM7990_CALLOUT_DMA_READ TME_BIT(4) ! 134: #define TME_AM7990_CALLOUT_DMA_WRITE TME_BIT(5) ! 135: ! 136: /* the default locks: */ ! 137: #define TME_AM7990_LOCKS_DEFAULT (0) ! 138: ! 139: /* the size of the TLB entry hash: */ ! 140: #define TME_AM7990_TLB_HASH_SIZE (512) ! 141: ! 142: /* structures: */ ! 143: ! 144: /* the chip: */ ! 145: struct tme_am7990 { ! 146: ! 147: /* our simple bus device header: */ ! 148: struct tme_bus_device tme_am7990_device; ! 149: #define tme_am7990_element tme_am7990_device.tme_bus_device_element ! 150: ! 151: /* the Ethernet connection: */ ! 152: struct tme_ethernet_connection *tme_am7990_eth_connection; ! 153: ! 154: /* the mutex protecting the chip: */ ! 155: tme_mutex_t tme_am7990_mutex; ! 156: ! 157: /* the callout flags: */ ! 158: int tme_am7990_callout_flags; ! 159: ! 160: /* our DMA TLB hash: */ ! 161: struct tme_bus_tlb * tme_shared tme_am7990_tlb_hash; ! 162: tme_rwlock_t tme_am7990_tlb_hash_rwlock; ! 163: ! 164: /* our bus addresses: */ ! 165: tme_bus_addr_t tme_am7990_offset_rap; ! 166: tme_bus_addr_t tme_am7990_offset_rdp; ! 167: ! 168: /* registers: */ ! 169: tme_uint16_t tme_am7990_rap; ! 170: tme_uint16_t tme_am7990_csrs[4]; ! 171: #define tme_am7990_csr0 tme_am7990_csrs[0] ! 172: ! 173: /* the initialization block: */ ! 174: tme_uint16_t tme_am7990_init[12]; ! 175: #define tme_am7990_mode tme_am7990_init[0] ! 176: #define tme_am7990_padr tme_am7990_init[1] ! 177: #define tme_am7990_ladrf tme_am7990_init[4] ! 178: #define tme_am7990_rdra tme_am7990_init[8] ! 179: #define tme_am7990_rlen_rdra tme_am7990_init[9] ! 180: #define tme_am7990_tdra tme_am7990_init[10] ! 181: #define tme_am7990_tlen_tdra tme_am7990_init[11] ! 182: ! 183: /* the transmit ring: */ ! 184: unsigned int tme_am7990_transmit_dte_index_mask; ! 185: tme_uint32_t tme_am7990_transmit_dte_address; ! 186: ! 187: /* the current transmit DTE index, and any previously read TMD1 ! 188: value: */ ! 189: unsigned int tme_am7990_transmit_dte_index; ! 190: tme_uint16_t tme_am7990_transmit_dte_tmd1; ! 191: ! 192: /* the receive buffer: */ ! 193: tme_uint8_t tme_am7990_receive_buffer[TME_ETHERNET_FRAME_MAX]; ! 194: unsigned int tme_am7990_receive_buffer_length; ! 195: ! 196: /* the receive ring: */ ! 197: unsigned int tme_am7990_receive_dte_index_mask; ! 198: tme_uint32_t tme_am7990_receive_dte_address; ! 199: ! 200: /* the current receive DTE index: */ ! 201: unsigned int tme_am7990_receive_dte_index; ! 202: ! 203: /* this is nonzero if the interrupt is asserted: */ ! 204: int tme_am7990_int_asserted; ! 205: ! 206: /* the input and output Ethernet controls: */ ! 207: unsigned int tme_am7990_ether_ctrl_out; ! 208: unsigned int tme_am7990_ether_ctrl_in; ! 209: }; ! 210: ! 211: /* prototypes: */ ! 212: static int _tme_am7990_transmit _TME_P((struct tme_ethernet_connection *, ! 213: tme_ethernet_fid_t *, ! 214: struct tme_ethernet_frame_chunk *, ! 215: unsigned int)); ! 216: ! 217: /* this resets the am7990: */ ! 218: static void ! 219: _tme_am7990_reset(struct tme_am7990 *am7990) ! 220: { ! 221: ! 222: tme_log(&am7990->tme_am7990_element->tme_element_log_handle, ! 223: 100, TME_OK, ! 224: (&am7990->tme_am7990_element->tme_element_log_handle, ! 225: "reset")); ! 226: ! 227: /* clear all pending callouts: */ ! 228: am7990->tme_am7990_callout_flags &= TME_AM7990_CALLOUTS_MASK; ! 229: ! 230: /* reset CSR0: */ ! 231: am7990->tme_am7990_csr0 = TME_AM7990_CSR0_STOP; ! 232: ! 233: /* reset CSR3: */ ! 234: am7990->tme_am7990_csrs[3] = 0; ! 235: ! 236: /* "EMBA is cleared by activation of the RESET pin or setting the ! 237: STOP bit." */ ! 238: am7990->tme_am7990_mode &= ~TME_AM7990_MODE_EMBA; ! 239: } ! 240: ! 241: /* this hashes an address into a TLB entry: */ ! 242: static struct tme_bus_tlb * ! 243: _tme_am7990_tlb_hash(void *_am7990, ! 244: tme_bus_addr_t linear_address, ! 245: unsigned int cycles) ! 246: { ! 247: struct tme_am7990 *am7990; ! 248: ! 249: /* recover our data structure: */ ! 250: am7990 = (struct tme_am7990 *) _am7990; ! 251: ! 252: /* return the TLB entry: */ ! 253: return (tme_memory_atomic_pointer_read(struct tme_bus_tlb *, ! 254: am7990->tme_am7990_tlb_hash, ! 255: &am7990->tme_am7990_tlb_hash_rwlock) ! 256: + ((linear_address >> 10) & (TME_AM7990_TLB_HASH_SIZE - 1))); ! 257: } ! 258: ! 259: /* this locks the mutex: */ ! 260: static void ! 261: _tme_am7990_lock(void *_am7990, ! 262: unsigned int locks) ! 263: { ! 264: struct tme_am7990 *am7990; ! 265: ! 266: /* recover our data structure: */ ! 267: am7990 = (struct tme_am7990 *) _am7990; ! 268: ! 269: /* lock the mutex: */ ! 270: tme_mutex_lock(&am7990->tme_am7990_mutex); ! 271: } ! 272: ! 273: /* this unlocks the mutex: */ ! 274: static void ! 275: _tme_am7990_unlock(void *_am7990, ! 276: unsigned int locks) ! 277: { ! 278: struct tme_am7990 *am7990; ! 279: ! 280: /* recover our data structure: */ ! 281: am7990 = (struct tme_am7990 *) _am7990; ! 282: ! 283: /* unlock the mutex: */ ! 284: tme_mutex_unlock(&am7990->tme_am7990_mutex); ! 285: } ! 286: ! 287: /* this does a DMA: */ ! 288: static int ! 289: _tme_am7990_dma(struct tme_am7990 *am7990, ! 290: tme_uint32_t callout_flags, ! 291: tme_uint32_t address, ! 292: unsigned int count, ! 293: tme_uint8_t *buffer) ! 294: { ! 295: int rc; ! 296: ! 297: /* make the callout: */ ! 298: rc = ((callout_flags & TME_AM7990_CALLOUT_DMA_READ) ! 299: ? tme_bus_device_dma_read_16(&am7990->tme_am7990_device, ! 300: address, ! 301: count, ! 302: buffer, ! 303: TME_AM7990_LOCKS_DEFAULT) ! 304: : tme_bus_device_dma_write_16(&am7990->tme_am7990_device, ! 305: address, ! 306: count, ! 307: buffer, ! 308: TME_AM7990_LOCKS_DEFAULT)); ! 309: ! 310: /* if we got a bus error: */ ! 311: if (rc != TME_OK) { ! 312: ! 313: /* set MERR: */ ! 314: am7990->tme_am7990_csr0 |= TME_AM7990_CSR0_MERR; ! 315: ! 316: /* we were cancelled: */ ! 317: return (TRUE); ! 318: } ! 319: ! 320: /* we weren't cancelled: */ ! 321: return (FALSE); ! 322: } ! 323: ! 324: /* this returns the address for a 16-bit DTE read or write: */ ! 325: static inline tme_uint32_t ! 326: _tme_am7990_dte_address(struct tme_am7990 *am7990, ! 327: tme_uint32_t callout_flags, ! 328: tme_uint32_t dte_offset) ! 329: { ! 330: tme_uint32_t dte_address; ! 331: tme_uint32_t dte_index; ! 332: tme_uint32_t dte_index_mask; ! 333: ! 334: /* get the DTE address, index, and index mask: */ ! 335: if (callout_flags & TME_AM7990_CALLOUT_RECEIVE) { ! 336: dte_address = am7990->tme_am7990_receive_dte_address; ! 337: dte_index = am7990->tme_am7990_receive_dte_index; ! 338: dte_index_mask = am7990->tme_am7990_receive_dte_index_mask; ! 339: } ! 340: else { ! 341: dte_address = am7990->tme_am7990_transmit_dte_address; ! 342: dte_index = am7990->tme_am7990_transmit_dte_index; ! 343: dte_index_mask = am7990->tme_am7990_transmit_dte_index_mask; ! 344: } ! 345: ! 346: /* get the DTE address to read or write: */ ! 347: dte_address ! 348: += (((dte_index * TME_AM7990_DTE_SIZE) ! 349: + dte_offset) ! 350: & ((dte_index_mask * TME_AM7990_DTE_SIZE) ! 351: | (TME_AM7990_DTE_SIZE - 1))); ! 352: assert ((dte_address % sizeof(tme_uint16_t)) == 0); ! 353: ! 354: return (dte_address); ! 355: } ! 356: ! 357: /* this does a 16-bit DTE read: */ ! 358: static tme_uint16_t ! 359: _tme_am7990_read(struct tme_am7990 *am7990, ! 360: tme_uint32_t callout_flags, ! 361: tme_uint32_t dte_offset, ! 362: int *_cancelled) ! 363: { ! 364: tme_uint16_t value; ! 365: ! 366: /* do the DMA read: */ ! 367: *_cancelled = ! 368: _tme_am7990_dma(am7990, ! 369: callout_flags, ! 370: _tme_am7990_dte_address(am7990, ! 371: callout_flags, ! 372: dte_offset), ! 373: sizeof(value), ! 374: (tme_uint8_t *) &value); ! 375: ! 376: /* possibly byteswap the value read: */ ! 377: assert (am7990->tme_am7990_device.tme_bus_device_router != NULL); ! 378: if (am7990->tme_am7990_device.tme_bus_device_router ! 379: != (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE ! 380: ? tme_bus_device_router_16el ! 381: : tme_bus_device_router_16eb)) { ! 382: value = tme_bswap_u16(value); ! 383: } ! 384: ! 385: return (value); ! 386: } ! 387: #define _tme_am7990_tx_read(am7990, dte_offset, _cancelled) \ ! 388: _tme_am7990_read((am7990), TME_AM7990_CALLOUT_DMA_READ, (dte_offset), (_cancelled)) ! 389: #define _tme_am7990_rx_read(am7990, dte_offset, _cancelled) \ ! 390: _tme_am7990_read((am7990), TME_AM7990_CALLOUT_DMA_READ | TME_AM7990_CALLOUT_RECEIVE, (dte_offset), (_cancelled)) ! 391: ! 392: /* this does a 16-bit DTE write: */ ! 393: static int ! 394: _tme_am7990_write(struct tme_am7990 *am7990, ! 395: tme_uint32_t callout_flags, ! 396: tme_uint32_t dte_offset, ! 397: tme_uint16_t value) ! 398: { ! 399: ! 400: /* possibly byteswap the value to write: */ ! 401: assert (am7990->tme_am7990_device.tme_bus_device_router != NULL); ! 402: if (am7990->tme_am7990_device.tme_bus_device_router ! 403: != (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE ! 404: ? tme_bus_device_router_16el ! 405: : tme_bus_device_router_16eb)) { ! 406: value = tme_bswap_u16(value); ! 407: } ! 408: ! 409: /* do the DMA write: */ ! 410: return (_tme_am7990_dma(am7990, ! 411: callout_flags, ! 412: _tme_am7990_dte_address(am7990, ! 413: callout_flags, ! 414: dte_offset), ! 415: sizeof(value), ! 416: (tme_uint8_t *) &value)); ! 417: } ! 418: #define _tme_am7990_tx_write(am7990, dte_offset, value) \ ! 419: _tme_am7990_write((am7990), TME_AM7990_CALLOUT_DMA_WRITE, (dte_offset), (value)) ! 420: #define _tme_am7990_rx_write(am7990, dte_offset, value) \ ! 421: _tme_am7990_write((am7990), TME_AM7990_CALLOUT_DMA_WRITE | TME_AM7990_CALLOUT_RECEIVE, (dte_offset), (value)) ! 422: ! 423: /* this initializes the am7990: */ ! 424: static void ! 425: _tme_am7990_init(struct tme_am7990 *am7990) ! 426: { ! 427: tme_uint32_t iadr; ! 428: int cancelled; ! 429: unsigned int init_i; ! 430: tme_uint16_t csr0; ! 431: tme_uint32_t drp; ! 432: ! 433: /* DMA in the initialization block: */ ! 434: iadr = am7990->tme_am7990_csrs[2]; ! 435: iadr = (iadr << 16) + am7990->tme_am7990_csrs[1]; ! 436: cancelled ! 437: = _tme_am7990_dma(am7990, ! 438: TME_AM7990_CALLOUT_DMA_READ, ! 439: iadr, ! 440: sizeof(am7990->tme_am7990_init), ! 441: (tme_uint8_t *) am7990->tme_am7990_init); ! 442: if (cancelled) { ! 443: return; ! 444: } ! 445: ! 446: /* possibly byteswap the 16-bit words of the initialization block: */ ! 447: assert (am7990->tme_am7990_device.tme_bus_device_router != NULL); ! 448: if (am7990->tme_am7990_device.tme_bus_device_router ! 449: != (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE ! 450: ? tme_bus_device_router_16el ! 451: : tme_bus_device_router_16eb)) { ! 452: for (init_i = 0; init_i < TME_ARRAY_ELS(am7990->tme_am7990_init); init_i++) { ! 453: am7990->tme_am7990_init[init_i] = tme_bswap_u16(am7990->tme_am7990_init[init_i]); ! 454: } ! 455: } ! 456: ! 457: /* the least significant byte of PADR is actually the "first" byte ! 458: of the Ethernet address as is is normally seen, but otherwise the ! 459: 16-bit words of PADR are in the correct order. so we only need ! 460: to swap those words into little-endian order: */ ! 461: (&am7990->tme_am7990_padr)[0] = tme_htole_u16((&am7990->tme_am7990_padr)[0]); ! 462: (&am7990->tme_am7990_padr)[1] = tme_htole_u16((&am7990->tme_am7990_padr)[1]); ! 463: (&am7990->tme_am7990_padr)[2] = tme_htole_u16((&am7990->tme_am7990_padr)[2]); ! 464: ! 465: tme_log(&am7990->tme_am7990_element->tme_element_log_handle, ! 466: 100, TME_OK, ! 467: (&am7990->tme_am7990_element->tme_element_log_handle, ! 468: "init CSR0 0x%04x IADR 0x%08x MODE 0x%04x", ! 469: (unsigned int) am7990->tme_am7990_csr0, ! 470: iadr, ! 471: (unsigned int) am7990->tme_am7990_mode)); ! 472: ! 473: /* get CSR0: */ ! 474: csr0 = am7990->tme_am7990_csr0; ! 475: ! 476: /* set IDON: */ ! 477: csr0 |= TME_AM7990_CSR0_IDON; ! 478: ! 479: /* "RXON is cleared when IDON is set from setting the INIT bit and ! 480: DRX = 1 in the MODE register" */ ! 481: if (am7990->tme_am7990_mode & TME_AM7990_MODE_DRX) { ! 482: csr0 &= ~TME_AM7990_CSR0_RXON; ! 483: } ! 484: ! 485: /* "TXON is cleared when IDON is set and DTX = 1 in the MODE ! 486: register" */ ! 487: if (am7990->tme_am7990_mode & TME_AM7990_MODE_DTX) { ! 488: csr0 &= ~TME_AM7990_CSR0_TXON; ! 489: } ! 490: ! 491: /* clear STOP: */ ! 492: csr0 &= ~TME_AM7990_CSR0_STOP; ! 493: ! 494: /* update CSR0: */ ! 495: am7990->tme_am7990_csr0 = csr0; ! 496: ! 497: /* call out an Ethernet configuration update: */ ! 498: am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_CONFIG; ! 499: ! 500: /* if we're not in internal loopback mode, and the Ethernet ! 501: connection is readable, call out an Ethernet receive: */ ! 502: if (!(am7990->tme_am7990_mode & TME_AM7990_MODE_INTL) ! 503: && (am7990->tme_am7990_ether_ctrl_in & TME_ETHERNET_CTRL_OK_READ)) { ! 504: am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_RECEIVE; ! 505: } ! 506: ! 507: /* initialize for the receive ring: */ ! 508: drp = am7990->tme_am7990_rlen_rdra; ! 509: drp = (drp << 16) | am7990->tme_am7990_rdra; ! 510: am7990->tme_am7990_receive_dte_address = drp & TME_AM7990_DRP_XDRA; ! 511: am7990->tme_am7990_receive_dte_index_mask = (1 << TME_FIELD_MASK_EXTRACTU(drp, TME_AM7990_DRP_XLEN_LOG2)) - 1; ! 512: am7990->tme_am7990_receive_dte_index = 0; ! 513: ! 514: /* initialize for the transmit ring: */ ! 515: drp = am7990->tme_am7990_tlen_tdra; ! 516: drp = (drp << 16) | am7990->tme_am7990_tdra; ! 517: am7990->tme_am7990_transmit_dte_address = drp & TME_AM7990_DRP_XDRA; ! 518: am7990->tme_am7990_transmit_dte_index_mask = (1 << TME_FIELD_MASK_EXTRACTU(drp, TME_AM7990_DRP_XLEN_LOG2)) - 1; ! 519: am7990->tme_am7990_transmit_dte_index = 0; ! 520: am7990->tme_am7990_transmit_dte_tmd1 = 0; ! 521: } ! 522: ! 523: /* this starts the am7990: */ ! 524: static void ! 525: _tme_am7990_start(struct tme_am7990 *am7990) ! 526: { ! 527: tme_uint16_t csr0; ! 528: ! 529: tme_log(&am7990->tme_am7990_element->tme_element_log_handle, ! 530: 100, TME_OK, ! 531: (&am7990->tme_am7990_element->tme_element_log_handle, ! 532: "start CSR0 0x%04x MODE 0x%04x", ! 533: (unsigned int) am7990->tme_am7990_csr0, ! 534: (unsigned int) am7990->tme_am7990_mode)); ! 535: ! 536: /* get CSR0: */ ! 537: csr0 = am7990->tme_am7990_csr0; ! 538: ! 539: /* "RXON is set when STRT is set if DRX = 0 in the MODE register" */ ! 540: if (!(am7990->tme_am7990_mode & TME_AM7990_MODE_DRX)) { ! 541: csr0 |= TME_AM7990_CSR0_RXON; ! 542: } ! 543: ! 544: /* "TXON is set when STRT is set if DTX = 0 in the MODE register" */ ! 545: if (!(am7990->tme_am7990_mode & TME_AM7990_MODE_DTX)) { ! 546: csr0 |= TME_AM7990_CSR0_TXON; ! 547: } ! 548: ! 549: /* clear STOP: */ ! 550: csr0 &= ~TME_AM7990_CSR0_STOP; ! 551: ! 552: /* update CSR0: */ ! 553: am7990->tme_am7990_csr0 = csr0; ! 554: } ! 555: ! 556: /* this scans for a start-of-packet transmit buffer owned by us: */ ! 557: static void ! 558: _tme_am7990_transmit_scan(struct tme_am7990 *am7990) ! 559: { ! 560: tme_uint16_t transmit_dte_tmd1; ! 561: int cancelled; ! 562: ! 563: /* if the transmitter is not on, return now: */ ! 564: if (!(am7990->tme_am7990_csr0 & TME_AM7990_CSR0_TXON)) { ! 565: return; ! 566: } ! 567: ! 568: /* clear TDMD: */ ! 569: am7990->tme_am7990_csr0 &= ~TME_AM7990_CSR0_TDMD; ! 570: ! 571: /* loop forever: */ ! 572: for (;;) { ! 573: ! 574: /* if we own the current transmit buffer: */ ! 575: transmit_dte_tmd1 = am7990->tme_am7990_transmit_dte_tmd1; ! 576: if (transmit_dte_tmd1 & TME_AM7990_XMD1_OWN) { ! 577: ! 578: /* if the current transmit buffer is also for the start of a ! 579: packet, return now: */ ! 580: if (transmit_dte_tmd1 & TME_AM7990_XMD1_STP) { ! 581: return; ! 582: } ! 583: ! 584: /* write TMD1 to clear OWN: */ ! 585: cancelled ! 586: = _tme_am7990_tx_write(am7990, ! 587: TME_AM7990_DTE_OFFSET_XMD1, ! 588: (transmit_dte_tmd1 ! 589: & ~TME_AM7990_XMD1_OWN)); ! 590: if (cancelled) { ! 591: return; ! 592: } ! 593: ! 594: /* advance to the next transmit buffer and request a transmit ! 595: interrupt: */ ! 596: am7990->tme_am7990_transmit_dte_index ! 597: = ((am7990->tme_am7990_transmit_dte_index ! 598: + 1) ! 599: & am7990->tme_am7990_transmit_dte_index_mask); ! 600: am7990->tme_am7990_transmit_dte_tmd1 = 0; ! 601: am7990->tme_am7990_csr0 |= TME_AM7990_CSR0_TINT; ! 602: } ! 603: ! 604: /* otherwise, we must not own the current transmit buffer: */ ! 605: else { ! 606: ! 607: /* read TMD1: */ ! 608: transmit_dte_tmd1 ! 609: = _tme_am7990_tx_read(am7990, ! 610: TME_AM7990_DTE_OFFSET_XMD1, ! 611: &cancelled); ! 612: if (cancelled) { ! 613: return; ! 614: } ! 615: am7990->tme_am7990_transmit_dte_tmd1 = transmit_dte_tmd1; ! 616: ! 617: /* if we still don't own the current transmit buffer, return now: */ ! 618: if (!(transmit_dte_tmd1 & TME_AM7990_XMD1_OWN)) { ! 619: return; ! 620: } ! 621: } ! 622: } ! 623: /* NOTREACHED */ ! 624: } ! 625: ! 626: /* this receives a frame: */ ! 627: static void ! 628: _tme_am7990_receive(struct tme_am7990 *am7990) ! 629: { ! 630: struct tme_ethernet_frame_chunk frame_chunk_buffer; ! 631: struct tme_ethernet_connection *conn_eth; ! 632: tme_ethernet_fid_t frame_id; ! 633: int resid; ! 634: tme_uint8_t *frame_chunk_bytes; ! 635: unsigned int frame_chunk_bytes_count; ! 636: struct tme_ethernet_header *ether_header; ! 637: tme_uint32_t crc32; ! 638: tme_uint16_t receive_dte_rmd0; ! 639: tme_uint16_t receive_dte_rmd1; ! 640: tme_uint16_t receive_dte_rmd2; ! 641: tme_uint16_t receive_dte_rmd1_next; ! 642: tme_uint32_t receive_buffer_address; ! 643: tme_uint16_t receive_buffer_count; ! 644: int cancelled; ! 645: int stop; ! 646: ! 647: /* assume that there is no loopback packet: */ ! 648: resid = 0; ! 649: ! 650: /* if we're in loopback mode: */ ! 651: if (am7990->tme_am7990_mode & TME_AM7990_MODE_LOOP) { ! 652: ! 653: /* get and clear any loopback packet length: */ ! 654: resid = am7990->tme_am7990_receive_buffer_length; ! 655: am7990->tme_am7990_receive_buffer_length = 0; ! 656: ! 657: /* "The C-LANCE will not receive any packets externally when it is ! 658: in internal loopback mode." */ ! 659: if (resid == 0 ! 660: && (am7990->tme_am7990_mode & TME_AM7990_MODE_INTL)) { ! 661: return; ! 662: } ! 663: } ! 664: ! 665: /* if there isn't any loopback packet, and the Ethernet connection ! 666: is not readable, return now: */ ! 667: if (resid == 0 ! 668: && !(am7990->tme_am7990_ether_ctrl_in & TME_ETHERNET_CTRL_OK_READ)) { ! 669: return; ! 670: } ! 671: ! 672: /* receive the packet into the internal buffer: */ ! 673: frame_chunk_buffer.tme_ethernet_frame_chunk_next = NULL; ! 674: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes_count = sizeof(am7990->tme_am7990_receive_buffer); ! 675: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes = &am7990->tme_am7990_receive_buffer[0]; ! 676: ! 677: /* if there isn't any loopback packet: */ ! 678: if (resid == 0) { ! 679: ! 680: /* assume that the Ethernet read will fail: */ ! 681: am7990->tme_am7990_ether_ctrl_in &= ~TME_ETHERNET_CTRL_OK_READ; ! 682: ! 683: /* get the Ethernet connection: */ ! 684: conn_eth = am7990->tme_am7990_eth_connection; ! 685: ! 686: /* unlock the mutex: */ ! 687: tme_mutex_unlock(&am7990->tme_am7990_mutex); ! 688: ! 689: /* do the callout: */ ! 690: resid = (conn_eth == NULL ! 691: ? 0 ! 692: : ((*conn_eth->tme_ethernet_connection_read) ! 693: (conn_eth, ! 694: &frame_id, ! 695: &frame_chunk_buffer, ! 696: TME_ETHERNET_READ_NEXT))); ! 697: ! 698: /* lock the mutex: */ ! 699: tme_mutex_lock(&am7990->tme_am7990_mutex); ! 700: ! 701: /* if the read failed, return now: */ ! 702: if (resid <= 0) { ! 703: return; ! 704: } ! 705: ! 706: /* assume that the Ethernet connection is still readable: */ ! 707: am7990->tme_am7990_ether_ctrl_in |= TME_ETHERNET_CTRL_OK_READ; ! 708: ! 709: /* append four dummy CRC bytes: */ ! 710: resid = TME_MIN((unsigned int) resid + TME_ETHERNET_CRC_SIZE, ! 711: sizeof(am7990->tme_am7990_receive_buffer)); ! 712: } ! 713: ! 714: /* assume that we should callout another receive after this one: */ ! 715: am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_RECEIVE; ! 716: ! 717: /* if the receiver is not on, return now: */ ! 718: if (!(am7990->tme_am7990_csr0 & TME_AM7990_CSR0_RXON)) { ! 719: return; ! 720: } ! 721: ! 722: /* if this packet is not addressed to our physical address: */ ! 723: ether_header = (struct tme_ethernet_header *) &am7990->tme_am7990_receive_buffer[0]; ! 724: if (memcmp(ðer_header->tme_ethernet_header_dst[0], ! 725: &am7990->tme_am7990_padr, ! 726: TME_ETHERNET_ADDR_SIZE) != 0) { ! 727: ! 728: /* if this is not a multicast packet, return now: */ ! 729: if (!(ether_header->tme_ethernet_header_dst[0] & 0x1)) { ! 730: return; ! 731: } ! 732: ! 733: /* if this is not a broadcast packet: */ ! 734: if (memcmp(ðer_header->tme_ethernet_header_dst[0], ! 735: &tme_ethernet_addr_broadcast[0], ! 736: TME_ETHERNET_ADDR_SIZE) != 0) { ! 737: ! 738: /* calculate the CRC of the destination address: */ ! 739: crc32 = tme_ethernet_crc32_el(ðer_header->tme_ethernet_header_dst[0], ! 740: TME_ETHERNET_ADDR_SIZE); ! 741: ! 742: /* the am7990 only uses the most significant six bits of the CRC: */ ! 743: crc32 >>= (32 - 6); ! 744: ! 745: /* if the bit in the logical address filter is clear, return now: */ ! 746: if (((&am7990->tme_am7990_ladrf)[crc32 / (8 * sizeof(am7990->tme_am7990_ladrf))] ! 747: & TME_BIT(crc32 % (8 * sizeof(am7990->tme_am7990_ladrf)))) == 0) { ! 748: return; ! 749: } ! 750: } ! 751: } ! 752: ! 753: /* read RMD1: */ ! 754: receive_dte_rmd1 ! 755: = _tme_am7990_rx_read(am7990, ! 756: TME_AM7990_DTE_OFFSET_XMD1, ! 757: &cancelled); ! 758: if (cancelled) { ! 759: return; ! 760: } ! 761: ! 762: /* if we don't own this receive buffer: */ ! 763: if (!(receive_dte_rmd1 & TME_AM7990_XMD1_OWN)) { ! 764: ! 765: if ((am7990->tme_am7990_csr0 & TME_AM7990_CSR0_MISS) == 0) { ! 766: tme_log(&am7990->tme_am7990_element->tme_element_log_handle, ! 767: 500, TME_OK, ! 768: (&am7990->tme_am7990_element->tme_element_log_handle, ! 769: "receive MISS")); ! 770: } ! 771: ! 772: /* set MISS in CSR0 and return now: */ ! 773: am7990->tme_am7990_csr0 |= TME_AM7990_CSR0_MISS; ! 774: return; ! 775: } ! 776: ! 777: /* set STP in RMD1: */ ! 778: receive_dte_rmd1 |= TME_AM7990_XMD1_STP; ! 779: ! 780: /* while we have bytes to write: */ ! 781: frame_chunk_bytes = &am7990->tme_am7990_receive_buffer[0]; ! 782: frame_chunk_bytes_count = resid; ! 783: do { ! 784: ! 785: /* read RMD0 and RMD2: */ ! 786: receive_dte_rmd0 ! 787: = _tme_am7990_rx_read(am7990, ! 788: TME_AM7990_DTE_OFFSET_XMD0, ! 789: &cancelled); ! 790: if (cancelled) { ! 791: break; ! 792: } ! 793: receive_dte_rmd2 ! 794: = _tme_am7990_rx_read(am7990, ! 795: TME_AM7990_DTE_OFFSET_XMD2, ! 796: &cancelled); ! 797: if (cancelled) { ! 798: break; ! 799: } ! 800: ! 801: /* get the receive buffer address and count: */ ! 802: receive_buffer_address = (receive_dte_rmd1 & TME_AM7990_XMD1_HADR); ! 803: receive_buffer_address = (receive_buffer_address << 16) + receive_dte_rmd0; ! 804: receive_buffer_count = (0 - receive_dte_rmd2) & TME_AM7990_XMD2_BCNT; ! 805: ! 806: /* get the count of bytes to write in this iteration: */ ! 807: receive_buffer_count = TME_MIN(frame_chunk_bytes_count, receive_buffer_count); ! 808: ! 809: /* do the write: */ ! 810: cancelled ! 811: = _tme_am7990_dma(am7990, ! 812: (TME_AM7990_CALLOUT_DMA_WRITE ! 813: | TME_AM7990_CALLOUT_RECEIVE), ! 814: receive_buffer_address, ! 815: receive_buffer_count, ! 816: frame_chunk_bytes); ! 817: if (cancelled) { ! 818: break; ! 819: } ! 820: ! 821: /* advance: */ ! 822: frame_chunk_bytes += receive_buffer_count; ! 823: frame_chunk_bytes_count -= receive_buffer_count; ! 824: ! 825: /* if this is the last buffer for this packet: */ ! 826: if (frame_chunk_bytes_count == 0) { ! 827: ! 828: /* write RMD3 to set MCNT: */ ! 829: cancelled ! 830: = _tme_am7990_rx_write(am7990, ! 831: TME_AM7990_DTE_OFFSET_XMD3, ! 832: (unsigned int) resid); ! 833: if (cancelled) { ! 834: break; ! 835: } ! 836: ! 837: /* set ENP in RMD1: */ ! 838: receive_dte_rmd1 |= TME_AM7990_XMD1_ENP; ! 839: ! 840: /* we don't read RMD1 for the next receive buffer: */ ! 841: receive_dte_rmd1_next = 0; ! 842: ! 843: /* stop now: */ ! 844: stop = TRUE; ! 845: } ! 846: ! 847: /* otherwise, this is not the last buffer for this packet: */ ! 848: else { ! 849: ! 850: /* read RMD1 for the next transmit buffer: */ ! 851: receive_dte_rmd1_next ! 852: = _tme_am7990_rx_read(am7990, ! 853: (TME_AM7990_DTE_SIZE ! 854: + TME_AM7990_DTE_OFFSET_XMD1), ! 855: &cancelled); ! 856: if (cancelled) { ! 857: break; ! 858: } ! 859: ! 860: /* if we don't own the next buffer: */ ! 861: stop = !(receive_dte_rmd1_next & TME_AM7990_XMD1_OWN); ! 862: if (stop) { ! 863: ! 864: tme_log(&am7990->tme_am7990_element->tme_element_log_handle, ! 865: 500, TME_OK, ! 866: (&am7990->tme_am7990_element->tme_element_log_handle, ! 867: "receive BUFF")); ! 868: ! 869: /* set BUFF and ERR in RMD1: */ ! 870: receive_dte_rmd1 |= TME_AM7990_RMD1_BUFF | TME_AM7990_XMD1_ERR; ! 871: } ! 872: } ! 873: ! 874: /* write RMD1 to clear OWN: */ ! 875: cancelled ! 876: = _tme_am7990_rx_write(am7990, ! 877: TME_AM7990_DTE_OFFSET_XMD1, ! 878: (receive_dte_rmd1 ! 879: & ~TME_AM7990_XMD1_OWN)); ! 880: if (cancelled) { ! 881: break; ! 882: } ! 883: ! 884: /* advance to the next receive buffer: */ ! 885: am7990->tme_am7990_receive_dte_index ! 886: = ((am7990->tme_am7990_receive_dte_index ! 887: + 1) ! 888: & am7990->tme_am7990_receive_dte_index_mask); ! 889: receive_dte_rmd1 = receive_dte_rmd1_next; ! 890: } while (!stop); ! 891: ! 892: /* if nothing was cancelled: */ ! 893: if (!cancelled) { ! 894: ! 895: /* generate a receive interrupt: */ ! 896: am7990->tme_am7990_csr0 |= TME_AM7990_CSR0_RINT; ! 897: } ! 898: } ! 899: ! 900: /* the am7990 callout function. it must be called with the mutex locked: */ ! 901: static void ! 902: _tme_am7990_callout(struct tme_am7990 *am7990) ! 903: { ! 904: struct tme_ethernet_connection *conn_eth; ! 905: struct tme_ethernet_connection conn_eth_buffer; ! 906: struct tme_bus_connection *conn_bus; ! 907: unsigned int ctrl; ! 908: struct tme_ethernet_config config; ! 909: const tme_uint8_t *config_addrs[2]; ! 910: int again; ! 911: int rc; ! 912: int int_asserted; ! 913: ! 914: /* if this function is already running in another thread, simply ! 915: return now. the other thread will do our work: */ ! 916: if (am7990->tme_am7990_callout_flags & TME_AM7990_CALLOUTS_RUNNING) { ! 917: return; ! 918: } ! 919: ! 920: /* callouts are now running: */ ! 921: am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUTS_RUNNING; ! 922: ! 923: /* loop while we have work to do: */ ! 924: do { ! 925: again = FALSE; ! 926: ! 927: /* if we need to do a transmit scan: */ ! 928: if (am7990->tme_am7990_callout_flags & TME_AM7990_CALLOUT_TRANSMIT_SCAN) { ! 929: again = TRUE; ! 930: ! 931: /* clear the callout flag: */ ! 932: am7990->tme_am7990_callout_flags &= ~TME_AM7990_CALLOUT_TRANSMIT_SCAN; ! 933: ! 934: /* do the transmit scan: */ ! 935: _tme_am7990_transmit_scan(am7990); ! 936: } ! 937: ! 938: /* form our ctrl: */ ! 939: ctrl = 0; ! 940: ! 941: /* if the transmitter is on and the next transmit buffer is for ! 942: the start of a packet and is owned by us, we are readable: */ ! 943: if ((am7990->tme_am7990_csr0 ! 944: & TME_AM7990_CSR0_TXON) ! 945: && ((am7990->tme_am7990_transmit_dte_tmd1 ! 946: & (TME_AM7990_XMD1_OWN ! 947: | TME_AM7990_XMD1_STP)) ! 948: == (TME_AM7990_XMD1_OWN ! 949: | TME_AM7990_XMD1_STP))) { ! 950: ctrl |= TME_ETHERNET_CTRL_OK_READ; ! 951: } ! 952: ! 953: /* if we are readable and in loopback mode: */ ! 954: if ((ctrl & TME_ETHERNET_CTRL_OK_READ) ! 955: && (am7990->tme_am7990_mode & TME_AM7990_MODE_LOOP)) { ! 956: again = TRUE; ! 957: ! 958: /* unlock the mutex: */ ! 959: tme_mutex_unlock(&am7990->tme_am7990_mutex); ! 960: ! 961: /* call out a loopback transmit: */ ! 962: conn_eth_buffer.tme_ethernet_connection.tme_connection_element = am7990->tme_am7990_element; ! 963: _tme_am7990_transmit(&conn_eth_buffer, ! 964: NULL, ! 965: NULL, ! 966: 0); ! 967: ! 968: /* lock the mutex: */ ! 969: tme_mutex_lock(&am7990->tme_am7990_mutex); ! 970: ! 971: /* don't call out any new control information for now: */ ! 972: ctrl = am7990->tme_am7990_ether_ctrl_out; ! 973: } ! 974: ! 975: /* if we need to call out new control information: */ ! 976: if (am7990->tme_am7990_ether_ctrl_out != ctrl) { ! 977: again = TRUE; ! 978: ! 979: /* note the new state of the called-out control information: */ ! 980: am7990->tme_am7990_ether_ctrl_out = ctrl; ! 981: ! 982: /* get this card's connection: */ ! 983: conn_eth = am7990->tme_am7990_eth_connection; ! 984: ! 985: /* unlock the mutex: */ ! 986: tme_mutex_unlock(&am7990->tme_am7990_mutex); ! 987: ! 988: /* do the callout: */ ! 989: rc = (conn_eth != NULL ! 990: ? ((*conn_eth->tme_ethernet_connection_ctrl) ! 991: (conn_eth, ! 992: ctrl)) ! 993: : TME_OK); ! 994: assert (rc == TME_OK); ! 995: ! 996: /* lock the mutex: */ ! 997: tme_mutex_lock(&am7990->tme_am7990_mutex); ! 998: } ! 999: ! 1000: /* if we need to call out new config information: */ ! 1001: if (am7990->tme_am7990_callout_flags & TME_AM7990_CALLOUT_CONFIG) { ! 1002: again = TRUE; ! 1003: ! 1004: /* clear the callout flag: */ ! 1005: am7990->tme_am7990_callout_flags &= ~TME_AM7990_CALLOUT_CONFIG; ! 1006: ! 1007: /* form the new config: */ ! 1008: memset(&config, 0, sizeof(config)); ! 1009: ! 1010: /* if we're in promiscuous mode or any bits the logical address ! 1011: filter are nonzero: */ ! 1012: if ((am7990->tme_am7990_mode & TME_AM7990_MODE_PROM) ! 1013: || (&am7990->tme_am7990_ladrf)[0] ! 1014: || (&am7990->tme_am7990_ladrf)[1] ! 1015: || (&am7990->tme_am7990_ladrf)[2] ! 1016: || (&am7990->tme_am7990_ladrf)[3]) { ! 1017: ! 1018: /* we have to be in promiscuous mode: */ ! 1019: config.tme_ethernet_config_flags |= TME_ETHERNET_CONFIG_PROMISC; ! 1020: } ! 1021: ! 1022: /* otherwise, we only need to see packets addressed to our ! 1023: physical address, and broadcast packets: */ ! 1024: else { ! 1025: ! 1026: /* our Ethernet addresses: */ ! 1027: config.tme_ethernet_config_addr_count = 2; ! 1028: config_addrs[0] = (tme_uint8_t *) &am7990->tme_am7990_padr; ! 1029: config_addrs[1] = &tme_ethernet_addr_broadcast[0]; ! 1030: config.tme_ethernet_config_addrs = config_addrs; ! 1031: } ! 1032: ! 1033: /* get this card's connection: */ ! 1034: conn_eth = am7990->tme_am7990_eth_connection; ! 1035: ! 1036: /* unlock the mutex: */ ! 1037: tme_mutex_unlock(&am7990->tme_am7990_mutex); ! 1038: ! 1039: /* do the callout: */ ! 1040: rc = (conn_eth == NULL ! 1041: ? TME_OK ! 1042: : ((*conn_eth->tme_ethernet_connection_config) ! 1043: (conn_eth, ! 1044: &config))); ! 1045: assert (rc == TME_OK); ! 1046: ! 1047: /* lock the mutex: */ ! 1048: tme_mutex_lock(&am7990->tme_am7990_mutex); ! 1049: } ! 1050: ! 1051: /* if we need to receive a frame: */ ! 1052: if (am7990->tme_am7990_callout_flags & TME_AM7990_CALLOUT_RECEIVE) { ! 1053: again = TRUE; ! 1054: ! 1055: /* clear the callout flag: */ ! 1056: am7990->tme_am7990_callout_flags &= ~TME_AM7990_CALLOUT_RECEIVE; ! 1057: ! 1058: /* do the receive: */ ! 1059: _tme_am7990_receive(am7990); ! 1060: } ! 1061: ! 1062: /* if we need to call out an interrupt: */ ! 1063: if (am7990->tme_am7990_csr0 ! 1064: & (TME_AM7990_CSR0_TINT ! 1065: | TME_AM7990_CSR0_BABL ! 1066: | TME_AM7990_CSR0_MISS ! 1067: | TME_AM7990_CSR0_MERR ! 1068: | TME_AM7990_CSR0_RINT ! 1069: | TME_AM7990_CSR0_TINT ! 1070: | TME_AM7990_CSR0_IDON)) { ! 1071: am7990->tme_am7990_csr0 |= TME_AM7990_CSR0_INTR; ! 1072: } ! 1073: else { ! 1074: am7990->tme_am7990_csr0 &= ~TME_AM7990_CSR0_INTR; ! 1075: } ! 1076: int_asserted ! 1077: = ((am7990->tme_am7990_csr0 ! 1078: & (TME_AM7990_CSR0_INTR ! 1079: | TME_AM7990_CSR0_INEA)) ! 1080: == (TME_AM7990_CSR0_INTR ! 1081: | TME_AM7990_CSR0_INEA)); ! 1082: if (!!am7990->tme_am7990_int_asserted != int_asserted) { ! 1083: again = TRUE; ! 1084: ! 1085: /* note the new state of the interrupt signal: */ ! 1086: am7990->tme_am7990_int_asserted = int_asserted; ! 1087: ! 1088: /* get our bus connection: */ ! 1089: conn_bus = tme_memory_atomic_pointer_read(struct tme_bus_connection *, ! 1090: am7990->tme_am7990_device.tme_bus_device_connection, ! 1091: &am7990->tme_am7990_device.tme_bus_device_connection_rwlock); ! 1092: ! 1093: /* unlock our mutex: */ ! 1094: tme_mutex_unlock(&am7990->tme_am7990_mutex); ! 1095: ! 1096: /* call out the bus interrupt signal edge: */ ! 1097: rc = (*conn_bus->tme_bus_signal) ! 1098: (conn_bus, ! 1099: TME_BUS_SIGNAL_INT_UNSPEC ! 1100: | (int_asserted ! 1101: ? TME_BUS_SIGNAL_LEVEL_ASSERTED ! 1102: : TME_BUS_SIGNAL_LEVEL_NEGATED)); ! 1103: assert (rc == TME_OK); ! 1104: ! 1105: /* lock our mutex: */ ! 1106: tme_mutex_lock(&am7990->tme_am7990_mutex); ! 1107: } ! 1108: } while (again); ! 1109: ! 1110: /* clear that callouts are running: */ ! 1111: am7990->tme_am7990_callout_flags &= ~TME_AM7990_CALLOUTS_RUNNING; ! 1112: } ! 1113: ! 1114: /* the am7990 bus signal handler: */ ! 1115: static int ! 1116: _tme_am7990_signal(void *_am7990, ! 1117: unsigned int signal) ! 1118: { ! 1119: struct tme_am7990 *am7990; ! 1120: unsigned int level; ! 1121: ! 1122: /* recover our data structure: */ ! 1123: am7990 = (struct tme_am7990 *) _am7990; ! 1124: ! 1125: /* lock the mutex: */ ! 1126: tme_mutex_lock(&am7990->tme_am7990_mutex); ! 1127: ! 1128: /* take out the signal level: */ ! 1129: level = signal & TME_BUS_SIGNAL_LEVEL_MASK; ! 1130: signal = TME_BUS_SIGNAL_WHICH(signal); ! 1131: ! 1132: /* dispatch on the generic bus signals: */ ! 1133: switch (signal) { ! 1134: case TME_BUS_SIGNAL_RESET: ! 1135: if (level == TME_BUS_SIGNAL_LEVEL_ASSERTED) { ! 1136: _tme_am7990_reset(am7990); ! 1137: } ! 1138: break; ! 1139: default: ! 1140: signal = TME_BUS_SIGNAL_IGNORE; ! 1141: break; ! 1142: } ! 1143: ! 1144: /* if we didn't ignore this bus signal: */ ! 1145: if (signal != TME_BUS_SIGNAL_IGNORE) { ! 1146: ! 1147: /* make any new callouts: */ ! 1148: _tme_am7990_callout(am7990); ! 1149: } ! 1150: ! 1151: /* unlock the mutex: */ ! 1152: tme_mutex_unlock(&am7990->tme_am7990_mutex); ! 1153: ! 1154: /* no faults: */ ! 1155: return (TME_OK); ! 1156: } ! 1157: ! 1158: /* this is called when a device changes its configuration: */ ! 1159: static int ! 1160: _tme_am7990_config(struct tme_ethernet_connection *conn_eth, ! 1161: struct tme_ethernet_config *config) ! 1162: { ! 1163: /* we don't care when other devices on the Ethernet ! 1164: reconfigure themselves: */ ! 1165: return (TME_OK); ! 1166: } ! 1167: ! 1168: /* this is called when control lines change: */ ! 1169: static int ! 1170: _tme_am7990_ctrl(struct tme_ethernet_connection *conn_eth, ! 1171: unsigned int ctrl) ! 1172: { ! 1173: struct tme_am7990 *am7990; ! 1174: ! 1175: /* recover our data structures: */ ! 1176: am7990 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private; ! 1177: ! 1178: /* lock the mutex: */ ! 1179: tme_mutex_lock(&am7990->tme_am7990_mutex); ! 1180: ! 1181: /* note the new state of the controls: */ ! 1182: am7990->tme_am7990_ether_ctrl_in = ctrl; ! 1183: ! 1184: /* if this connection is readable, call out a read: */ ! 1185: if (ctrl & TME_ETHERNET_CTRL_OK_READ) { ! 1186: am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_RECEIVE; ! 1187: } ! 1188: ! 1189: /* make any new callouts: */ ! 1190: _tme_am7990_callout(am7990); ! 1191: ! 1192: /* unlock the mutex: */ ! 1193: tme_mutex_unlock(&am7990->tme_am7990_mutex); ! 1194: ! 1195: return (TME_OK); ! 1196: } ! 1197: ! 1198: /* this transmits a frame: */ ! 1199: static int ! 1200: _tme_am7990_transmit(struct tme_ethernet_connection *conn_eth, ! 1201: tme_ethernet_fid_t *_frame_id, ! 1202: struct tme_ethernet_frame_chunk *frame_chunk, ! 1203: unsigned int flags) ! 1204: { ! 1205: struct tme_am7990 *am7990; ! 1206: struct tme_ethernet_frame_chunk frame_chunk_buffer; ! 1207: tme_uint8_t frame_chunk_bytes_buffer[32]; ! 1208: tme_uint8_t *frame_chunk_bytes; ! 1209: unsigned int frame_chunk_bytes_count; ! 1210: tme_uint16_t transmit_dte_tmd0; ! 1211: tme_uint16_t transmit_dte_tmd1; ! 1212: tme_uint16_t transmit_dte_tmd2; ! 1213: tme_uint16_t transmit_dte_tmd1_next; ! 1214: tme_uint32_t transmit_buffer_address; ! 1215: tme_uint16_t transmit_buffer_count; ! 1216: unsigned int count; ! 1217: int rc; ! 1218: int add_fcs; ! 1219: int stop; ! 1220: int cancelled; ! 1221: ! 1222: /* recover our data structures: */ ! 1223: am7990 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private; ! 1224: ! 1225: /* lock our mutex: */ ! 1226: tme_mutex_lock(&am7990->tme_am7990_mutex); ! 1227: ! 1228: /* assume that we will have no packet to transmit: */ ! 1229: rc = 0; ! 1230: ! 1231: /* if the transmitter is on, and the current transmit buffer is for ! 1232: the start of a packet and is owned by us: */ ! 1233: if ((am7990->tme_am7990_csr0 ! 1234: & TME_AM7990_CSR0_TXON) ! 1235: && ((am7990->tme_am7990_transmit_dte_tmd1 ! 1236: & (TME_AM7990_XMD1_OWN ! 1237: | TME_AM7990_XMD1_STP)) ! 1238: == (TME_AM7990_XMD1_OWN ! 1239: | TME_AM7990_XMD1_STP))) { ! 1240: ! 1241: /* see if we will add the FCS to this transmitted packet. ! 1242: "ADD_FCS is only valid when STP=1." */ ! 1243: add_fcs = ! 1244: (!(am7990->tme_am7990_mode ! 1245: & TME_AM7990_MODE_DTCR) ! 1246: || (am7990->tme_am7990_transmit_dte_tmd1 ! 1247: & TME_AM7990_TMD1_ADD_FCS)); ! 1248: ! 1249: /* if we're in loopback mode, transmit this packet directly into ! 1250: the receive buffer: */ ! 1251: if (am7990->tme_am7990_mode & TME_AM7990_MODE_LOOP) { ! 1252: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes = &am7990->tme_am7990_receive_buffer[0]; ! 1253: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes_count = sizeof(am7990->tme_am7990_receive_buffer); ! 1254: frame_chunk_buffer.tme_ethernet_frame_chunk_next = NULL; ! 1255: frame_chunk = &frame_chunk_buffer; ! 1256: } ! 1257: ! 1258: do { ! 1259: ! 1260: /* recover the previously read TMD1: */ ! 1261: transmit_dte_tmd1 = am7990->tme_am7990_transmit_dte_tmd1; ! 1262: ! 1263: /* read TMD0 and TMD2: */ ! 1264: transmit_dte_tmd0 ! 1265: = _tme_am7990_tx_read(am7990, ! 1266: TME_AM7990_DTE_OFFSET_XMD0, ! 1267: &cancelled); ! 1268: if (cancelled) { ! 1269: break; ! 1270: } ! 1271: transmit_dte_tmd2 ! 1272: = _tme_am7990_tx_read(am7990, ! 1273: TME_AM7990_DTE_OFFSET_XMD2, ! 1274: &cancelled); ! 1275: if (cancelled) { ! 1276: break; ! 1277: } ! 1278: ! 1279: /* get the transmit buffer address and count: */ ! 1280: transmit_buffer_address = (transmit_dte_tmd1 & TME_AM7990_XMD1_HADR); ! 1281: transmit_buffer_address = (transmit_buffer_address << 16) + transmit_dte_tmd0; ! 1282: transmit_buffer_count = (0 - transmit_dte_tmd2) & TME_AM7990_XMD2_BCNT; ! 1283: ! 1284: /* read this transmit buffer into the frame chunks: */ ! 1285: frame_chunk_bytes = NULL; ! 1286: frame_chunk_bytes_count = 0; ! 1287: for (; transmit_buffer_count > 0; ) { ! 1288: ! 1289: /* if we have exhausted the previous chunk: */ ! 1290: if (frame_chunk_bytes_count == 0) { ! 1291: ! 1292: /* advance to the next chunk: */ ! 1293: if (frame_chunk == NULL) { ! 1294: frame_chunk_bytes = &frame_chunk_bytes_buffer[0]; ! 1295: frame_chunk_bytes_count = sizeof(frame_chunk_bytes_buffer); ! 1296: } ! 1297: else { ! 1298: frame_chunk_bytes = frame_chunk->tme_ethernet_frame_chunk_bytes; ! 1299: frame_chunk_bytes_count = frame_chunk->tme_ethernet_frame_chunk_bytes_count; ! 1300: frame_chunk = frame_chunk->tme_ethernet_frame_chunk_next; ! 1301: continue; ! 1302: } ! 1303: } ! 1304: ! 1305: /* get the count of bytes to read in this iteration: */ ! 1306: count = TME_MIN(frame_chunk_bytes_count, transmit_buffer_count); ! 1307: ! 1308: /* do the read: */ ! 1309: cancelled ! 1310: = _tme_am7990_dma(am7990, ! 1311: TME_AM7990_CALLOUT_DMA_READ, ! 1312: transmit_buffer_address, ! 1313: count, ! 1314: frame_chunk_bytes); ! 1315: if (cancelled) { ! 1316: break; ! 1317: } ! 1318: ! 1319: /* advance: */ ! 1320: frame_chunk_bytes += count; ! 1321: frame_chunk_bytes_count -= count; ! 1322: transmit_buffer_address += count; ! 1323: transmit_buffer_count -= count; ! 1324: rc += count; ! 1325: } ! 1326: if (cancelled) { ! 1327: break; ! 1328: } ! 1329: ! 1330: /* if this is the last transmit buffer in the packet: */ ! 1331: if (transmit_dte_tmd1 & TME_AM7990_XMD1_ENP) { ! 1332: ! 1333: /* we can't suppress CRC generation: */ ! 1334: if (!add_fcs) { ! 1335: abort(); ! 1336: } ! 1337: ! 1338: /* clear TMD1 for the next transmit buffer: */ ! 1339: transmit_dte_tmd1_next = 0; ! 1340: ! 1341: /* this is the last transmit buffer: */ ! 1342: stop = TRUE; ! 1343: } ! 1344: ! 1345: /* otherwise, this is not the last transmit buffer in the packet: */ ! 1346: else { ! 1347: ! 1348: /* read TMD1 for the next transmit buffer: */ ! 1349: transmit_dte_tmd1_next ! 1350: = _tme_am7990_tx_read(am7990, ! 1351: (TME_AM7990_DTE_SIZE ! 1352: + TME_AM7990_DTE_OFFSET_XMD1), ! 1353: &cancelled); ! 1354: if (cancelled) { ! 1355: break; ! 1356: } ! 1357: ! 1358: /* if we don't own the next transmit buffer: */ ! 1359: stop = !(transmit_dte_tmd1_next & TME_AM7990_XMD1_OWN); ! 1360: if (stop) { ! 1361: ! 1362: tme_log(&am7990->tme_am7990_element->tme_element_log_handle, ! 1363: 500, TME_OK, ! 1364: (&am7990->tme_am7990_element->tme_element_log_handle, ! 1365: "transmit BUFF")); ! 1366: ! 1367: /* write a TMD3 with BUFF set: */ ! 1368: cancelled ! 1369: = _tme_am7990_tx_write(am7990, ! 1370: TME_AM7990_DTE_OFFSET_XMD3, ! 1371: TME_AM7990_TMD3_BUFF); ! 1372: if (cancelled) { ! 1373: break; ! 1374: } ! 1375: ! 1376: /* turn off the transmitter: */ ! 1377: am7990->tme_am7990_csr0 &= ~TME_AM7990_CSR0_TXON; ! 1378: } ! 1379: } ! 1380: ! 1381: /* write TMD1 to clear OWN: */ ! 1382: cancelled ! 1383: = _tme_am7990_tx_write(am7990, ! 1384: TME_AM7990_DTE_OFFSET_XMD1, ! 1385: (transmit_dte_tmd1 ! 1386: & ~TME_AM7990_XMD1_OWN)); ! 1387: if (cancelled) { ! 1388: break; ! 1389: } ! 1390: ! 1391: /* advance to the next transmit buffer: */ ! 1392: am7990->tme_am7990_transmit_dte_index ! 1393: = ((am7990->tme_am7990_transmit_dte_index ! 1394: + 1) ! 1395: & am7990->tme_am7990_transmit_dte_index_mask); ! 1396: am7990->tme_am7990_transmit_dte_tmd1 = transmit_dte_tmd1_next; ! 1397: } while (!stop); ! 1398: ! 1399: /* if nothing was cancelled: */ ! 1400: if (!cancelled) { ! 1401: ! 1402: /* generate a transmit interrupt: */ ! 1403: am7990->tme_am7990_csr0 |= TME_AM7990_CSR0_TINT; ! 1404: } ! 1405: } ! 1406: ! 1407: /* if we're in loopback mode: */ ! 1408: if (am7990->tme_am7990_mode & TME_AM7990_MODE_LOOP) { ! 1409: ! 1410: /* if we have a loopback packet: */ ! 1411: if (rc > 0) { ! 1412: ! 1413: /* append the CRC bytes: */ ! 1414: if ((rc + sizeof(tme_uint32_t)) > sizeof(am7990->tme_am7990_receive_buffer)) { ! 1415: abort(); ! 1416: } ! 1417: rc += sizeof(tme_uint32_t); ! 1418: ! 1419: /* set the receive buffer length: */ ! 1420: am7990->tme_am7990_receive_buffer_length = rc; ! 1421: } ! 1422: ! 1423: /* if we have a loopback packet, call out a receive: */ ! 1424: if (am7990->tme_am7990_receive_buffer_length > 0) { ! 1425: am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_RECEIVE; ! 1426: } ! 1427: } ! 1428: ! 1429: /* otherwise, if we're not returning a packet: */ ! 1430: else if (rc <= 0) { ! 1431: ! 1432: /* we aren't considered readable any more: */ ! 1433: am7990->tme_am7990_ether_ctrl_out &= ~TME_ETHERNET_CTRL_OK_READ; ! 1434: } ! 1435: ! 1436: /* start a scan for the first buffer in the next packet to transmit: */ ! 1437: am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_TRANSMIT_SCAN; ! 1438: ! 1439: /* make any new callouts: */ ! 1440: _tme_am7990_callout(am7990); ! 1441: ! 1442: /* unlock our mutex: */ ! 1443: tme_mutex_unlock(&am7990->tme_am7990_mutex); ! 1444: ! 1445: /* done: */ ! 1446: return (rc); ! 1447: ! 1448: /* unused: */ ! 1449: _frame_id = 0; ! 1450: flags = 0; ! 1451: } ! 1452: ! 1453: /* the am7990 descriptor polling thread: */ ! 1454: static void ! 1455: _tme_am7990_poll_th(struct tme_am7990 *am7990) ! 1456: { ! 1457: ! 1458: /* lock our mutex: */ ! 1459: tme_mutex_lock(&am7990->tme_am7990_mutex); ! 1460: ! 1461: /* loop forever: */ ! 1462: for (;;) { ! 1463: ! 1464: /* call out a transmit scan: */ ! 1465: am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_TRANSMIT_SCAN; ! 1466: ! 1467: /* make any callouts: */ ! 1468: _tme_am7990_callout(am7990); ! 1469: ! 1470: /* unlock our mutex: */ ! 1471: tme_mutex_unlock(&am7990->tme_am7990_mutex); ! 1472: ! 1473: /* "[T]he C-LANCE will automatically poll the transmit ring in the ! 1474: memory once it has started .. every 1.6ms" */ ! 1475: tme_thread_sleep_yield(0, 16000); ! 1476: ! 1477: /* lock our mutex: */ ! 1478: tme_mutex_unlock(&am7990->tme_am7990_mutex); ! 1479: } ! 1480: /* NOTREACHED */ ! 1481: } ! 1482: ! 1483: /* the am7990 bus cycle handler: */ ! 1484: static int ! 1485: _tme_am7990_bus_cycle(void *_am7990, struct tme_bus_cycle *cycle_init) ! 1486: { ! 1487: struct tme_am7990 *am7990; ! 1488: tme_bus_addr_t address, am7990_address_last; ! 1489: tme_uint16_t value; ! 1490: tme_uint32_t reg; ! 1491: tme_uint16_t csr0_old; ! 1492: tme_uint16_t csr0_new; ! 1493: tme_uint8_t port_init; ! 1494: unsigned int routing_index; ! 1495: ! 1496: /* recover our data structure: */ ! 1497: am7990 = (struct tme_am7990 *) _am7990; ! 1498: ! 1499: /* the address must be within range: */ ! 1500: am7990_address_last = am7990->tme_am7990_device.tme_bus_device_address_last; ! 1501: assert(cycle_init->tme_bus_cycle_address <= am7990_address_last); ! 1502: assert(cycle_init->tme_bus_cycle_size <= (am7990_address_last - cycle_init->tme_bus_cycle_address) + 1); ! 1503: ! 1504: /* get the register being accessed: */ ! 1505: address = cycle_init->tme_bus_cycle_address; ! 1506: reg = (address & ((am7990_address_last + 1) / 2)); ! 1507: ! 1508: /* save the initiator's port description: */ ! 1509: port_init = cycle_init->tme_bus_cycle_port; ! 1510: ! 1511: /* lock the mutex: */ ! 1512: tme_mutex_lock(&am7990->tme_am7990_mutex); ! 1513: ! 1514: /* if this is a write: */ ! 1515: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) { ! 1516: ! 1517: /* run the bus cycle: */ ! 1518: tme_bus_cycle_xfer_reg(cycle_init, ! 1519: &value, ! 1520: TME_BUS16_LOG2); ! 1521: ! 1522: /* if this was a write to the RAP: */ ! 1523: if (reg == am7990->tme_am7990_offset_rap) { ! 1524: ! 1525: /* set the new RAP: */ ! 1526: am7990->tme_am7990_rap = value % TME_ARRAY_ELS(am7990->tme_am7990_csrs); ! 1527: } ! 1528: ! 1529: /* otherwise, this was a write to the RDP: */ ! 1530: else { ! 1531: assert (reg == am7990->tme_am7990_offset_rdp); ! 1532: ! 1533: /* if this is a write to CSR0: */ ! 1534: if (am7990->tme_am7990_rap == 0) { ! 1535: ! 1536: /* get the previous value of CSR0: */ ! 1537: csr0_old = am7990->tme_am7990_csr0; ! 1538: ! 1539: /* handle the read-only, write-1-to-clear, and write-1-only ! 1540: bits: */ ! 1541: csr0_new = ((value & ~TME_AM7990_CSR0_READ_ONLY) ! 1542: | (csr0_old ! 1543: & (TME_AM7990_CSR0_READ_ONLY ! 1544: | TME_AM7990_CSR0_WRITE_ONE_ONLY))); ! 1545: csr0_new = ((csr0_new ^ TME_AM7990_CSR0_WRITE_ONE_TO_CLEAR) ! 1546: & (csr0_old | ~TME_AM7990_CSR0_WRITE_ONE_TO_CLEAR)); ! 1547: ! 1548: /* update ERR: */ ! 1549: csr0_new &= ~TME_AM7990_CSR0_ERR; ! 1550: if (csr0_new ! 1551: & (TME_AM7990_CSR0_BABL ! 1552: | TME_AM7990_CSR0_CERR ! 1553: | TME_AM7990_CSR0_MISS ! 1554: | TME_AM7990_CSR0_MERR)) { ! 1555: csr0_new |= TME_AM7990_CSR0_ERR; ! 1556: } ! 1557: ! 1558: /* set the initial new CSR0 value: */ ! 1559: am7990->tme_am7990_csr0 = csr0_new; ! 1560: ! 1561: /* "If STRT, INIT and STOP are all set together, STOP will ! 1562: override the other bits and only STOP will be set." */ ! 1563: if (value & TME_AM7990_CSR0_STOP) { ! 1564: ! 1565: /* reset the am7990: */ ! 1566: _tme_am7990_reset(am7990); ! 1567: } ! 1568: ! 1569: /* otherwise, STOP is not set in the new CSR0 value: */ ! 1570: else { ! 1571: ! 1572: /* if INIT is set in the CSR0 value written, and STOP is set ! 1573: in the old CSR0 value: */ ! 1574: if ((value & TME_AM7990_CSR0_INIT) ! 1575: && (csr0_old & TME_AM7990_CSR0_STOP)) { ! 1576: ! 1577: /* run the initialization procedure: */ ! 1578: _tme_am7990_init(am7990); ! 1579: } ! 1580: ! 1581: /* if STRT is set in the CSR0 value written, and STRT is not ! 1582: set in the old CSR0 value: */ ! 1583: if ((value & TME_AM7990_CSR0_STRT) ! 1584: && !(csr0_old & TME_AM7990_CSR0_STRT)) { ! 1585: ! 1586: /* start the am7990: */ ! 1587: _tme_am7990_start(am7990); ! 1588: } ! 1589: ! 1590: /* if TDMD is set in the CSR0 value written, call out a ! 1591: transmit scan: */ ! 1592: if (value & TME_AM7990_CSR0_TDMD) { ! 1593: am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_TRANSMIT_SCAN; ! 1594: } ! 1595: } ! 1596: } ! 1597: ! 1598: /* otherwise, this is writing another CSR: */ ! 1599: else { ! 1600: ! 1601: tme_log(&am7990->tme_am7990_element->tme_element_log_handle, ! 1602: 100, TME_OK, ! 1603: (&am7990->tme_am7990_element->tme_element_log_handle, ! 1604: "CSR%u <- 0x%04x", ! 1605: am7990->tme_am7990_rap, ! 1606: value)); ! 1607: ! 1608: am7990->tme_am7990_csrs[am7990->tme_am7990_rap] = value; ! 1609: } ! 1610: } ! 1611: } ! 1612: ! 1613: /* otherwise, this is a read: */ ! 1614: else { ! 1615: assert (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ); ! 1616: ! 1617: /* get the value to read: */ ! 1618: if (reg == am7990->tme_am7990_offset_rap) { ! 1619: value = am7990->tme_am7990_rap; ! 1620: } ! 1621: else { ! 1622: assert (reg == am7990->tme_am7990_offset_rdp); ! 1623: value = am7990->tme_am7990_csrs[am7990->tme_am7990_rap]; ! 1624: } ! 1625: ! 1626: /* run the bus cycle: */ ! 1627: tme_bus_cycle_xfer_reg(cycle_init, ! 1628: &value, ! 1629: TME_BUS16_LOG2); ! 1630: } ! 1631: ! 1632: /* NB: the generic memory implementation doesn't know its own port ! 1633: size or endianness, and instead just follows the endianness of ! 1634: whatever reads and writes it (see tme_bus_cycle_xfer_memory()). ! 1635: this is sort of a fragile system, but does allow the same generic ! 1636: memory implementation to work with all kinds of CPU emulations. ! 1637: ! 1638: the fragility shows with a chip like the am7990. for all of its ! 1639: non-Ethernet data bus mastering, the real chip doesn't need to ! 1640: know memory's endianness; it just reads a 16-bit quantity from a ! 1641: 16-bit aligned address and expects that the most-significant ! 1642: eight bits will be on D8..D15. but since the memory doesn't know ! 1643: its own endianness, we have to use a bus routing that matches the ! 1644: endianness of the bus routing used by the CPU that wrote the ! 1645: memory. ! 1646: ! 1647: fortunately, we can learn the endianness of the CPU when it reads ! 1648: or writes us. we do this here: */ ! 1649: if (am7990->tme_am7990_device.tme_bus_device_router == NULL) { ! 1650: ! 1651: /* get the index into the bus routing used by the initiator for ! 1652: this cycle. if the initiator's least lane is zero, then this ! 1653: is also a lane number: */ ! 1654: routing_index ! 1655: = (TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_init->tme_bus_cycle_port) ! 1656: - TME_BUS_CYCLE_PORT_LANE_LEAST(port_init)); ! 1657: ! 1658: /* if the initiator routed a byte from a lower address to the byte ! 1659: lane of lesser significance, then we assume that memory is ! 1660: little-endian: */ ! 1661: am7990->tme_am7990_device.tme_bus_device_router ! 1662: = ((cycle_init->tme_bus_cycle_lane_routing[routing_index + 0] ! 1663: < cycle_init->tme_bus_cycle_lane_routing[routing_index + 1]) ! 1664: ? tme_bus_device_router_16el ! 1665: : tme_bus_device_router_16eb); ! 1666: } ! 1667: ! 1668: /* make any new callouts: */ ! 1669: _tme_am7990_callout(am7990); ! 1670: ! 1671: /* unlock the mutex: */ ! 1672: tme_mutex_unlock(&am7990->tme_am7990_mutex); ! 1673: ! 1674: /* no faults: */ ! 1675: return (TME_OK); ! 1676: } ! 1677: ! 1678: /* the am7990 TLB filler: */ ! 1679: static int ! 1680: _tme_am7990_tlb_fill(void *_am7990, ! 1681: struct tme_bus_tlb *tlb, ! 1682: tme_bus_addr_t address, ! 1683: unsigned int cycles) ! 1684: { ! 1685: struct tme_am7990 *am7990; ! 1686: tme_bus_addr_t am7990_address_last; ! 1687: ! 1688: /* recover our data structure: */ ! 1689: am7990 = (struct tme_am7990 *) _am7990; ! 1690: ! 1691: /* the address must be within range: */ ! 1692: am7990_address_last = am7990->tme_am7990_device.tme_bus_device_address_last; ! 1693: assert(address <= am7990_address_last); ! 1694: ! 1695: /* initialize the TLB entry: */ ! 1696: tme_bus_tlb_initialize(tlb); ! 1697: ! 1698: /* this TLB entry can cover the whole device: */ ! 1699: tlb->tme_bus_tlb_addr_first = 0; ! 1700: tlb->tme_bus_tlb_addr_last = am7990_address_last; ! 1701: ! 1702: /* allow reading and writing: */ ! 1703: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 1704: ! 1705: /* our bus cycle handler: */ ! 1706: tlb->tme_bus_tlb_cycle_private = am7990; ! 1707: tlb->tme_bus_tlb_cycle = _tme_am7990_bus_cycle; ! 1708: ! 1709: return (TME_OK); ! 1710: } ! 1711: ! 1712: /* this makes a new Ethernet connection: */ ! 1713: static int ! 1714: _tme_am7990_connection_make_eth(struct tme_connection *conn, unsigned int state) ! 1715: { ! 1716: struct tme_am7990 *am7990; ! 1717: struct tme_ethernet_connection *conn_eth; ! 1718: struct tme_ethernet_connection *conn_eth_other; ! 1719: ! 1720: /* recover our data structures: */ ! 1721: am7990 = conn->tme_connection_element->tme_element_private; ! 1722: conn_eth = (struct tme_ethernet_connection *) conn; ! 1723: conn_eth_other = (struct tme_ethernet_connection *) conn->tme_connection_other; ! 1724: ! 1725: /* both sides must be Ethernet connections: */ ! 1726: assert(conn->tme_connection_type == TME_CONNECTION_ETHERNET); ! 1727: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_ETHERNET); ! 1728: ! 1729: /* we're always set up to answer calls across the connection, so we ! 1730: only have to do work when the connection has gone full, namely ! 1731: taking the other side of the connection: */ ! 1732: if (state == TME_CONNECTION_FULL) { ! 1733: ! 1734: /* lock our mutex: */ ! 1735: tme_mutex_lock(&am7990->tme_am7990_mutex); ! 1736: ! 1737: /* save our connection: */ ! 1738: am7990->tme_am7990_eth_connection = conn_eth_other; ! 1739: ! 1740: /* unlock our mutex: */ ! 1741: tme_mutex_unlock(&am7990->tme_am7990_mutex); ! 1742: } ! 1743: ! 1744: return (TME_OK); ! 1745: } ! 1746: ! 1747: /* this makes a new bus connection: */ ! 1748: static int ! 1749: _tme_am7990_connection_make_bus(struct tme_connection *conn, ! 1750: unsigned int state) ! 1751: { ! 1752: struct tme_am7990 *am7990; ! 1753: struct tme_bus_connection *conn_bus; ! 1754: int rc; ! 1755: ! 1756: /* recover our data structure: */ ! 1757: am7990 = conn->tme_connection_element->tme_element_private; ! 1758: ! 1759: /* call the bus device connection maker: */ ! 1760: rc = tme_bus_device_connection_make(conn, state); ! 1761: ! 1762: /* if the full connection was successful, and we don't have a TLB ! 1763: hash yet, allocate it: */ ! 1764: if (rc == TME_OK ! 1765: && state == TME_CONNECTION_FULL ! 1766: && tme_memory_atomic_pointer_read(struct tme_bus_tlb *, ! 1767: am7990->tme_am7990_tlb_hash, ! 1768: &am7990->tme_am7990_tlb_hash_rwlock) == NULL) { ! 1769: ! 1770: /* get our bus connection: */ ! 1771: conn_bus ! 1772: = tme_memory_atomic_pointer_read(struct tme_bus_connection *, ! 1773: am7990->tme_am7990_device.tme_bus_device_connection, ! 1774: &am7990->tme_am7990_device.tme_bus_device_connection_rwlock); ! 1775: ! 1776: /* allocate the TLB set: */ ! 1777: rc = ((*conn_bus->tme_bus_tlb_set_allocate) ! 1778: (conn_bus, ! 1779: TME_AM7990_TLB_HASH_SIZE, ! 1780: sizeof(struct tme_bus_tlb), ! 1781: &am7990->tme_am7990_tlb_hash, ! 1782: &am7990->tme_am7990_device.tme_bus_device_connection_rwlock)); ! 1783: assert (rc == TME_OK); ! 1784: } ! 1785: ! 1786: return (rc); ! 1787: } ! 1788: ! 1789: /* this breaks a connection: */ ! 1790: static int ! 1791: _tme_am7990_connection_break(struct tme_connection *conn, unsigned int state) ! 1792: { ! 1793: abort(); ! 1794: } ! 1795: ! 1796: /* this makes a new connection side for a am7990: */ ! 1797: static int ! 1798: _tme_am7990_connections_new(struct tme_element *element, ! 1799: const char * const *args, ! 1800: struct tme_connection **_conns, ! 1801: char **_output) ! 1802: { ! 1803: struct tme_am7990 *am7990; ! 1804: struct tme_ethernet_connection *conn_eth; ! 1805: struct tme_connection *conn; ! 1806: int rc; ! 1807: ! 1808: /* recover our data structure: */ ! 1809: am7990 = (struct tme_am7990 *) element->tme_element_private; ! 1810: ! 1811: /* make the generic bus device connection side: */ ! 1812: rc = tme_bus_device_connections_new(element, args, _conns, _output); ! 1813: if (rc != TME_OK) { ! 1814: return (rc); ! 1815: } ! 1816: ! 1817: /* since we need to allocate our TLB hash when we make our bus ! 1818: connection, make sure any generic bus device connection sides use ! 1819: our connection maker: */ ! 1820: for (conn = *_conns; ! 1821: conn != NULL; ! 1822: conn = conn->tme_connection_next) { ! 1823: if ((conn->tme_connection_type ! 1824: == TME_CONNECTION_BUS_GENERIC) ! 1825: && (conn->tme_connection_make ! 1826: == tme_bus_device_connection_make)) { ! 1827: conn->tme_connection_make ! 1828: = _tme_am7990_connection_make_bus; ! 1829: } ! 1830: } ! 1831: ! 1832: /* if we don't have an Ethernet connection, make one: */ ! 1833: if (am7990->tme_am7990_eth_connection == NULL) { ! 1834: ! 1835: /* allocate the new Ethernet connection: */ ! 1836: conn_eth = tme_new0(struct tme_ethernet_connection, 1); ! 1837: conn = &conn_eth->tme_ethernet_connection; ! 1838: ! 1839: /* fill in the generic connection: */ ! 1840: conn->tme_connection_next = *_conns; ! 1841: conn->tme_connection_type = TME_CONNECTION_ETHERNET; ! 1842: conn->tme_connection_score = tme_ethernet_connection_score; ! 1843: conn->tme_connection_make = _tme_am7990_connection_make_eth; ! 1844: conn->tme_connection_break = _tme_am7990_connection_break; ! 1845: ! 1846: /* fill in the Ethernet connection: */ ! 1847: conn_eth->tme_ethernet_connection_config = _tme_am7990_config; ! 1848: conn_eth->tme_ethernet_connection_ctrl = _tme_am7990_ctrl; ! 1849: conn_eth->tme_ethernet_connection_read = _tme_am7990_transmit; ! 1850: ! 1851: /* return the connection side possibility: */ ! 1852: *_conns = conn; ! 1853: } ! 1854: ! 1855: /* done: */ ! 1856: return (TME_OK); ! 1857: } ! 1858: ! 1859: /* the new am7990 function: */ ! 1860: TME_ELEMENT_X_NEW_DECL(tme_ic_,am7990,am7990) { ! 1861: struct tme_am7990 *am7990; ! 1862: int arg_i; ! 1863: int usage; ! 1864: tme_uint32_t reg_size; ! 1865: ! 1866: /* check our arguments: */ ! 1867: usage = 0; ! 1868: arg_i = 1; ! 1869: for (;;) { ! 1870: ! 1871: if (0) { ! 1872: } ! 1873: ! 1874: /* if we ran out of arguments: */ ! 1875: else if (args[arg_i] == NULL) { ! 1876: ! 1877: break; ! 1878: } ! 1879: ! 1880: /* otherwise this is a bad argument: */ ! 1881: else { ! 1882: tme_output_append_error(_output, ! 1883: "%s %s, ", ! 1884: args[arg_i], ! 1885: _("unexpected")); ! 1886: usage = TRUE; ! 1887: break; ! 1888: } ! 1889: } ! 1890: ! 1891: if (usage) { ! 1892: tme_output_append_error(_output, ! 1893: "%s %s", ! 1894: _("usage:"), ! 1895: args[0]); ! 1896: return (EINVAL); ! 1897: } ! 1898: ! 1899: /* start the am7990 structure: */ ! 1900: am7990 = tme_new0(struct tme_am7990, 1); ! 1901: am7990->tme_am7990_element = element; ! 1902: tme_mutex_init(&am7990->tme_am7990_mutex); ! 1903: ! 1904: /* set the register offsets: */ ! 1905: /* XXX FIXME - these should come from a socket structure: */ ! 1906: am7990->tme_am7990_offset_rdp = 0; ! 1907: am7990->tme_am7990_offset_rap = sizeof(tme_uint16_t); ! 1908: ! 1909: /* get the total register size: */ ! 1910: assert ((am7990->tme_am7990_offset_rdp & (am7990->tme_am7990_offset_rdp - 1)) == 0); ! 1911: assert ((am7990->tme_am7990_offset_rap & (am7990->tme_am7990_offset_rap - 1)) == 0); ! 1912: reg_size = TME_MAX(am7990->tme_am7990_offset_rdp, am7990->tme_am7990_offset_rap) * 2; ! 1913: ! 1914: /* initialize our simple bus device descriptor: */ ! 1915: am7990->tme_am7990_device.tme_bus_device_element = element; ! 1916: am7990->tme_am7990_device.tme_bus_device_tlb_fill = _tme_am7990_tlb_fill; ! 1917: am7990->tme_am7990_device.tme_bus_device_address_last = reg_size - 1; ! 1918: am7990->tme_am7990_device.tme_bus_device_signal = _tme_am7990_signal; ! 1919: am7990->tme_am7990_device.tme_bus_device_lock = _tme_am7990_lock; ! 1920: am7990->tme_am7990_device.tme_bus_device_unlock = _tme_am7990_unlock; ! 1921: am7990->tme_am7990_device.tme_bus_device_tlb_hash = _tme_am7990_tlb_hash; ! 1922: ! 1923: /* fill the element: */ ! 1924: element->tme_element_private = am7990; ! 1925: element->tme_element_connections_new = _tme_am7990_connections_new; ! 1926: ! 1927: /* start the descriptor polling thread: */ ! 1928: tme_thread_create((tme_thread_t) _tme_am7990_poll_th, am7990); ! 1929: ! 1930: /* reset the am7990: */ ! 1931: _tme_am7990_reset(am7990); ! 1932: ! 1933: return (TME_OK); ! 1934: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.