|
|
1.1 ! root 1: /* $Id: 3c400.c,v 1.6 2003/05/18 00:05:12 fredette Exp $ */ ! 2: ! 3: /* bus/multibus/3c400.c - implementation of the Multibus 3c400 emulation: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2003 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: 3c400.c,v 1.6 2003/05/18 00:05:12 fredette Exp $"); ! 38: ! 39: /* includes: */ ! 40: #include <tme/generic/bus-device.h> ! 41: #include <tme/generic/ethernet.h> ! 42: ! 43: /* macros: */ ! 44: ! 45: /* register offsets and sizes: */ ! 46: #define TME_3C400_REG_CSR (0) ! 47: #define TME_3C400_SIZ_CSR (sizeof(tme_uint16_t)) ! 48: #define TME_3C400_REG_BACKOFF (2) ! 49: #define TME_3C400_SIZ_BACKOFF (sizeof(tme_uint16_t)) ! 50: #define TME_3C400_REG_AROM (1024) ! 51: #define TME_3C400_SIZ_AROM (TME_ETHERNET_ADDR_SIZE) ! 52: #define TME_3C400_REG_ARAM (1536) ! 53: #define TME_3C400_SIZ_ARAM (TME_ETHERNET_ADDR_SIZE) ! 54: #define TME_3C400_REG_TBUF (2048) ! 55: #define TME_3C400_SIZ_BUF (2048) ! 56: #define TME_3C400_REG_ABUF (TME_3C400_REG_TBUF + TME_3C400_SIZ_BUF) ! 57: #define TME_3C400_REG_BBUF (TME_3C400_REG_ABUF + TME_3C400_SIZ_BUF) ! 58: #define TME_3C400_SIZ_CARD (TME_3C400_REG_BBUF + TME_3C400_SIZ_BUF) ! 59: ! 60: /* the bits in the Control/Status Register. software can set and ! 61: clear bits covered by TME_3C400_CSR_INTPA. software can set, but ! 62: not clear, bits not covered by TME_3C400_CSR_INTPA: */ ! 63: #define TME_3C400_CSR_BBSW (0x8000) /* B buffer empty (belongs to card) */ ! 64: #define TME_3C400_CSR_ABSW (0x4000) /* A buffer empty (belongs to card) */ ! 65: #define TME_3C400_CSR_TBSW (0x2000) /* T buffer full (belongs to card) */ ! 66: #define TME_3C400_CSR_JAM (0x1000) /* Ethernet jammed (collision) */ ! 67: #define TME_3C400_CSR_AMSW (0x0800) /* address RAM belongs to ether */ ! 68: #define TME_3C400_CSR_RBBA (0x0400) /* B buffer received before A */ ! 69: #define TME_3C400_CSR_RESET (0x0100) /* reset the card */ ! 70: #define TME_3C400_CSR_INTPA (0x00ff) /* mask for interrupt and PA fields */ ! 71: #define TME_3C400_CSR_BINT (0x0080) /* B buffer interrupt enable */ ! 72: #define TME_3C400_CSR_AINT (0x0040) /* A buffer interrupt enable */ ! 73: #define TME_3C400_CSR_TINT (0x0020) /* T buffer interrupt enable */ ! 74: #define TME_3C400_CSR_JINT (0x0010) /* jam interrupt enable */ ! 75: #define TME_3C400_CSR_PAMASK (0x000f) /* PA field */ ! 76: #define TME_3C400_CSR_PA (0x0007) /* receive mine+broadcast-errors */ ! 77: #define TME_3C400_CSR_PROMISC (0x0001) /* receive all-errors */ ! 78: ! 79: /* the first 16 bits of all buffers are a status word: */ ! 80: #define TME_3C400_SIZ_BUF_STATUS (sizeof(tme_uint16_t)) ! 81: ! 82: /* the bits of a receive buffer status word: */ ! 83: /* Frame Check Sequence (CRC) error */ ! 84: #define TME_3C400_RBUF_FCSERR (0x8000) ! 85: /* this packet was broadcast: */ ! 86: #define TME_3C400_RBUF_BROADCAST (0x4000) ! 87: /* this packet had a "range error": */ ! 88: #define TME_3C400_RBUF_RGERR (0x2000) ! 89: /* this packet matched our address: */ ! 90: #define TME_3C400_RBUF_ADDRMATCH (0x1000) ! 91: /* this packet had a framing error: */ ! 92: #define TME_3C400_RBUF_FRERR (0x0800) ! 93: /* the first byte after the frame in the buffer: */ ! 94: #define TME_3C400_RBUF_DOFF_MASK (0x07ff) ! 95: ! 96: /* these get and put the CSR: */ ! 97: #define TME_3C400_CSR_GET(_3c400) \ ! 98: tme_betoh_u16(*((tme_uint16_t *) &(_3c400)->tme_3c400_card[TME_3C400_REG_CSR])) ! 99: #define TME_3C400_CSR_PUT(_3c400, csr) \ ! 100: (*((tme_uint16_t *) &(_3c400)->tme_3c400_card[TME_3C400_REG_CSR]) = tme_betoh_u16(csr)) ! 101: ! 102: /* the callout flags: */ ! 103: #define TME_3C400_CALLOUT_CHECK (0) ! 104: #define TME_3C400_CALLOUT_RUNNING TME_BIT(0) ! 105: #define TME_3C400_CALLOUTS_MASK (-2) ! 106: #define TME_3C400_CALLOUT_CTRL TME_BIT(1) ! 107: #define TME_3C400_CALLOUT_CONFIG TME_BIT(2) ! 108: #define TME_3C400_CALLOUT_READ TME_BIT(3) ! 109: #define TME_3C400_CALLOUT_INT TME_BIT(4) ! 110: ! 111: /* structures: */ ! 112: ! 113: /* the card: */ ! 114: struct tme_3c400 { ! 115: ! 116: /* our simple bus device header: */ ! 117: struct tme_bus_device tme_3c400_device; ! 118: #define tme_3c400_element tme_3c400_device.tme_bus_device_element ! 119: ! 120: /* the mutex protecting the card: */ ! 121: tme_mutex_t tme_3c400_mutex; ! 122: ! 123: /* the rwlock protecting the card: */ ! 124: tme_rwlock_t tme_3c400_rwlock; ! 125: ! 126: /* the Ethernet connection: */ ! 127: struct tme_ethernet_connection *tme_3c400_eth_connection; ! 128: ! 129: /* the callout flags: */ ! 130: int tme_3c400_callout_flags; ! 131: ! 132: /* if our interrupt line is currently asserted: */ ! 133: int tme_3c400_int_asserted; ! 134: ! 135: /* it's easiest to just model the card as a chunk of memory: */ ! 136: tme_uint8_t tme_3c400_card[TME_3C400_SIZ_CARD]; ! 137: ! 138: #ifndef TME_NO_LOG ! 139: tme_uint16_t tme_3c400_last_log_csr; ! 140: #endif /* !TME_NO_LOG */ ! 141: }; ! 142: ! 143: /* this resets the card: */ ! 144: static void ! 145: _tme_3c400_reset(struct tme_3c400 *_3c400) ! 146: { ! 147: tme_uint16_t csr; ! 148: ! 149: /* the reset CSR value: */ ! 150: csr = 0; ! 151: ! 152: /* set the CSR: */ ! 153: TME_3C400_CSR_PUT(_3c400, csr); ! 154: ! 155: /* clear all pending callouts: */ ! 156: _3c400->tme_3c400_callout_flags &= TME_3C400_CALLOUTS_MASK; ! 157: ! 158: /* if the interrupt line is currently asserted, negate it: */ ! 159: if (_3c400->tme_3c400_int_asserted) { ! 160: _3c400->tme_3c400_callout_flags |= TME_3C400_CALLOUT_INT; ! 161: } ! 162: } ! 163: ! 164: /* the _3c400 callout function. it must be called with the mutex locked: */ ! 165: static void ! 166: _tme_3c400_callout(struct tme_3c400 *_3c400, int new_callouts) ! 167: { ! 168: struct tme_ethernet_connection *conn_eth; ! 169: struct tme_bus_connection *conn_bus; ! 170: tme_uint16_t csr, csr_rbba, recv_buffer; ! 171: int callouts, later_callouts; ! 172: unsigned int ctrl; ! 173: struct tme_ethernet_config config; ! 174: int rc; ! 175: const tme_uint8_t *addrs[2]; ! 176: tme_ethernet_fid_t frame_id; ! 177: tme_uint8_t *rbuf; ! 178: tme_uint16_t status; ! 179: struct tme_ethernet_frame_chunk *frame_chunk, frame_chunk_buffer; ! 180: int int_asserted; ! 181: ! 182: /* add in any new callouts: */ ! 183: _3c400->tme_3c400_callout_flags |= new_callouts; ! 184: ! 185: /* if this function is already running in another thread, simply ! 186: return now. the other thread will do our work: */ ! 187: if (_3c400->tme_3c400_callout_flags & TME_3C400_CALLOUT_RUNNING) { ! 188: return; ! 189: } ! 190: ! 191: /* callouts are now running: */ ! 192: _3c400->tme_3c400_callout_flags |= TME_3C400_CALLOUT_RUNNING; ! 193: ! 194: /* assume that we won't need any later callouts: */ ! 195: later_callouts = 0; ! 196: ! 197: /* loop while callouts are needed: */ ! 198: for (; (callouts = _3c400->tme_3c400_callout_flags) & TME_3C400_CALLOUTS_MASK; ) { ! 199: ! 200: /* clear the needed callouts: */ ! 201: _3c400->tme_3c400_callout_flags = callouts & ~TME_3C400_CALLOUTS_MASK; ! 202: callouts &= TME_3C400_CALLOUTS_MASK; ! 203: ! 204: /* get this card's connection: */ ! 205: conn_eth = _3c400->tme_3c400_eth_connection; ! 206: ! 207: /* if we need to call out new control information: */ ! 208: if (callouts & TME_3C400_CALLOUT_CTRL) { ! 209: ! 210: /* get the current CSR value: */ ! 211: csr = TME_3C400_CSR_GET(_3c400); ! 212: ! 213: /* form the new ctrl: */ ! 214: ctrl = 0; ! 215: if (csr & TME_3C400_CSR_TBSW) { ! 216: ctrl |= TME_ETHERNET_CTRL_OK_READ; ! 217: } ! 218: ! 219: /* unlock the mutex: */ ! 220: tme_mutex_unlock(&_3c400->tme_3c400_mutex); ! 221: ! 222: /* do the callout: */ ! 223: rc = (conn_eth != NULL ! 224: ? ((*conn_eth->tme_ethernet_connection_ctrl) ! 225: (conn_eth, ! 226: ctrl)) ! 227: : TME_OK); ! 228: ! 229: /* lock the mutex: */ ! 230: tme_mutex_lock(&_3c400->tme_3c400_mutex); ! 231: ! 232: /* if the callout was unsuccessful, remember that at some later ! 233: time this callout should be attempted again: */ ! 234: if (rc != TME_OK) { ! 235: later_callouts |= TME_3C400_CALLOUT_CTRL; ! 236: } ! 237: } ! 238: ! 239: /* if we need to call out new config information: */ ! 240: if (callouts & TME_3C400_CALLOUT_CONFIG) { ! 241: ! 242: /* get the current CSR value: */ ! 243: csr = TME_3C400_CSR_GET(_3c400); ! 244: ! 245: /* form the new config: */ ! 246: memset(&config, 0, sizeof(config)); ! 247: ! 248: /* our Ethernet address: */ ! 249: config.tme_ethernet_config_addr_count = 0; ! 250: addrs[config.tme_ethernet_config_addr_count++] ! 251: = tme_ethernet_addr_broadcast; ! 252: if (csr & TME_3C400_CSR_AMSW) { ! 253: addrs[config.tme_ethernet_config_addr_count++] ! 254: = &_3c400->tme_3c400_card[TME_3C400_REG_ARAM]; ! 255: } ! 256: config.tme_ethernet_config_addrs = addrs; ! 257: ! 258: /* our config flags: */ ! 259: config.tme_ethernet_config_flags = TME_ETHERNET_CONFIG_NORMAL; ! 260: switch (csr & TME_3C400_CSR_PAMASK) { ! 261: case 0: ! 262: config.tme_ethernet_config_addr_count = 0; ! 263: break; ! 264: case TME_3C400_CSR_PA: ! 265: break; ! 266: case TME_3C400_CSR_PROMISC: ! 267: config.tme_ethernet_config_flags |= TME_ETHERNET_CONFIG_PROMISC; ! 268: break; ! 269: default: abort(); ! 270: } ! 271: ! 272: /* unlock the mutex: */ ! 273: tme_mutex_unlock(&_3c400->tme_3c400_mutex); ! 274: ! 275: /* do the callout: */ ! 276: rc = (conn_eth == NULL ! 277: ? TME_OK ! 278: : ((*conn_eth->tme_ethernet_connection_config) ! 279: (conn_eth, ! 280: &config))); ! 281: ! 282: /* lock the mutex: */ ! 283: tme_mutex_lock(&_3c400->tme_3c400_mutex); ! 284: ! 285: /* if the callout was unsuccessful, remember that at some later ! 286: time this callout should be attempted again: */ ! 287: if (rc != TME_OK) { ! 288: later_callouts |= TME_3C400_CALLOUT_CONFIG; ! 289: } ! 290: } ! 291: ! 292: /* if the Ethernet is readable: */ ! 293: if (callouts & TME_3C400_CALLOUT_READ) { ! 294: ! 295: /* get the current CSR value: */ ! 296: csr = TME_3C400_CSR_GET(_3c400); ! 297: ! 298: /* try to find an empty buffer: */ ! 299: switch (csr & (TME_3C400_CSR_BBSW | TME_3C400_CSR_ABSW)) { ! 300: default: ! 301: /* both buffers are full: */ ! 302: recv_buffer = 0; ! 303: csr_rbba = (csr & TME_3C400_CSR_RBBA); ! 304: break; ! 305: case TME_3C400_CSR_BBSW: ! 306: /* the A buffer is full but the B buffer is empty: */ ! 307: recv_buffer = TME_3C400_CSR_BBSW; ! 308: csr_rbba = 0; ! 309: break; ! 310: case TME_3C400_CSR_ABSW: ! 311: /* the B buffer is full but the A buffer is empty: */ ! 312: recv_buffer = TME_3C400_CSR_ABSW; ! 313: csr_rbba = TME_3C400_CSR_RBBA; ! 314: break; ! 315: case TME_3C400_CSR_ABSW | TME_3C400_CSR_BBSW: ! 316: /* both buffers are empty: */ ! 317: recv_buffer = TME_3C400_CSR_ABSW; ! 318: csr_rbba = 0; ! 319: break; ! 320: } ! 321: ! 322: /* unlock the mutex: */ ! 323: tme_mutex_unlock(&_3c400->tme_3c400_mutex); ! 324: ! 325: /* make a frame chunk to receive this frame. remember that the ! 326: first two bytes of our card's buffers are a status word: */ ! 327: if (recv_buffer == 0) { ! 328: rbuf = NULL; ! 329: frame_chunk = NULL; ! 330: } ! 331: else { ! 332: rbuf = ! 333: &_3c400->tme_3c400_card[(recv_buffer == TME_3C400_CSR_ABSW ! 334: ? TME_3C400_REG_ABUF ! 335: : TME_3C400_REG_BBUF)]; ! 336: frame_chunk_buffer.tme_ethernet_frame_chunk_next = NULL; ! 337: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes ! 338: = rbuf + TME_3C400_SIZ_BUF_STATUS; ! 339: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes_count ! 340: = TME_3C400_SIZ_BUF; ! 341: frame_chunk = &frame_chunk_buffer; ! 342: } ! 343: ! 344: /* do the callout: */ ! 345: rc = (conn_eth == NULL ! 346: ? TME_OK ! 347: : ((*conn_eth->tme_ethernet_connection_read) ! 348: (conn_eth, ! 349: &frame_id, ! 350: frame_chunk, ! 351: TME_ETHERNET_READ_NEXT))); ! 352: ! 353: /* lock the mutex: */ ! 354: tme_mutex_lock(&_3c400->tme_3c400_mutex); ! 355: ! 356: /* get the current CSR value: */ ! 357: csr = TME_3C400_CSR_GET(_3c400); ! 358: ! 359: /* if the read was successful: */ ! 360: if (rc > 0) { ! 361: ! 362: /* if this frame was received into a buffer: */ ! 363: if (recv_buffer != 0) { ! 364: ! 365: /* form the status word for this buffer: */ ! 366: status = 0; ! 367: ! 368: /* the first thing in the frame is the destination address, ! 369: which we check against our address and the broadcast ! 370: address: */ ! 371: if (memcmp(rbuf + TME_3C400_SIZ_BUF_STATUS, ! 372: &_3c400->tme_3c400_card[TME_3C400_REG_ARAM], ! 373: TME_ETHERNET_ADDR_SIZE) == 0) { ! 374: status |= TME_3C400_RBUF_ADDRMATCH; ! 375: } ! 376: else if (memcmp(rbuf + TME_3C400_SIZ_BUF_STATUS, ! 377: tme_ethernet_addr_broadcast, ! 378: TME_ETHERNET_ADDR_SIZE) == 0) { ! 379: status |= TME_3C400_RBUF_BROADCAST; ! 380: } ! 381: ! 382: /* put in the offset of the first free byte in the status. ! 383: make sure we present a packet that is at least as big ! 384: as the smallest Ethernet frame: */ ! 385: rc = TME_MAX(rc, TME_ETHERNET_FRAME_MIN - TME_ETHERNET_CRC_SIZE); ! 386: status |= TME_3C400_SIZ_BUF_STATUS + rc; ! 387: ! 388: /* put in the status: */ ! 389: *((tme_uint16_t *) rbuf) = tme_htobe_u16(status); ! 390: ! 391: /* update the CSR to reflect the new packet: */ ! 392: csr = (csr & ~(recv_buffer | TME_3C400_CSR_RBBA)) | csr_rbba; ! 393: TME_3C400_CSR_PUT(_3c400, csr); ! 394: ! 395: /* if interrupts are enabled on this buffer, mark that we need ! 396: to callout an interrupt: */ ! 397: if (csr & (recv_buffer >> 8)) { ! 398: _3c400->tme_3c400_callout_flags |= TME_3C400_CALLOUT_INT; ! 399: } ! 400: } ! 401: ! 402: /* mark that we need to loop to callout to read more frames: */ ! 403: _3c400->tme_3c400_callout_flags |= TME_3C400_CALLOUT_READ; ! 404: } ! 405: ! 406: /* otherwise, the read failed. convention dictates that we ! 407: forget that the connection was readable, which we already ! 408: have done by clearing the CALLOUT_READ flag: */ ! 409: } ! 410: ! 411: /* if we need to call out a possible change to our interrupt ! 412: signal: */ ! 413: if (callouts & TME_3C400_CALLOUT_INT) { ! 414: ! 415: /* get the current CSR value: */ ! 416: csr = TME_3C400_CSR_GET(_3c400); ! 417: ! 418: /* see if the interrupt signal should be asserted or negated: */ ! 419: int_asserted = ((~(csr & (TME_3C400_CSR_BBSW ! 420: | TME_3C400_CSR_ABSW ! 421: | TME_3C400_CSR_TBSW))) ! 422: & ((csr & (TME_3C400_CSR_BINT ! 423: | TME_3C400_CSR_AINT ! 424: | TME_3C400_CSR_TINT)) << 8)); ! 425: ! 426: /* if the interrupt signal doesn't already have the right state: */ ! 427: if (!int_asserted != !_3c400->tme_3c400_int_asserted) { ! 428: ! 429: /* unlock our mutex: */ ! 430: tme_mutex_unlock(&_3c400->tme_3c400_mutex); ! 431: ! 432: /* get our bus connection: */ ! 433: conn_bus = TME_ATOMIC_READ(struct tme_bus_connection *, ! 434: _3c400->tme_3c400_device.tme_bus_device_connection); ! 435: ! 436: /* call out the bus interrupt signal edge: */ ! 437: rc = (*conn_bus->tme_bus_signal) ! 438: (conn_bus, ! 439: TME_BUS_SIGNAL_INT_UNSPEC ! 440: | (int_asserted ! 441: ? TME_BUS_SIGNAL_LEVEL_ASSERTED ! 442: : TME_BUS_SIGNAL_LEVEL_NEGATED) ! 443: | TME_BUS_SIGNAL_EDGE); ! 444: ! 445: /* lock our mutex: */ ! 446: tme_mutex_lock(&_3c400->tme_3c400_mutex); ! 447: ! 448: /* if this callout was successful, note the new state of the ! 449: interrupt signal: */ ! 450: if (rc == TME_OK) { ! 451: _3c400->tme_3c400_int_asserted = int_asserted; ! 452: } ! 453: ! 454: /* otherwise, remember that at some later time this callout ! 455: should be attempted again: */ ! 456: else { ! 457: later_callouts |= TME_3C400_CALLOUT_INT; ! 458: } ! 459: } ! 460: } ! 461: } ! 462: ! 463: /* put in any later callouts, and clear that callouts are running: */ ! 464: _3c400->tme_3c400_callout_flags = later_callouts; ! 465: } ! 466: ! 467: /* the _3c400 bus cycle handler: */ ! 468: static int ! 469: _tme_3c400_bus_cycle(void *__3c400, struct tme_bus_cycle *cycle_init) ! 470: { ! 471: struct tme_3c400 *_3c400; ! 472: tme_uint16_t csr_old, csr_new, csr_diff; ! 473: int new_callouts; ! 474: ! 475: /* recover our data structure: */ ! 476: _3c400 = (struct tme_3c400 *) __3c400; ! 477: ! 478: /* assume we won't need any new callouts: */ ! 479: new_callouts = 0; ! 480: ! 481: /* lock the mutex: */ ! 482: tme_mutex_lock(&_3c400->tme_3c400_mutex); ! 483: ! 484: /* get the changed CSR value - there are bits that software can only ! 485: set, and not clear: */ ! 486: csr_old = TME_3C400_CSR_GET(_3c400); ! 487: ! 488: /* unless this address falls within the address ROM, run the cycle: */ ! 489: if ((cycle_init->tme_bus_cycle_address ! 490: < TME_3C400_REG_AROM) ! 491: || (cycle_init->tme_bus_cycle_address ! 492: >= TME_3C400_REG_ARAM)) { ! 493: tme_bus_cycle_xfer_memory(cycle_init, ! 494: _3c400->tme_3c400_card, ! 495: _3c400->tme_3c400_device.tme_bus_device_address_last); ! 496: } ! 497: ! 498: /* get the new CSR value, and put back any bits that software ! 499: cannot clear: */ ! 500: csr_new = TME_3C400_CSR_GET(_3c400); ! 501: csr_new |= (csr_old & ~TME_3C400_CSR_INTPA); ! 502: ! 503: /* get the set of bits that has changed: */ ! 504: csr_diff = (csr_old ^ csr_new); ! 505: ! 506: /* if this is a reset: */ ! 507: if (csr_diff & TME_3C400_CSR_RESET) { ! 508: _tme_3c400_reset(_3c400); ! 509: } ! 510: ! 511: /* otherwise: */ ! 512: else { ! 513: ! 514: /* if the transmit buffer now belongs to the card, call out ! 515: that we are now readable: */ ! 516: if (csr_diff & TME_3C400_CSR_TBSW) { ! 517: new_callouts |= TME_3C400_CALLOUT_CTRL; ! 518: } ! 519: ! 520: /* if the address RAM now belongs to the card, or if the address ! 521: filter configuration has changed, call out the config change: */ ! 522: if ((csr_diff & TME_3C400_CSR_AMSW) ! 523: || (csr_diff & TME_3C400_CSR_PAMASK) != 0) { ! 524: new_callouts |= TME_3C400_CALLOUT_CONFIG; ! 525: } ! 526: ! 527: /* if any interrupt enable status bits have changed, ! 528: call out the interrupt signal change: */ ! 529: if (csr_diff & (TME_3C400_CSR_BINT ! 530: | TME_3C400_CSR_AINT ! 531: | TME_3C400_CSR_TINT)) { ! 532: new_callouts |= TME_3C400_CALLOUT_INT; ! 533: } ! 534: ! 535: /* set the current CSR value: */ ! 536: TME_3C400_CSR_PUT(_3c400, csr_new); ! 537: ! 538: #ifndef TME_NO_LOG ! 539: if (csr_new != _3c400->tme_3c400_last_log_csr) { ! 540: _3c400->tme_3c400_last_log_csr = csr_new; ! 541: tme_log(&_3c400->tme_3c400_element->tme_element_log_handle, ! 542: 1000, TME_OK, ! 543: (&_3c400->tme_3c400_element->tme_element_log_handle, ! 544: "csr now 0x%04x", ! 545: csr_new)); ! 546: } ! 547: #endif /* !TME_NO_LOG */ ! 548: } ! 549: ! 550: /* make any new callouts: */ ! 551: _tme_3c400_callout(_3c400, new_callouts); ! 552: ! 553: /* unlock the mutex: */ ! 554: tme_mutex_unlock(&_3c400->tme_3c400_mutex); ! 555: ! 556: /* no faults: */ ! 557: return (TME_OK); ! 558: } ! 559: ! 560: /* this is called when a device changes its configuration: */ ! 561: static int ! 562: _tme_3c400_config(struct tme_ethernet_connection *conn_eth, ! 563: struct tme_ethernet_config *config) ! 564: { ! 565: /* we don't care when other devices on the Ethernet ! 566: reconfigure themselves: */ ! 567: return (TME_OK); ! 568: } ! 569: ! 570: /* this is called when control lines change: */ ! 571: static int ! 572: _tme_3c400_ctrl(struct tme_ethernet_connection *conn_eth, ! 573: unsigned int ctrl) ! 574: { ! 575: struct tme_3c400 *_3c400; ! 576: int new_callouts; ! 577: ! 578: /* recover our data structures: */ ! 579: _3c400 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private; ! 580: ! 581: /* assume that we won't need any new callouts: */ ! 582: new_callouts = 0; ! 583: ! 584: /* lock the mutex: */ ! 585: tme_mutex_lock(&_3c400->tme_3c400_mutex); ! 586: ! 587: /* if this connection is readable, call out a read: */ ! 588: if (ctrl & TME_ETHERNET_CTRL_OK_READ) { ! 589: new_callouts |= TME_3C400_CALLOUT_READ; ! 590: } ! 591: ! 592: /* make any new callouts: */ ! 593: _tme_3c400_callout(_3c400, new_callouts); ! 594: ! 595: /* unlock the mutex: */ ! 596: tme_mutex_unlock(&_3c400->tme_3c400_mutex); ! 597: ! 598: return (TME_OK); ! 599: } ! 600: ! 601: /* this is called to read frames (from the 3c400 perspective, to transmit them): */ ! 602: static int ! 603: _tme_3c400_read(struct tme_ethernet_connection *conn_eth, ! 604: tme_ethernet_fid_t *_frame_id, ! 605: struct tme_ethernet_frame_chunk *frame_chunks, ! 606: unsigned int flags) ! 607: { ! 608: struct tme_3c400 *_3c400; ! 609: struct tme_ethernet_frame_chunk frame_chunk_buffer; ! 610: tme_uint16_t csr, count; ! 611: int new_callouts; ! 612: int rc; ! 613: ! 614: /* recover our data structures: */ ! 615: _3c400 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private; ! 616: ! 617: /* assume that we won't need any new callouts: */ ! 618: new_callouts = 0; ! 619: ! 620: /* lock our mutex: */ ! 621: tme_mutex_lock(&_3c400->tme_3c400_mutex); ! 622: ! 623: /* get the current CSR value: */ ! 624: csr = TME_3C400_CSR_GET(_3c400); ! 625: ! 626: /* if the transmit buffer is full: */ ! 627: if (csr & TME_3C400_CSR_TBSW) { ! 628: ! 629: /* get the count of bytes in the frame: */ ! 630: count = (TME_3C400_SIZ_BUF ! 631: - (tme_betoh_u16(*((tme_uint16_t *) ! 632: &_3c400->tme_3c400_card[TME_3C400_REG_TBUF])) ! 633: & TME_3C400_RBUF_DOFF_MASK)); ! 634: ! 635: /* form the single frame chunk: */ ! 636: frame_chunk_buffer.tme_ethernet_frame_chunk_next = NULL; ! 637: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes ! 638: = (&_3c400->tme_3c400_card[TME_3C400_REG_TBUF] ! 639: + TME_3C400_SIZ_BUF ! 640: - count); ! 641: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes_count ! 642: = count; ! 643: ! 644: /* copy out the frame: */ ! 645: count = tme_ethernet_chunks_copy(frame_chunks, &frame_chunk_buffer); ! 646: ! 647: /* if this isn't a peek: */ ! 648: if (!(flags & TME_ETHERNET_READ_PEEK)) { ! 649: ! 650: /* mark the transmit buffer as empty: */ ! 651: csr &= ~TME_3C400_CSR_TBSW; ! 652: TME_3C400_CSR_PUT(_3c400, csr); ! 653: ! 654: /* if transmit buffer interrupts are enabled, call out ! 655: an interrupt: */ ! 656: if (csr & TME_3C400_CSR_TINT) { ! 657: new_callouts |= TME_3C400_CALLOUT_INT; ! 658: } ! 659: } ! 660: ! 661: /* success: */ ! 662: rc = count; ! 663: } ! 664: ! 665: /* if the transmit buffer is empty, return an error: */ ! 666: else { ! 667: rc = -ENOENT; ! 668: } ! 669: ! 670: /* make any new callouts: */ ! 671: _tme_3c400_callout(_3c400, new_callouts); ! 672: ! 673: /* unlock our mutex: */ ! 674: tme_mutex_unlock(&_3c400->tme_3c400_mutex); ! 675: ! 676: /* done: */ ! 677: return (rc); ! 678: } ! 679: ! 680: /* the _3c400 TLB filler: */ ! 681: static int ! 682: _tme_3c400_tlb_fill(void *__3c400, struct tme_bus_tlb *tlb, ! 683: tme_bus_addr_t address, unsigned int cycles) ! 684: { ! 685: struct tme_3c400 *_3c400; ! 686: ! 687: /* recover our data structure: */ ! 688: _3c400 = (struct tme_3c400 *) __3c400; ! 689: ! 690: /* the address must be within range: */ ! 691: assert(address < TME_3C400_SIZ_CARD); ! 692: ! 693: /* initialize the TLB entry: */ ! 694: tme_bus_tlb_initialize(tlb); ! 695: ! 696: /* if the address falls from the CSR to the address ROM: */ ! 697: if (TME_3C400_REG_CSR <= address ! 698: && address < TME_3C400_REG_AROM) { ! 699: ! 700: /* this TLB entry covers this range: */ ! 701: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, TME_3C400_REG_CSR); ! 702: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, TME_3C400_REG_AROM - 1); ! 703: } ! 704: ! 705: /* if this address falls from the address ROM to the address RAM: */ ! 706: else if (TME_3C400_REG_AROM <= address ! 707: && address < TME_3C400_REG_ARAM) { ! 708: ! 709: /* this TLB entry covers this range: */ ! 710: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, TME_3C400_REG_AROM); ! 711: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, TME_3C400_REG_ARAM - 1); ! 712: } ! 713: ! 714: /* anything else covers the remainder of the device: */ ! 715: else { ! 716: ! 717: /* this TLB entry can cover from the address RAM to the end of the card: */ ! 718: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, TME_3C400_REG_ARAM); ! 719: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, TME_3C400_SIZ_CARD - 1); ! 720: ! 721: /* this TLB entry allows fast writing: */ ! 722: tlb->tme_bus_tlb_emulator_off_write = &_3c400->tme_3c400_card[0]; ! 723: } ! 724: ! 725: /* all address ranges allow fast reading: */ ! 726: tlb->tme_bus_tlb_emulator_off_read = &_3c400->tme_3c400_card[0]; ! 727: tlb->tme_bus_tlb_rwlock = &_3c400->tme_3c400_rwlock; ! 728: ! 729: /* allow reading and writing: */ ! 730: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 731: ! 732: /* our bus cycle handler: */ ! 733: tlb->tme_bus_tlb_cycle_private = _3c400; ! 734: tlb->tme_bus_tlb_cycle = _tme_3c400_bus_cycle; ! 735: ! 736: return (TME_OK); ! 737: } ! 738: ! 739: /* this makes a new Ethernet connection: */ ! 740: static int ! 741: _tme_3c400_connection_make(struct tme_connection *conn, unsigned int state) ! 742: { ! 743: struct tme_3c400 *_3c400; ! 744: struct tme_ethernet_connection *conn_eth; ! 745: struct tme_ethernet_connection *conn_eth_other; ! 746: ! 747: /* recover our data structures: */ ! 748: _3c400 = conn->tme_connection_element->tme_element_private; ! 749: conn_eth = (struct tme_ethernet_connection *) conn; ! 750: conn_eth_other = (struct tme_ethernet_connection *) conn->tme_connection_other; ! 751: ! 752: /* both sides must be Ethernet connections: */ ! 753: assert(conn->tme_connection_type == TME_CONNECTION_ETHERNET); ! 754: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_ETHERNET); ! 755: ! 756: /* we're always set up to answer calls across the connection, so we ! 757: only have to do work when the connection has gone full, namely ! 758: taking the other side of the connection: */ ! 759: if (state == TME_CONNECTION_FULL) { ! 760: ! 761: /* lock our mutex: */ ! 762: tme_mutex_lock(&_3c400->tme_3c400_mutex); ! 763: ! 764: /* save our connection: */ ! 765: _3c400->tme_3c400_eth_connection = conn_eth_other; ! 766: ! 767: /* unlock our mutex: */ ! 768: tme_mutex_unlock(&_3c400->tme_3c400_mutex); ! 769: } ! 770: ! 771: return (TME_OK); ! 772: } ! 773: ! 774: /* this breaks a connection: */ ! 775: static int ! 776: _tme_3c400_connection_break(struct tme_connection *conn, unsigned int state) ! 777: { ! 778: abort(); ! 779: } ! 780: ! 781: /* this makes a new connection side for a 3c400: */ ! 782: static int ! 783: _tme_3c400_connections_new(struct tme_element *element, ! 784: const char * const *args, ! 785: struct tme_connection **_conns, ! 786: char **_output) ! 787: { ! 788: struct tme_3c400 *_3c400; ! 789: struct tme_ethernet_connection *conn_eth; ! 790: struct tme_connection *conn; ! 791: int rc; ! 792: ! 793: /* recover our data structure: */ ! 794: _3c400 = (struct tme_3c400 *) element->tme_element_private; ! 795: ! 796: /* make the generic bus device connection side: */ ! 797: rc = tme_bus_device_connections_new(element, args, _conns, _output); ! 798: if (rc != TME_OK) { ! 799: return (rc); ! 800: } ! 801: ! 802: /* if we don't have an Ethernet connection, make one: */ ! 803: if (_3c400->tme_3c400_eth_connection == NULL) { ! 804: ! 805: /* allocate the new Ethernet connection: */ ! 806: conn_eth = tme_new0(struct tme_ethernet_connection, 1); ! 807: conn = &conn_eth->tme_ethernet_connection; ! 808: ! 809: /* fill in the generic connection: */ ! 810: conn->tme_connection_next = *_conns; ! 811: conn->tme_connection_type = TME_CONNECTION_ETHERNET; ! 812: conn->tme_connection_score = tme_ethernet_connection_score; ! 813: conn->tme_connection_make = _tme_3c400_connection_make; ! 814: conn->tme_connection_break = _tme_3c400_connection_break; ! 815: ! 816: /* fill in the Ethernet connection: */ ! 817: conn_eth->tme_ethernet_connection_config = _tme_3c400_config; ! 818: conn_eth->tme_ethernet_connection_ctrl = _tme_3c400_ctrl; ! 819: conn_eth->tme_ethernet_connection_read = _tme_3c400_read; ! 820: ! 821: /* return the connection side possibility: */ ! 822: *_conns = conn; ! 823: } ! 824: ! 825: /* done: */ ! 826: return (TME_OK); ! 827: } ! 828: ! 829: /* the new _3c400 function: */ ! 830: TME_ELEMENT_SUB_NEW_DECL(tme_bus_multibus,3c400) { ! 831: struct tme_3c400 *_3c400; ! 832: tme_uint8_t arom[TME_ETHERNET_ADDR_SIZE]; ! 833: int arom_ok; ! 834: int arg_i; ! 835: int usage; ! 836: ! 837: /* check our arguments: */ ! 838: usage = 0; ! 839: arom_ok = FALSE; ! 840: arg_i = 1; ! 841: for (;;) { ! 842: ! 843: /* our Ethernet address ROM: */ ! 844: if (TME_ARG_IS(args[arg_i], "ether") ! 845: && tme_ethernet_addr_parse(args[arg_i + 1], arom) == TME_OK) { ! 846: arom_ok = TRUE; ! 847: arg_i += 2; ! 848: } ! 849: ! 850: /* if we ran out of arguments: */ ! 851: else if (args[arg_i] == NULL) { ! 852: ! 853: /* we must have been given our Ethernet address ROM: */ ! 854: if (!arom_ok) { ! 855: usage = TRUE; ! 856: } ! 857: break; ! 858: } ! 859: ! 860: /* otherwise this is a bad argument: */ ! 861: else { ! 862: tme_output_append_error(_output, ! 863: "%s %s, ", ! 864: args[arg_i], ! 865: _("unexpected")); ! 866: usage = TRUE; ! 867: break; ! 868: } ! 869: } ! 870: ! 871: if (usage) { ! 872: tme_output_append_error(_output, ! 873: "%s %s ether %s", ! 874: _("usage:"), ! 875: args[0], ! 876: _("ETHERNET-ADDRESS")); ! 877: return (EINVAL); ! 878: } ! 879: ! 880: /* start the _3c400 structure: */ ! 881: _3c400 = tme_new0(struct tme_3c400, 1); ! 882: _3c400->tme_3c400_element = element; ! 883: tme_mutex_init(&_3c400->tme_3c400_mutex); ! 884: tme_rwlock_init(&_3c400->tme_3c400_rwlock); ! 885: memcpy(_3c400->tme_3c400_card + TME_3C400_REG_AROM, ! 886: arom, ! 887: sizeof(arom)); ! 888: ! 889: /* initialize our simple bus device descriptor: */ ! 890: assert((TME_3C400_SIZ_CARD & (TME_3C400_SIZ_CARD - 1)) == 0); ! 891: _3c400->tme_3c400_device.tme_bus_device_element = element; ! 892: _3c400->tme_3c400_device.tme_bus_device_tlb_fill = _tme_3c400_tlb_fill; ! 893: _3c400->tme_3c400_device.tme_bus_device_address_last = TME_3C400_SIZ_CARD - 1; ! 894: ! 895: /* fill the element: */ ! 896: element->tme_element_private = _3c400; ! 897: element->tme_element_connections_new = _tme_3c400_connections_new; ! 898: ! 899: return (TME_OK); ! 900: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.