2 * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
4 * This software may be freely used, copied, modified, and distributed
5 * provided that the above copyright notice is preserved in all copies of the
15 * hostchan.c - Semi Synchronous Host side channel interface for Angel.
20 #if defined(__unix) || defined(__CYGWIN32__)
21 # include <sys/time.h>
23 int gettimeofday(struct timeval *tp, struct timezone *tzp);
42 #define UNUSED(x) (x = x) /* Silence compiler warnings for unused arguments */
45 #define HEARTRATE 5000000
48 * list of available drivers, declared in drivers.c
50 extern DeviceDescr *devices[];
52 static DeviceDescr *deviceToUse = NULL;
54 static struct Channel {
55 ChannelCallback callback;
57 } channels[CI_NUM_CHANNELS];
59 static unsigned char HomeSeq;
60 static unsigned char OppoSeq;
63 * Handler for DC_APPL packets
65 static DC_Appl_Handler dc_appl_handler = NULL;
68 * slots for registered asynchronous processing callback procedures
70 #define MAX_ASYNC_CALLBACKS 8
71 static unsigned int num_async_callbacks = 0;
72 static Adp_Async_Callback async_callbacks[MAX_ASYNC_CALLBACKS];
75 * writeQueueRoot is the queue of write requests pending acknowledgement
76 * writeQueueSend is the queue of pending write requests which will
77 * be a subset of the list writeQueueRoot
79 static Packet *writeQueueRoot = NULL;
80 static Packet *writeQueueSend = NULL;
81 static Packet *resend_pkt = NULL;
82 static int resending = FALSE;
84 /* heartbeat_enabled is a flag used to indicate whether the heartbeat is
85 * currently turned on, heartbeat_enabled will be false in situations
86 * where even though a heartbeat is being used it is problematical or
87 * dis-advantageous to have it turned on, for instance during the
88 * initial stages of boot up
90 unsigned int heartbeat_enabled = FALSE;
91 /* heartbeat_configured is set up by the device driver to indicate whether
92 * the heartbeat is being used during this debug session. In contrast to
93 * heartbeat_enabled it must not be changed during a session. The logic for
94 * deciding whether to send a heartbeat is: Is heartbeat_configured for this
95 * session? if and only if it is then if heartbeat[is currently]_enabled and
96 * we are due to send a pulse then send it
98 unsigned int heartbeat_configured = TRUE;
100 void Adp_initSeq( void ) {
101 Packet *tmp_pkt = writeQueueSend;
105 if ( writeQueueSend != NULL) {
106 while (writeQueueSend->pk_next !=NULL) {
107 tmp_pkt = writeQueueSend;
108 writeQueueSend = tmp_pkt->pk_next;
109 DevSW_FreePacket(tmp_pkt);
112 tmp_pkt = writeQueueRoot;
113 if ( writeQueueRoot == NULL)
116 while (writeQueueRoot->pk_next !=NULL) {
117 tmp_pkt = writeQueueRoot;
118 writeQueueRoot = tmp_pkt->pk_next;
119 DevSW_FreePacket(tmp_pkt);
124 /**********************************************************************/
127 * Function: DummyCallback
128 * Purpose: Default callback routine to handle unexpected input
132 * Input: packet The received packet
134 * state Contains nothing of significance
138 static void DummyCallback(Packet *packet, void *state)
141 const char fmt[] = "Unexpected read on channel %u, length %d\n";
142 char fmtbuf[sizeof(fmt) + 24];
146 chan = *(packet->pk_buffer);
147 sprintf(fmtbuf, fmt, chan, packet->pk_length);
153 DevSW_FreePacket(packet);
157 * Function: BlockingCallback
158 * Purpose: Callback routine used to implement a blocking read call
161 * Input: packet The received packet.
163 * Output: state Address of higher level's pointer to the received
168 static void BlockingCallback(Packet *packet, void *state)
171 * Pass the packet back to the caller which requested a packet
172 * from this channel. This also flags the completion of the I/O
173 * request to the blocking read call.
175 *((Packet **)state) = packet;
179 * Function: FireCallback
180 * Purpose: Pass received packet along to the callback routine for
181 * the appropriate channel
184 * Input: packet The received packet.
188 * Post-conditions: The Target-to-Host sequence number for the channel
189 * will have been incremented.
191 static void FireCallback(Packet *packet)
197 * is this a sensible channel number?
199 chan = *(packet->pk_buffer);
200 if (invalidChannelID(chan))
202 printf("ERROR: invalid ChannelID received from target\n");
205 * free the packet's resources, 'cause no-one else will
207 DevSW_FreePacket(packet);
212 * looks OK - increment sequence number, and pass packet to callback
214 ch = channels + chan;
215 (ch->callback)(packet, ch->callback_state);
218 /**********************************************************************/
221 * These are the externally visible functions. They are documented
224 void Adp_addToQueue(Packet **head, Packet *newpkt)
227 * this is a bit of a hack
232 * make sure that the hack we are about to use will work as expected
234 ASSERT(&(((Packet *)0)->pk_next) == 0, "bad struct Packet layout");
237 printf("Adp_addToQueue(%p, %p)\n", head, newpkt);
241 * here's the hack - it relies upon the next
242 * pointer being at the start of Packet.
244 pk = (Packet *)(head);
247 * skip to the end of the queue
249 while (pk->pk_next != NULL)
253 * now add the new element
255 newpkt->pk_next = NULL;
256 pk->pk_next = newpkt;
259 Packet *Adp_removeFromQueue(Packet **head)
271 AdpErrs Adp_OpenDevice(const char *name, const char *arg,
272 unsigned int heartbeat_on)
279 printf("Adp_OpenDevice(%s, %s)\n", name, arg ? arg : "<NULL>");
282 heartbeat_configured = heartbeat_on;
283 if (deviceToUse != NULL)
284 return adp_device_already_open;
286 for (i = 0; (deviceToUse = devices[i]) != NULL; ++i)
287 if (DevSW_Match(deviceToUse, name, arg) == adp_ok)
290 if (deviceToUse == NULL)
291 return adp_device_not_found;
294 * we seem to have found a suitable device driver, so try to open it
296 if ((retc = DevSW_Open(deviceToUse, name, arg, DC_DBUG)) != adp_ok)
298 /* we don't have a device to use */
304 * there is no explicit open on channels any more, so
305 * initialise state for all channels.
307 for (chan = 0; chan < CI_NUM_CHANNELS; ++chan)
309 struct Channel *ch = channels + chan;
311 ch->callback = DummyCallback;
312 ch->callback_state = NULL;
320 AdpErrs Adp_CloseDevice(void)
325 printf("Adp_CloseDevice\n");
328 if (deviceToUse == NULL)
329 return adp_device_not_open;
331 heartbeat_enabled = FALSE;
333 retc = DevSW_Close(deviceToUse, DC_DBUG);
336 * we have to clear deviceToUse, even when the lower layers
337 * faulted the close, otherwise the condition will never clear
340 WARN("DevSW_Close faulted the call");
346 AdpErrs Adp_Ioctl(int opcode, void *args)
349 printf("Adp_Ioctl\n");
352 if (deviceToUse == NULL)
353 return adp_device_not_open;
355 return DevSW_Ioctl(deviceToUse, opcode, args);
358 AdpErrs Adp_ChannelRegisterRead(const ChannelID chan,
359 const ChannelCallback cbfunc,
363 printf("Adp_ChannelRegisterRead(%d, %p, %x)\n", chan, cbfunc, cbstate);
366 if (deviceToUse == NULL)
367 return adp_device_not_open;
369 if (invalidChannelID(chan))
370 return adp_bad_channel_id;
374 channels[chan].callback = DummyCallback;
375 channels[chan].callback_state = NULL;
379 channels[chan].callback = cbfunc;
380 channels[chan].callback_state = cbstate;
386 AdpErrs Adp_ChannelRead(const ChannelID chan, Packet **packet)
391 printf("Adp_ChannelRead(%d, %x)\n", chan, *packet);
394 if (deviceToUse == NULL)
395 return adp_device_not_open;
397 if (invalidChannelID(chan))
398 return adp_bad_channel_id;
401 * if a callback has already been registered for this
402 * channel, then we do not allow this blocking read.
404 ch = channels + chan;
405 if (ch->callback != DummyCallback)
406 return adp_callback_already_registered;
409 * OK, use our own callback to wait for a packet to arrive
412 ch->callback = BlockingCallback;
413 ch->callback_state = packet;
417 * keep polling until a packet appears for this channel
419 while (((volatile Packet *)(*packet)) == NULL)
421 * this call will block until a packet is read on any channel
423 Adp_AsynchronousProcessing(async_block_on_read);
426 * OK, the packet has arrived: clear the callback
428 ch->callback = DummyCallback;
429 ch->callback_state = NULL;
434 static AdpErrs ChannelWrite(
435 const ChannelID chan, Packet *packet, AsyncMode mode)
441 printf( "Adp_ChannelWrite(%d, %x)\n", chan, packet );
444 if (deviceToUse == NULL)
445 return adp_device_not_open;
447 if (invalidChannelID(chan))
448 return adp_bad_channel_id;
451 * fill in the channels header at the start of this buffer
453 ch = channels + chan;
454 cptr = packet->pk_buffer;
457 packet->pk_length += CHAN_HEADER_SIZE;
460 * OK, add this packet to the write queue, and try to flush it out
463 Adp_addToQueue(&writeQueueSend, packet);
464 Adp_AsynchronousProcessing(mode);
469 AdpErrs Adp_ChannelWrite(const ChannelID chan, Packet *packet) {
470 return ChannelWrite(chan, packet, async_block_on_write);
473 AdpErrs Adp_ChannelWriteAsync(const ChannelID chan, Packet *packet) {
474 return ChannelWrite(chan, packet, async_block_on_nothing);
477 static AdpErrs send_resend_msg(DeviceID devid) {
480 * Send a resend message, usually in response to a bad packet or
481 * a resend request */
483 packet = DevSW_AllocatePacket(CF_DATA_BYTE_POS);
484 packet->pk_buffer[CF_CHANNEL_BYTE_POS] = CI_PRIVATE;
485 packet->pk_buffer[CF_HOME_SEQ_BYTE_POS] = HomeSeq;
486 packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS] = OppoSeq;
487 packet->pk_buffer[CF_FLAGS_BYTE_POS] = CF_RELIABLE | CF_RESEND;
488 packet->pk_length = CF_DATA_BYTE_POS;
489 return DevSW_Write(deviceToUse, packet, devid);
492 static AdpErrs check_seq(unsigned char msg_home, unsigned char msg_oppo) {
497 * check if we have got an ack for anything and if so remove it from the
500 if (msg_home == (unsigned char)(OppoSeq+1)) {
502 * arrived in sequence can increment our opposing seq number and remove
503 * the relevant packet from our queue
504 * check that the packet we're going to remove really is the right one
506 tmp_pkt = writeQueueRoot;
507 while ((tmp_pkt->pk_next != NULL) &&
508 (tmp_pkt->pk_next->pk_buffer[CF_HOME_SEQ_BYTE_POS]
510 tmp_pkt = tmp_pkt->pk_next;
513 if (tmp_pkt->pk_next == NULL) {
515 printf("trying to remove a non existant packet\n");
517 return adp_bad_packet;
520 Packet *tmp = tmp_pkt->pk_next;
522 printf("removing a packet from the root queue\n");
524 tmp_pkt->pk_next = tmp_pkt->pk_next->pk_next;
525 /* remove the appropriate packet */
526 DevSW_FreePacket(tmp);
530 else if (msg_home < (unsigned char) (OppoSeq+1)){
531 /* already received this message */
533 printf("sequence numbers low\n");
537 else { /* we've missed something */
539 printf("sequence numbers high\n");
545 static unsigned long tv_diff(const struct timeval *time_now,
546 const struct timeval *time_was)
548 return ( ((time_now->tv_sec * 1000000) + time_now->tv_usec)
549 - ((time_was->tv_sec * 1000000) + time_was->tv_usec) );
552 #if !defined(__unix) && !defined(__CYGWIN32__)
553 static void gettimeofday( struct timeval *time_now, void *dummy )
557 time_now->tv_sec = t/CLOCKS_PER_SEC;
558 time_now->tv_usec = (t%CLOCKS_PER_SEC)*(1000000/CLOCKS_PER_SEC);
562 static AdpErrs pacemaker(void)
566 packet = DevSW_AllocatePacket(CF_DATA_BYTE_POS);
567 if (packet == NULL) {
568 printf("ERROR: could not allocate a packet in pacemaker()\n");
569 return adp_malloc_failure;
571 packet->pk_buffer[CF_CHANNEL_BYTE_POS] = CI_PRIVATE;
572 packet->pk_buffer[CF_HOME_SEQ_BYTE_POS] = HomeSeq;
573 packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS] = OppoSeq;
574 packet->pk_buffer[CF_FLAGS_BYTE_POS] = CF_RELIABLE | CF_HEARTBEAT;
575 packet->pk_length = CF_DATA_BYTE_POS;
576 return DevSW_Write(deviceToUse, packet, DC_DBUG);
579 #ifdef FAKE_BAD_LINE_RX
580 static AdpErrs fake_bad_line_rx( const Packet *const packet, AdpErrs adp_err )
582 static unsigned int bl_num = 0;
584 if ( (packet != NULL)
586 && ((bl_num % FAKE_BAD_LINE_RX) == 0))
588 printf("DEBUG: faking a bad packet\n");
589 return adp_bad_packet;
593 #endif /* def FAKE_BAD_LINE_RX */
595 #ifdef FAKE_BAD_LINE_TX
596 static unsigned char tmp_ch;
598 static void fake_bad_line_tx( void )
600 static unsigned int bl_num = 0;
602 /* give the thing a chance to boot then try corrupting stuff */
603 if ( (bl_num++ >= 20) && ((bl_num % FAKE_BAD_LINE_TX) == 0))
605 printf("DEBUG: faking a bad packet for tx\n");
606 tmp_ch = writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS];
607 writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS] = 77;
611 static void unfake_bad_line_tx( void )
613 static unsigned int bl_num = 0;
616 * must reset the packet so that its not corrupted when we
619 if ( (bl_num >= 20) && ((bl_num % FAKE_BAD_LINE_TX) != 0))
621 writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS] = tmp_ch;
624 #endif /* def FAKE_BAD_LINE_TX */
627 * NOTE: we are assuming that a resolution of microseconds will
628 * be good enough for the purporses of the heartbeat. If this proves
629 * not to be the case then we may need a rethink, possibly using
632 static struct timeval time_now;
633 static struct timeval time_lastalive;
635 static void async_process_dbug_read( const AsyncMode mode,
636 bool *const finished )
639 unsigned int msg_home, msg_oppo;
642 adp_err = DevSW_Read(deviceToUse, DC_DBUG, &packet,
643 mode == async_block_on_read );
645 #ifdef FAKE_BAD_LINE_RX
646 adp_err = fake_bad_line_rx( packet, adp_err );
649 if (adp_err == adp_bad_packet) {
650 /* We got a bad packet, ask for a resend, send a resend message */
652 printf("received a bad packet\n");
654 send_resend_msg(DC_DBUG);
656 else if (packet != NULL)
658 /* update the heartbeat clock */
659 gettimeofday(&time_lastalive, NULL);
662 * we got a live one here - were we waiting for it?
664 if (mode == async_block_on_read)
669 if (packet->pk_length < CF_DATA_BYTE_POS) {
670 /* we've got a packet with no header information! */
671 printf("ERROR: packet with no transport header\n");
672 send_resend_msg(DC_DBUG);
679 * TODO: Check to see if its acknowledgeing anything, remove
680 * those packets it is from the queue. If its a retrans add the
681 * packets to the queue
683 msg_home = packet->pk_buffer[CF_HOME_SEQ_BYTE_POS];
684 msg_oppo = packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS];
686 printf("msg seq numbers are hseq 0x%x oseq 0x%x\n",
688 for (c=0;c<packet->pk_length;c++)
689 printf("%02.2x", packet->pk_buffer[c]);
692 /* now was it a resend request? */
693 if ((packet->pk_buffer[CF_FLAGS_BYTE_POS])
695 /* we've been asked for a resend so we had better resend */
697 * I don't think we can use a resend as acknowledgement for
698 * anything so lets not do this for the moment
699 * check_seq(msg_home, msg_oppo);
702 printf("received a resend request\n");
704 if (HomeSeq != msg_oppo) {
706 /* need to resend from msg_oppo +1 upwards */
707 DevSW_FreePacket(packet);
709 /* find the correct packet to resend from */
710 packet = writeQueueRoot;
711 while (((packet->pk_next) != NULL) && !found) {
712 if ((packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS])
717 packet = packet->pk_next;
720 panic("trying to resend non-existent packets\n");
723 else if (OppoSeq != msg_home) {
725 * send a resend request telling the target where we think
728 DevSW_FreePacket(packet);
729 send_resend_msg(DC_DBUG);
733 /* not a resend request, lets check the sequence numbers */
735 if ((packet->pk_buffer[CF_CHANNEL_BYTE_POS] != CI_HBOOT) &&
736 (packet->pk_buffer[CF_CHANNEL_BYTE_POS] != CI_TBOOT)) {
737 adp_err = check_seq(msg_home, msg_oppo);
738 if (adp_err == adp_seq_low) {
739 /* we have already received this packet so discard */
740 DevSW_FreePacket(packet);
742 else if (adp_err == adp_seq_high) {
744 * we must have missed a packet somewhere, discard this
745 * packet and tell the target where we are
747 DevSW_FreePacket(packet);
748 send_resend_msg(DC_DBUG);
752 * now pass the packet to whoever is waiting for it
754 FireCallback(packet);
757 FireCallback(packet);
762 * now pass the packet to whoever is waiting for it
764 FireCallback(packet);
769 static void async_process_appl_read(void)
774 /* see if there is anything for the DC_APPL channel */
775 adp_err = DevSW_Read(deviceToUse, DC_APPL, &packet, FALSE);
777 if (adp_err == adp_ok && packet != NULL)
779 /* got an application packet on a shared device */
782 printf("GOT DC_APPL PACKET: len %d\nData: ", packet->pk_length);
785 for ( c = 0; c < packet->pk_length; ++c )
786 printf( "%02X ", packet->pk_buffer[c] );
791 if (dc_appl_handler != NULL)
793 dc_appl_handler( deviceToUse, packet );
797 /* for now, just free it!! */
799 printf("no handler - dropping DC_APPL packet\n");
801 DevSW_FreePacket( packet );
806 static void async_process_write( const AsyncMode mode,
807 bool *const finished )
812 static unsigned int num_written = 0;
816 * NOTE: here we rely in the fact that any packet in the writeQueueSend
817 * section of the queue will need its sequence number setting up while
818 * and packet in the writeQueueRoot section will have its sequence
819 * numbers set up from when it was first sent so we can easily look
820 * up the packet numbers when(if) we want to resend the packet.
824 if (writeQueueSend!=NULL)
825 printf("written 0x%x\n",num_written += writeQueueSend->pk_length);
828 * give the switcher a chance to complete any partial writes
830 if (DevSW_FlushPendingWrite(deviceToUse) == adp_write_busy)
832 /* no point trying a new write */
837 * now see whether there is anything to write
843 printf("resending hseq 0x%x oseq 0x%x\n",
844 packet->pk_buffer[CF_HOME_SEQ_BYTE_POS],
845 packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS]);
848 else if (writeQueueSend != NULL) {
850 /* set up the sequence number on the packet */
851 packet = writeQueueSend;
853 (writeQueueSend->pk_buffer[CF_OPPO_SEQ_BYTE_POS])
855 (writeQueueSend->pk_buffer[CF_HOME_SEQ_BYTE_POS])
857 (writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS])
860 printf("sending packet with hseq 0x%x oseq 0x%x\n",
861 writeQueueSend->pk_buffer[CF_HOME_SEQ_BYTE_POS],
862 writeQueueSend->pk_buffer[CF_OPPO_SEQ_BYTE_POS]);
867 if (packet != NULL) {
870 #ifdef FAKE_BAD_LINE_TX
874 dev_err = DevSW_Write(deviceToUse, packet, DC_DBUG);
875 if (dev_err == adp_ok) {
878 /* check to see if we've recovered yet */
879 if ((packet->pk_next) == NULL){
881 printf("we have recovered\n");
886 resend_pkt = resend_pkt->pk_next;
891 * move the packet we just sent from the send queue to the root
893 Packet *tmp_pkt, *tmp;
895 # ifdef FAKE_BAD_LINE_TX
896 unfake_bad_line_tx();
899 tmp_pkt = writeQueueSend;
900 writeQueueSend = writeQueueSend->pk_next;
901 tmp_pkt->pk_next = NULL;
902 if (writeQueueRoot == NULL)
903 writeQueueRoot = tmp_pkt;
905 tmp = writeQueueRoot;
906 while (tmp->pk_next != NULL) {
909 tmp->pk_next = tmp_pkt;
912 #else /* not RETRANS */
914 * switcher has taken the write, so remove it from the
915 * queue, and free its resources
917 DevSW_FreePacket(Adp_removeFromQueue(&writeQueueSend));
918 #endif /* if RETRANS ... else ... */
920 if (mode == async_block_on_write)
921 *finished = DevSW_WriteFinished(deviceToUse);
923 } /* endif write ok */
925 else /* packet == NULL */
927 if (mode == async_block_on_write)
928 *finished = DevSW_WriteFinished(deviceToUse);
932 static void async_process_heartbeat( void )
934 /* check to see whether we need to send a heartbeat */
935 gettimeofday(&time_now, NULL);
937 if (tv_diff(&time_now, &time_lastalive) >= HEARTRATE)
940 * if we've not booted then don't do send a heartrate the link
941 * must be reliable enough for us to boot without any clever stuff,
942 * if we can't do this then theres little chance of the link staying
943 * together even with the resends etc
945 if (heartbeat_enabled) {
946 gettimeofday(&time_lastalive, NULL);
952 static void async_process_callbacks( void )
954 /* call any registered asynchronous callbacks */
956 for ( i = 0; i < num_async_callbacks; ++i )
957 async_callbacks[i]( deviceToUse, &time_now );
960 void Adp_AsynchronousProcessing(const AsyncMode mode)
962 bool finished = FALSE;
964 unsigned int wc = 0, dc = 0, ac = 0, hc = 0;
965 # define INC_COUNT(x) ((x)++)
967 # define INC_COUNT(x)
970 if ((time_lastalive.tv_sec == 0) && (time_lastalive.tv_usec == 0)) {
971 /* first time through, needs initing */
972 gettimeofday(&time_lastalive, NULL);
978 async_process_write( mode, &finished );
981 if ( ! finished && mode != async_block_on_write )
983 async_process_dbug_read( mode, &finished );
987 if ( ! finished && mode != async_block_on_write )
989 async_process_appl_read();
995 if (heartbeat_configured)
996 async_process_heartbeat();
997 async_process_callbacks();
1001 } while (!finished && mode != async_block_on_nothing);
1004 if ( mode != async_block_on_nothing )
1005 printf( "Async: %s - w %d, d %d, a %d, h %d\n",
1006 mode == async_block_on_write ? "blk_write" : "blk_read",
1012 * install a handler for DC_APPL packets (can be NULL), returning old one.
1014 DC_Appl_Handler Adp_Install_DC_Appl_Handler(const DC_Appl_Handler handler)
1016 DC_Appl_Handler old_handler = dc_appl_handler;
1019 printf( "Installing DC_APPL handler %x (old %x)\n", handler, old_handler );
1022 dc_appl_handler = handler;
1028 * add an asynchronous processing callback to the list
1029 * TRUE == okay, FALSE == no more async processing slots
1031 bool Adp_Install_Async_Callback( const Adp_Async_Callback callback_proc )
1033 if ( num_async_callbacks < MAX_ASYNC_CALLBACKS && callback_proc != NULL )
1035 async_callbacks[num_async_callbacks] = callback_proc;
1036 ++num_async_callbacks;
1045 * delay for a given period (in microseconds)
1047 void Adp_delay(unsigned int period)
1052 printf("delaying for %d microseconds\n", period);
1054 tv.tv_sec = (period / 1000000);
1055 tv.tv_usec = (period % 1000000);
1057 (void)select(0, NULL, NULL, NULL, &tv);
1060 /* EOF hostchan.c */