1 /* $Id: 3c400.c,v 1.11 2010/06/05 13:49:56 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.11 2010/06/05 13:49:56 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_uint16_t) (_3c400)->tme_3c400_card[TME_3C400_REG_CSR + 0]) << 8)	\
99    + (_3c400)->tme_3c400_card[TME_3C400_REG_CSR + 1])
100 #define TME_3C400_CSR_PUT(_3c400, csr)	\
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)
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
_tme_3c400_reset(struct tme_3c400 * _3c400)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
_tme_3c400_callout(struct tme_3c400 * _3c400,int new_callouts)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: */
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);
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
447 	      : TME_BUS_SIGNAL_LEVEL_NEGATED));
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
_tme_3c400_bus_cycle(void * __3c400,struct tme_bus_cycle * cycle_init)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
_tme_3c400_config(struct tme_ethernet_connection * conn_eth,struct tme_ethernet_config * config)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
_tme_3c400_ctrl(struct tme_ethernet_connection * conn_eth,unsigned int ctrl)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
_tme_3c400_read(struct tme_ethernet_connection * conn_eth,tme_ethernet_fid_t * _frame_id,struct tme_ethernet_frame_chunk * frame_chunks,unsigned int flags)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
_tme_3c400_tlb_fill(void * __3c400,struct tme_bus_tlb * tlb,tme_bus_addr_t address_wider,unsigned int cycles)686 _tme_3c400_tlb_fill(void *__3c400, struct tme_bus_tlb *tlb,
687 		    tme_bus_addr_t address_wider, unsigned int cycles)
688 {
689   struct tme_3c400 *_3c400;
690   tme_bus_addr32_t address;
691 
692   /* recover our data structure: */
693   _3c400 = (struct tme_3c400 *) __3c400;
694 
695   /* get the normal-width address: */
696   address = address_wider;
697   assert (address == address_wider);
698 
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: */
710     tlb->tme_bus_tlb_addr_first = TME_3C400_REG_CSR;
711     tlb->tme_bus_tlb_addr_last = TME_3C400_REG_AROM - 1;
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: */
719     tlb->tme_bus_tlb_addr_first = TME_3C400_REG_AROM;
720     tlb->tme_bus_tlb_addr_last = TME_3C400_REG_ARAM - 1;
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: */
727     tlb->tme_bus_tlb_addr_first = TME_3C400_REG_ARAM;
728     tlb->tme_bus_tlb_addr_last = TME_3C400_SIZ_CARD - 1;
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
_tme_3c400_connection_make(struct tme_connection * conn,unsigned int state)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
_tme_3c400_connection_break(struct tme_connection * conn,unsigned int state)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
_tme_3c400_connections_new(struct tme_element * element,const char * const * args,struct tme_connection ** _conns,char ** _output)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 }
910