1 /* $NetBSD: eshconfig.c,v 1.8 2008/05/02 19:59:19 xtraeme Exp $ */
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 * This code contributed to The NetBSD Foundation by Kevin M. Lahey
8 * of the Numerical Aerospace Simulation Facility, NASA Ames Research
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
35 __RCSID("$NetBSD: eshconfig.c,v 1.8 2008/05/02 19:59:19 xtraeme Exp $");
38 #include <sys/param.h>
39 #include <sys/socket.h>
40 #include <sys/ioctl.h>
41 #include <sys/sockio.h>
45 #include <net/if_dl.h>
46 #include <net/if_media.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
58 #include <dev/ic/rrunnerreg.h>
59 #include <dev/ic/rrunnervar.h>
62 * Create a simple pair of tables to map possible burst DMA values
63 * to the values required by the RoadRunner.
71 struct map_dma read_dma_map
[] = {{0, RR_PS_READ_DISABLE
},
76 {128, RR_PS_READ_128
},
77 {256, RR_PS_READ_256
},
78 {1024, RR_PS_READ_1024
},
81 struct map_dma write_dma_map
[] = {{0, RR_PS_WRITE_DISABLE
},
86 {128, RR_PS_WRITE_128
},
87 {256, RR_PS_WRITE_256
},
88 {1024, RR_PS_WRITE_1024
},
92 * The RunCode is composed of separate segments, each of which has a
93 * starting address in SRAM memory (for running) and in EEPROM
104 static u_int32_t do_map
__P((int, struct map_dma
*));
105 static void eeprom_upload
__P((const char *));
106 static void eeprom_download
__P((const char *));
107 static u_int32_t rr_checksum
__P((const u_int32_t
*, int));
108 static void esh_tune
__P((void));
109 static void esh_tune_eeprom
__P((void));
110 static void esh_tuning_stats
__P((void));
111 static void esh_stats
__P((int));
112 static void esh_reset
__P((void));
113 static int drvspec_ioctl
__P((char *, int, int, int, caddr_t
));
114 static void usage
__P((void));
115 int main
__P((int, char *[]));
119 char name
[30] = "esh0";
122 #define RR_EE_SIZE 8192
123 u_int32_t eeprom
[RR_EE_SIZE
];
124 u_int32_t runcode
[RR_EE_SIZE
];
130 * We defined a driver-specific socket ioctl to allow us to tweak
131 * the characteristics of network devices. This routine will
132 * provide a shortcut to calling this routine, which would otherwise
133 * require lots of costly and annoying setup.
137 drvspec_ioctl(char *lname
, int fd
, int cmd
, int len
, caddr_t data
)
139 strcpy(ifd
.ifd_name
, lname
);
144 return ioctl(fd
, SIOCSDRVSPEC
, (caddr_t
) &ifd
);
150 fprintf(stderr
, "eshconfig -- configure Essential Communications "
152 fprintf(stderr
, "-b burst size for read\n");
153 fprintf(stderr
, "-c burst size for write:\n");
154 fprintf(stderr
, "\t0 (no limit), 5, 16, 32, 64, 128, 256, 1024\n");
155 fprintf(stderr
, "-d download filename\n");
156 fprintf(stderr
, "-e write data to EEPROM\n");
157 fprintf(stderr
, "-m minimum bytes DMA per direction\n");
158 fprintf(stderr
, "-r bytes before DMA starts for read\n");
159 fprintf(stderr
, "-s show statistics (-ss to display only non-zero)\n");
160 fprintf(stderr
, "-t show tuning parameters\n");
161 fprintf(stderr
, "-u upload filename [not working]\n");
162 fprintf(stderr
, "-w bytes before DMA starts for write\n");
163 fprintf(stderr
, "-i interrupt delay in usecs\n");
164 fprintf(stderr
, "-x reset interface\n");
170 * Map between values for burst DMA sizes and the values expected by
171 * the RoadRunner chip.
175 do_map(int value
, struct map_dma
*map
)
179 for (i
= 0; map
[i
].value
!= -1; i
++)
180 if (value
== map
[i
].value
)
181 return map
[i
].rr_value
;
188 * Reverse the mapping.
192 do_map_dma(uint32_t value
, struct map_dma
*map
)
196 for (i
= 0; map
[i
].value
!= -1; i
++)
197 if (value
== map
[i
].rr_value
)
204 int dma_thresh_read
= -1;
205 int dma_thresh_write
= -1;
206 int dma_min_grab
= -1;
207 int dma_max_read
= -1;
208 int dma_max_write
= -1;
210 int interrupt_delay
= -1;
213 int get_tuning_stats
= 0;
214 int eeprom_write
= 0;
215 char *eeprom_download_filename
= NULL
;
216 char *eeprom_upload_filename
= NULL
;
219 struct rr_tuning rr_tune
;
220 struct rr_eeprom rr_eeprom
;
221 struct rr_stats rr_stats
;
230 /* Parse command-line options */
232 while ((ch
= getopt(argc
, argv
, "b:c:d:ei:m:r:stu:w:x")) != -1) {
235 dma_max_read
= atoi(optarg
);
238 dma_max_write
= atoi(optarg
);
241 eeprom_download_filename
= optarg
;
247 interrupt_delay
= atoi(optarg
);
250 dma_min_grab
= atoi(optarg
);
253 dma_thresh_read
= atoi(optarg
);
262 eeprom_upload_filename
= optarg
;
265 dma_thresh_write
= atoi(optarg
);
281 (void) strncpy(name
, argv
[0], sizeof(name
));
285 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
289 if (eeprom_upload_filename
)
290 eeprom_upload(eeprom_upload_filename
);
292 if (eeprom_download_filename
)
293 eeprom_download(eeprom_download_filename
);
296 esh_stats(get_stats
);
299 if (drvspec_ioctl(name
, s
, EIOCGTUNE
, sizeof(struct rr_tuning
),
300 (caddr_t
) &rr_tune
) < 0) {
301 err(1, "ioctl(EIOCGTUNE)");
304 if (get_tuning_stats
) {
310 if (eeprom_write
|| dma_thresh_read
!= -1 ||
311 dma_thresh_write
!= -1 ||
312 dma_min_grab
!= -1 ||
313 dma_max_read
!= -1 ||
314 dma_max_write
!= -1 ||
315 interrupt_delay
!= -1) {
331 dma_max_read
= do_map(dma_max_read
, read_dma_map
);
332 if (dma_max_read
!= -1) {
333 rr_tune
.rt_pci_state
&= ~RR_PS_READ_MASK
;
334 rr_tune
.rt_pci_state
|= dma_max_read
;
337 dma_max_write
= do_map(dma_max_write
, write_dma_map
);
338 if (dma_max_write
!= -1) {
339 rr_tune
.rt_pci_state
&= ~RR_PS_WRITE_MASK
;
340 rr_tune
.rt_pci_state
|= dma_max_write
;
343 if (dma_min_grab
!= -1) {
344 if ((dma_min_grab
& (RR_PS_MIN_DMA_MASK
>> RR_PS_MIN_DMA_SHIFT
))
347 rr_tune
.rt_pci_state
&= ~RR_PS_MIN_DMA_MASK
;
348 rr_tune
.rt_pci_state
|=
349 (dma_min_grab
<< RR_PS_MIN_DMA_SHIFT
);
352 if (dma_thresh_write
!= -1) {
353 if (dma_thresh_write
< 1 || dma_thresh_write
> RR_DW_THRESHOLD_MAX
)
355 rr_tune
.rt_dma_write_state
&= ~RR_DW_THRESHOLD_MASK
;
356 rr_tune
.rt_dma_write_state
|=
357 dma_thresh_write
<< RR_DW_THRESHOLD_SHIFT
;
360 if (dma_thresh_read
!= -1) {
361 if (dma_thresh_read
< 1 || dma_thresh_read
> RR_DR_THRESHOLD_MAX
)
363 rr_tune
.rt_dma_read_state
&= ~RR_DR_THRESHOLD_MASK
;
364 rr_tune
.rt_dma_read_state
|=
365 dma_thresh_read
<< RR_DR_THRESHOLD_SHIFT
;
368 rr_tune
.rt_stats_timer
= ESH_STATS_TIMER_DEFAULT
;
370 if (interrupt_delay
!= -1)
371 rr_tune
.rt_interrupt_timer
= interrupt_delay
;
373 if (drvspec_ioctl(name
, s
, EIOCSTUNE
, sizeof(struct rr_tuning
),
374 (caddr_t
) &rr_tune
) < 0)
380 * Store the current tuning data into the eeprom.
386 #define LAST (RR_EE_HEADER_CHECKSUM / RR_EE_WORD_LEN)
387 #define FIRST (RR_EE_HEADER_CHECKSUM / RR_EE_WORD_LEN)
389 u_int32_t tuning_data
[LAST
+ 1];
391 rr_eeprom
.ifr_buffer
= tuning_data
;
392 rr_eeprom
.ifr_length
= sizeof(tuning_data
);
393 rr_eeprom
.ifr_offset
= 0;
395 if (drvspec_ioctl(name
, s
, EIOCGEEPROM
, sizeof(struct rr_eeprom
),
396 (caddr_t
) &rr_eeprom
) == -1)
397 err(6, "ioctl to retrieve tuning information from EEPROM");
399 tuning_data
[RR_EE_PCI_STATE
/ RR_EE_WORD_LEN
] =
400 rr_tune
.rt_pci_state
;
401 tuning_data
[RR_EE_DMA_WRITE_STATE
/ RR_EE_WORD_LEN
] =
402 rr_tune
.rt_dma_write_state
;
403 tuning_data
[RR_EE_DMA_READ_STATE
/ RR_EE_WORD_LEN
] =
404 rr_tune
.rt_dma_read_state
;
405 tuning_data
[RR_EE_INTERRUPT_TIMER
/ RR_EE_WORD_LEN
] = rr_tune
.rt_interrupt_timer
;
406 tuning_data
[RR_EE_STATS_TIMER
/ RR_EE_WORD_LEN
] =
407 ESH_STATS_TIMER_DEFAULT
;
409 tuning_data
[RR_EE_HEADER_CHECKSUM
/ RR_EE_WORD_LEN
] =
410 rr_checksum(&tuning_data
[FIRST
], LAST
- FIRST
);
412 rr_eeprom
.ifr_buffer
= tuning_data
;
413 rr_eeprom
.ifr_length
= sizeof(tuning_data
);
414 rr_eeprom
.ifr_offset
= 0;
416 if (drvspec_ioctl(name
, s
, EIOCSEEPROM
, sizeof(struct rr_eeprom
),
417 (caddr_t
) &rr_eeprom
) == -1)
418 err(7, "ioctl to set tuning information from EEPROM");
423 * Upload the EEPROM from the card and store in the data file.
427 eeprom_upload(const char *filename
)
431 bzero(eeprom
, sizeof(eeprom
));
432 if ((fd
= open(filename
, O_WRONLY
| O_CREAT
, 0644)) < 0)
433 err(4, "Couldn't open %s for output", filename
);
435 rr_eeprom
.ifr_buffer
= eeprom
;
436 rr_eeprom
.ifr_length
= sizeof(eeprom
);
437 rr_eeprom
.ifr_offset
= 0;
439 if (drvspec_ioctl(name
, s
, EIOCGEEPROM
, sizeof(struct rr_eeprom
),
440 (caddr_t
) &rr_eeprom
) == -1)
441 err(5, "ioctl to retrieve all of EEPROM");
443 write(fd
, eeprom
, sizeof(eeprom
));
449 * Download into eeprom the contents of a file. The file is made up
450 * of ASCII text; the first three characters can be ignored, the next
451 * four hex characters define an address, the next two characters can
452 * be ignored, and the final eight hex characters are the data.
456 eeprom_download(const char *filename
)
459 struct rr_seg_descr
*segd
= NULL
, *nsegd
;
463 u_int32_t address
= 0;
464 u_int32_t last_address
= 0;
466 u_int32_t length
= 0;
467 int segment_start
= 0;
469 int seg_count_offset
;
479 /* Clear out eeprom storage space, then read in the value on the card */
481 bzero(eeprom
, sizeof(eeprom
));
482 bzero(runcode
, sizeof(runcode
));
484 rr_eeprom
.ifr_buffer
= eeprom
;
485 rr_eeprom
.ifr_length
= sizeof(eeprom
);
486 rr_eeprom
.ifr_offset
= 0;
487 if (drvspec_ioctl(name
, s
, EIOCGEEPROM
, sizeof(struct rr_eeprom
),
488 (caddr_t
) &rr_eeprom
) == -1)
489 err(5, "ioctl to retrieve EEPROM");
492 * Open the input file and proceed to read the data file, storing
493 * the data and counting the number of segments.
496 if ((fp
= fopen(filename
, "r")) == NULL
)
500 if (fgets(buffer
, sizeof(buffer
), fp
) == NULL
)
501 errx(3, "premature, unmarked end of file, line %d", line
);
504 if (!strncmp(buffer
+ 7, "01", 2)) { /* check for EOF marker... */
507 sscanf(buffer
, "%3s%4x%2s%8x%2s",
508 id
, &address
, pad
, &value
, pad
);
509 if (strcmp(id
, ":04") != 0)
510 errx(3, "bad initial id on line %d", line
);
514 * Check to see if we terminated a segment; this happens
515 * when we are at end of file, or we hit a non-sequential
516 * address value, or we see three or more zeroes in a row.
519 if ((length
== RR_EE_SEG_SIZE
|| eof
|| zero_count
>= 3 ||
520 (last_address
&& last_address
!= address
- 1)) && in_segment
) {
522 length
-= zero_count
;
523 segment_start
+= length
;
524 segd
[segment
].length
= length
;
526 printf("segment %d, %d words\n", segment
, length
);
527 last_address
= in_segment
= zero_count
= length
= 0;
534 /* Skip zero values starting a segment */
536 if (!in_segment
&& value
== 0)
538 last_address
= address
;
541 * If we haven't started a segment yet, do so now.
542 * Store away the address at which this code should be placed
543 * in memory and the address of the code in the EEPROM.
549 nsegd
= realloc(segd
, sizeof(struct rr_seg_descr
) * (segment
+ 1));
551 err(6, "couldn't realloc segment descriptor space");
554 segd
[segment
].start_addr
= address
* sizeof(u_int32_t
);
555 segd
[segment
].ee_addr
= segment_start
;
558 /* Keep track of consecutive zeroes */
560 if (in_segment
&& value
== 0)
565 /* Store away the actual data */
567 runcode
[segment_start
+ length
++] = value
;
571 /* Now that we have a segment count, fill in the EEPROM image. */
573 seg_count_offset
= eeprom
[RR_EE_RUNCODE_SEGMENTS
/ RR_EE_WORD_LEN
];
574 seg_count_offset
= (seg_count_offset
- RR_EE_OFFSET
) / RR_EE_WORD_LEN
;
575 seg_table_start
= seg_count_offset
+ 1;
576 phase2_checksum
= seg_table_start
+ 3 * segment
;
577 phase2_start
= eeprom
[RR_EE_PHASE2_EE_START
/ RR_EE_WORD_LEN
];
578 phase2_start
= (phase2_start
- RR_EE_OFFSET
) / RR_EE_WORD_LEN
;
580 printf("segment table start = %x, segments = %d\n",
581 seg_table_start
, eeprom
[seg_count_offset
]);
583 /* We'll fill in anything after the segment count, so clear it */
585 bzero(eeprom
+ seg_count_offset
,
586 sizeof(eeprom
) - seg_count_offset
* sizeof(eeprom
[0]));
588 eeprom
[seg_count_offset
] = segment
;
590 for (i
= 0; i
< segment
; i
++)
591 segd
[i
].ee_addr
= RR_EE_OFFSET
+
592 (segd
[i
].ee_addr
+ phase2_checksum
+ 1) * RR_EE_WORD_LEN
;
594 bcopy(segd
, &eeprom
[seg_table_start
],
595 sizeof(struct rr_seg_descr
) * segment
);
597 bcopy(runcode
, &eeprom
[phase2_checksum
+ 1],
598 segment_start
* sizeof(u_int32_t
));
600 eeprom
[phase2_checksum
] = rr_checksum(&eeprom
[phase2_start
],
601 phase2_checksum
- phase2_start
);
603 eeprom
[segment_start
+ phase2_checksum
+ 1] =
604 rr_checksum(&eeprom
[phase2_checksum
+ 1], segment_start
);
606 printf("phase2 checksum %x, runcode checksum %x\n",
607 eeprom
[phase2_checksum
],
608 eeprom
[segment_start
+ phase2_checksum
+ 1]);
610 rr_eeprom
.ifr_buffer
= eeprom
;
611 rr_eeprom
.ifr_length
= sizeof(eeprom
);
612 rr_eeprom
.ifr_offset
= 0;
613 if (drvspec_ioctl(name
, s
, EIOCSEEPROM
, sizeof(struct rr_eeprom
),
614 (caddr_t
) &rr_eeprom
) == -1)
615 err(5, "ioctl to retrieve EEPROM");
620 * Perform checksum on RunCode. Length is in words. Ugh.
624 rr_checksum(const u_int32_t
*data
, int length
)
626 u_int32_t checksum
= 0;
631 checksum
= 0 - checksum
;
635 struct stats_values
{
640 struct stats_values stats_values
[] = {
641 {0x04, "receive rings created"},
642 {0x08, "receive rings deleted"},
643 {0x0c, "interrupts"},
644 {0x10, "event overflows"},
645 {0x14, "invalid commands"},
646 {0x18, "DMA read errors"},
647 {0x1c, "DMA write errors"},
648 {0x20, "stats updates per timer"},
649 {0x24, "stats updates per host"},
652 {0x30, "link ready sync established"},
653 {0x34, "GLink errors"},
654 {0x38, "alternating flag errors"},
655 {0x3c, "overhead bit 8 synchronized"},
656 {0x40, "remote serial parity errors"},
657 {0x44, "remote parallel parity errors"},
658 {0x48, "remote loopback requested"},
659 {0x50, "transmit connections established"},
660 {0x54, "transmit connections rejected"},
661 {0x58, "transmit connections retried"},
662 {0x5c, "transmit connections timed out"},
663 {0x60, "transmit connections disconnected"},
664 {0x64, "transmit parity errors"},
665 {0x68, "packets sent"},
666 {0x74, "short first burst sent"},
667 {0x80, "transmit data not moving"},
668 {0x90, "receive connections accepted"},
669 {0x94, "receive connections rejected -- bad parity"},
670 {0x98, "receive connections rejected -- 64-bit width"},
671 {0x9c, "receive connections rejected -- buffers low"},
672 {0xa0, "receive connections disconnected"},
673 {0xa4, "receive connections with no data"},
674 {0xa8, "packets received"},
675 {0xb4, "short first burst received"},
676 {0xc0, "receive parity error"},
677 {0xc4, "receive LLRC error"},
678 {0xc8, "receive burst size error"},
679 {0xcc, "receive state error"},
680 {0xd0, "receive ready ULP"},
681 {0xd4, "receive invalid ULP"},
682 {0xd8, "receive packets flow control due to buffer space"},
683 {0xdc, "receive packets flow control due to descriptors"},
684 {0xe0, "receive ring fulls"},
685 {0xe4, "packet length errors"},
686 {0xe8, "packets with checksum error"},
687 {0xec, "packets dropped"},
688 {0xf0, "ring low on space"},
689 {0xf4, "data in ring at close"},
690 {0xf8, "receives to ring not moving data"},
691 {0xfc, "receiver idles"},
698 if (drvspec_ioctl(name
, s
, EIOCRESET
, 0, 0) < 0)
699 err(1, "ioctl(EIOCRESET)");
703 esh_stats(int lget_stats
)
709 if (drvspec_ioctl(name
, s
, EIOCGSTATS
, sizeof(struct rr_stats
),
710 (caddr_t
) &rr_stats
) < 0)
711 err(1, "ioctl(EIOCGTUNE)");
713 stats
= rr_stats
.rs_stats
;
715 value
= (((long long) stats
[0x78 / 4]) << 32) | stats
[0x7c / 4];
716 if (lget_stats
== 1 || value
> 0)
717 printf("%12lld bytes sent\n", value
);
718 value
= ((long long) stats
[0xb8 / 4] << 32) | stats
[0xbc / 4];
719 if (lget_stats
== 1 || value
> 0)
720 printf("%12lld bytes received\n", value
);
722 for (offset
= 0; stats_values
[offset
].offset
!= 0; offset
++) {
723 if (lget_stats
== 1 || stats
[stats_values
[offset
].offset
/ 4] > 0)
724 printf("%12d %s\n", stats
[stats_values
[offset
].offset
/ 4],
725 stats_values
[offset
].name
);
733 printf("rt_mode_and_status = %x\n",
734 rr_tune
.rt_mode_and_status
);
735 printf("rt_conn_retry_count = %x\n",
736 rr_tune
.rt_conn_retry_count
);
737 printf("rt_conn_retry_timer = %x\n",
738 rr_tune
.rt_conn_retry_timer
);
739 printf("rt_conn_timeout = %x\n", rr_tune
.rt_conn_timeout
);
740 printf("rt_stats_timer = %x\n", rr_tune
.rt_stats_timer
);
741 printf("rt_interrupt_timer = %x\n",
742 rr_tune
.rt_interrupt_timer
);
743 printf("rt_tx_timeout = %x\n", rr_tune
.rt_tx_timeout
);
744 printf("rt_rx_timeout = %x\n", rr_tune
.rt_rx_timeout
);
745 printf("rt_pci_state = %x"
746 " min DMA %x read max %x write max %x\n",
747 rr_tune
.rt_pci_state
,
748 (rr_tune
.rt_pci_state
& RR_PS_MIN_DMA_MASK
)
749 >> RR_PS_MIN_DMA_SHIFT
,
750 do_map_dma(rr_tune
.rt_pci_state
& RR_PS_READ_MASK
,
752 do_map_dma(rr_tune
.rt_pci_state
& RR_PS_WRITE_MASK
,
754 printf("rt_dma_write_state = %x\n",
755 rr_tune
.rt_dma_write_state
);
756 printf("rt_dma_read_state = %x\n", rr_tune
.rt_dma_read_state
);
757 printf("rt_driver_param = %x\n", rr_tune
.rt_driver_param
);