|
|
1.1.1.2 ! root 1: /* $Id: 3c400.c,v 1.7 2003/07/29 18:17:14 fredette Exp $ */ 1.1 root 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> 1.1.1.2 ! root 37: _TME_RCSID("$Id: 3c400.c,v 1.7 2003/07/29 18:17:14 fredette Exp $"); 1.1 root 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) \ 1.1.1.2 ! root 100: (*((tme_uint16_t *) &(_3c400)->tme_3c400_card[TME_3C400_REG_CSR]) = tme_htobe_u16(csr)) 1.1 root 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.