/* * trace_dump.c * ------------ * * Quick lash-up to drain the trace buffer of an Alteon gigabit ethernet card * * TJD April '99 * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "acenic_ioctls.h" typedef struct { int socket; struct ifreq ifr; struct acenic_ioc_req req; } alteon_st; alteon_st st; #define TRUE 1 #define FALSE 0 #define STARS 0x42424242 /* MIPS is big-endian but PCI but gives us little-endian values, so * the ioctl routines need to switch them to big_endian so GDB gets * the contents right. We can use ntohl, htonl to access control * register contents, &c. here in the stub. * * NB: 'offset' and card addresses are _host-endian_ and do not need htonl(). */ static __inline__ __u32 other_endian (__u32 val) { return (((val & 0xff) << 24) | ((val & 0xff00) << 8) | ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24)); } /* Read and write shared memory locations */ static __inline__ int read_smem (alteon_st *nic, __u32 offset, __u32 *dpr) { nic->req.cardoffset = offset; if (ioctl(nic->socket, ACENIC_IOCTL_READ_SMEM, &nic->ifr)) { *dpr = other_endian(nic->req.data); return FALSE; } *dpr = other_endian(nic->req.data); return TRUE; } static __inline__ int write_smem (alteon_st *nic, __u32 offset, __u32 data) { nic->req.cardoffset = offset; nic->req.data = other_endian(data); if (ioctl(nic->socket, ACENIC_IOCTL_WRITE_SMEM, &nic->ifr)) { return FALSE; } return TRUE; } static __inline__ void die (char *why) { fprintf (stderr, "\nPanic -- %s\n\n", why); exit (-1); } static void read_tbuf (__u32 offset, __u32 *buf) { /* Read a trace entry (8 32-bit items) into 'buf' */ __u32 frame_base, current; int i; read_smem(&st, 0x68, &frame_base); frame_base = htonl(frame_base); current = offset; for (i=0; i < 8; i++) { if ((current & 0xfffff800) != frame_base) { frame_base = (current & 0xfffff800); write_smem (&st, 0x68, ntohl(frame_base)); } read_smem(&st, (current & 0x7ff) + 0x800, buf + i); current += 4; } /* First 8 bytes are ASCII, rest are 32-bit values */ for (i = 2; i < 8; i++) buf[i] = ntohl(buf[i]); } int main (int argc, char **argv) { __u32 offset, tptr, tstart, tlen; __u32 entry[8]; /* argument */ if (argc != 2) die ("Usage: %s "); if (strlen(argv[1]) >= IFNAMSIZ) die ("i/f name too long"); if (geteuid() != 0) die ("must be root to access shared memory"); memset (&st, 0, sizeof (st)); /* Open a socket for our ioctls */ st.socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); /* Set up basic ioctl structure */ st.ifr.ifr_data = (char *)&st.req; strcpy(st.ifr.ifr_name, argv[optind]); /* Find the trace buffer */ offset = 0x650; /* Trace element pointer */ read_smem(&st, offset, &tptr); offset = 0x654; /* Trace buffer start */ read_smem(&st, offset, &tstart); offset = 0x658; /* Trace buffer length */ read_smem(&st, offset, &tlen); /* NIC is big-endian */ tptr = ntohl(tptr); tstart = ntohl(tstart); tlen = ntohl(tlen); printf ("Trace buffer is %i bytes at %#x.\n" "Trace pointer is at %#x\n\n" "String ID Time " "A B C D\n\n", tlen, tstart, tptr); /* dump that trace buffer */ while (tptr < (tstart + tlen)) { read_tbuf (tptr, entry); tptr += 32; if (entry[0] == STARS && entry[1] == STARS) { printf (" /------ %#010x %#010x %#010x %#010x %#010x %#010x\n", entry[2], entry[3], entry[4], entry[5], entry[6], entry[7]); } else { printf ("%8.8s %#010x %#010x %#010x %#010x %#010x %#010x\n", (char *) entry, entry[2], entry[3], entry[4], entry[5], entry[6], entry[7]); } } close (st.socket); return 0; } /* * EOF trace_dump.c */