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