nictools-pci-1.3.8.orig/0000755000175000017500000000000010264226143014017 5ustar alainalainnictools-pci-1.3.8.orig/alta-diag.c0000644000175000017500000007343610264216413016022 0ustar alainalain/* alta-diag.c: Diagnostic and setup for the Sundance "Alta" NIC. This is a diagnostic and EEPROM setup program for PCI adapters based on the following chips: Sundance ST201 "Alta" This file also contains the chip-independent diagnostic code. Copyright 1998-2002 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 Updates and additional information are available at http://www.scyld.com/diag/index.html http://scyld.com/expert/mii-status.html http://scyld.com/expert/NWay.html Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. To use this code under other terms requires an explicit license from the copyright holder. */ static char *version_msg = "alta-diag.c:v2.04 2/28/2005 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: alta-diag [-aEefFGhmqrRtvVwW] [-p ] [-[AF] ]\n" " For details and other options see http://www.scyld.com/diag/index.html\n"; static const char long_usage_msg[] = "Usage: %s [-aDfrRvVw] [-AF ] [-#]\n\ \n\ Show the internal state of a network adapter.\n\ \n\ The common usage is\n\ diag -aem\n\ \n\ Frequently used options are\n\ -a --show_all_registers Print all registers.\n\ -e --show-eeprom Dump EEPROM contents, \"-ee\" shows the details.\n\ -m --show_mii Print the MII transceiver state\n\ Using -mm monitors the link.\n\ -f --force Perform operation, even on a running NIC.\n\ \n\ To operate on a single NIC, or one that hasn't been automatically found:\n\ -# --card_num INDEX Operate on the specified card index.\n\ -p --port-base IOADDR Assume an adapter at the specified I/O address.\n\ -t --chip-type TYPE Specify adapter type (with '-p'). Use '-1' to\n\ list available types indicies.\n\ \n\ To change the persistent EEPROM settings\n\ -G --parameters PARMS Set adapter-specific parameters.\n\ -H --new-hwaddr 01:23:45:67:89:ab\n\ Set a new hardware station address.\n\ -w --write-EEPROM Actually write the new settings into the EEPROM.\n\ \n\ -D --debug\n\ -v --verbose Report each action taken.\n\ -V --version Emit version information.\n\ \n\ -A --advertise (See the mii-diag manual page.)\n\ "; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include #include /* The following are required only with unaligned field accesses. */ #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif /* No libmii.h or libflash.h yet, thus the declarations here. */ extern int show_mii_details(long ioaddr, int phy_id); extern int monitor_mii(long ioaddr, int phy_id); extern int flash_show(long addr_ioaddr, long data_ioaddr); extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename); extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename); extern int (*flash_in_hook)(long addr, int offset); extern void (*flash_out_hook)(long addr, int offset, int val); /* We should use __u8 .. __u32, but they are not always defined. */ typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; struct option longopts[] = { /* { name has_arg *flag val } */ {"card-num", 1, 0, '#'}, /* Operate on the specified card index. */ {"Advertise", 1, 0, 'A'}, {"base-address", 1, 0, 'p'}, {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Print a long usage message. */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; extern int sundance_diag(int vend_id, int dev_id, long ioaddr, int part_idx); /* Chip-specific flags. Yes, it's grungy to have the enum here. */ /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name from the kernel, a common name and the PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { const char *part_name; const char *proc_pci_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx); } pcidev_tbl[] = { { "Sundance Technology Alta", "Sundance Technology Alta", 0x1186, 0x1002, 0xffff, 0, 128, sundance_diag}, { 0, 0, 0, 0}, }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int nway_advertise = 0, fixed_speed = -1; int new_default_media = -1; /* Valid with libflash only. */ static unsigned int opt_flash_show = 0; static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int emergency_rewrite = 0; static int scan_proc_pci(int card_num); static int parse_media_type(const char *capabilities); static int get_media_index(const char *name); /* Chip-specific options, if any, go here. */ int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:hH:mp:qrRt:vVwWBL:S:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'A': nway_advertise = parse_media_type(optarg); break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 16); break; case 'h': fprintf(stderr, long_usage_msg, argv[0]); return 0; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtoul(optarg, NULL, 16); break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case 'W': opt_watch++; break; case 'B': opt_flash_show++; break; case 'L': opt_flash_loadfile = optarg; break; case 'S': opt_flash_dumpfile = optarg; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("Network adapter diagnostic: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for parsed contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n" " See http://www.scyld.com/expert/irq-conflict.html for more information.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if ((pci_devid >> 16) != pcidev_tbl[i].vendor || (pci_devid & pcidev_tbl[i].device_mask) != pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].part_name; i++) if (pcidev_tbl[i].proc_pci_name && strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Convert a text media name to a NWay capability word. */ static int parse_media_type(const char *capabilities) { const char *mtypes[] = { "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD", "10baseT", "10baseT-FD", "10baseT-HD", 0, }; int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,}; int i; if (debug) fprintf(stderr, "Advertise string is '%s'.\n", capabilities); for (i = 0; mtypes[i]; i++) if (strcasecmp(mtypes[i], capabilities) == 0) return cap_map[i]; if ((i = strtoul(capabilities, NULL, 16)) <= 0xffff) return i; fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities); return 0; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to indices. This matches the Digital Tulip SROM numbering, primarily because that is the most complete list. Other chips will have to map these number to their internal values. */ struct { char *name; int value; } mediamap[] = { { "10baseT", 0 }, { "10base2", 1 }, { "AUI", 2 }, { "100baseTx", 3 }, { "10baseT-FDX", 0x204 }, { "100baseTx-FDX", 0x205 }, { "100baseT4", 6 }, { "100baseFx", 7 }, { "100baseFx-FDX", 8 }, { "MII", 11 }, { "Autosense", 0x0800 }, { 0, 0 }, }; static int get_media_index(const char *name) { int i; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) return i; if (name && atoi(name) >= 00) return atoi(name); fprintf(stderr, "Invalid interface specified: it must be one of\n "); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %s", mediamap[i].name); fprintf(stderr, ".\n"); return -1; } /* Chip-specific section. */ /* The chip-specific section for the Sundance Alta. */ #include static int eeprom_addr_len(long ioaddr); static int read_eeprom(long ioaddr, int location, int addr_len); static void write_eeprom(long ioaddr, int index, int value, int addr_len); int mdio_read(long ioaddr, int phy_id, int location); void mdio_write(long ioaddr, int phy_id, int location, int value); /* Offsets to the various registers. Accesses need not be longword aligned. */ enum alta_offsets { DMACtrl=0x00, TxListPtr=0x04, TxDMACtrl=0x08, TxDescPoll=0x0a, RxDMAStatus=0x0c, RxListPtr=0x10, RxDMACtrl=0x14, RxDescPoll=0x16, LEDCtrl=0x1a, ASICCtrl=0x30, EEData=0x34, EECtrl=0x36, TxThreshold=0x3c, FlashAddr=0x40, FlashData=0x44, TxStatus=0x46, DownCounter=0x48, IntrClear=0x4a, IntrEnable=0x4c, IntrStatus=0x4e, MACCtrl0=0x50, MACCtrl1=0x52, StationAddr=0x54, MaxTxSize=0x5A, RxMode=0x5c, MIICtrl=0x5e, MulticastFilter0=0x60, MulticastFilter1=0x64, RxOctetsLow=0x68, RxOctetsHigh=0x6a, TxOctetsLow=0x6c, TxOctetsHigh=0x6e, TxFramesOK=0x70, RxFramesOK=0x72, StatsCarrierError=0x74, StatsLateColl=0x75, StatsMultiColl=0x76, StatsOneColl=0x77, StatsTxDefer=0x78, RxMissed=0x79, StatsTxXSDefer=0x7a, StatsTxAbort=0x7b, StatsBcastTx=0x7c, StatsBcastRx=0x7d, StatsMcastTx=0x7e, StatsMcastRx=0x7f, }; /* The textual names of the interrupt indications. */ static const char *intr_names[16] ={ "Interrupt summary", "PCI bus fault", "Tx Done Event", "MAC Control Frame", "Receive done", "Receive started", "Software triggered interrupt", "Update statistics", "Link status changed", "Tx DMA done", "Rx DMA done", }; /* Bits in the RxMode register. */ enum rx_mode_bits { AcceptAllIPMulti=0x20, AcceptMultiHash=0x10, AcceptAll=0x08, AcceptBroadcast=0x04, AcceptMulticast=0x02, AcceptMyPhys=0x01, }; /* Values read from the EEPROM, and the new image. */ #define MAX_EEPROM_SIZE 256 static u16 eeprom_contents[MAX_EEPROM_SIZE]; static u16 new_ee_contents[MAX_EEPROM_SIZE]; #define EEPROM_SA_OFFSET 0x10 /* In words! */ #define EEPROM_CSUM_OFFSET 0 /* 0 means none. */ /* Support for Flash operations. */ static int alta_flash_in(long ioaddr, int offset) { outl(offset, ioaddr + FlashAddr); return inb(ioaddr + FlashData); } #ifdef LIBFLASH static void alta_flash_out(long ioaddr, int offset, int val) { outl(offset, ioaddr + FlashAddr); outb(val, ioaddr + FlashData); } #endif struct config_name { int val, mask; const char*name;} static rcvr_mode[] = { {0x05, 0xff, "Normal unicast"}, {0x07, 0xff, "Normal unicast and all multicast"}, {0x15, 0xff, "Normal unicast and hashed multicast"}, {0x08, 0x08, "Promiscuous"}, {0x00, 0xff, "Uninitialized/disabled"}, {0x00, 0x00, "Unknown/invalid"}, }; int sundance_diag(int vendor_id, int device_id, long ioaddr, int part_idx) { int chip_active = 0; int rx_mode = inb(ioaddr + RxMode); int tx_status = inb(ioaddr + TxStatus); int mac_mode = inw(ioaddr + MACCtrl0); int ee_addr_len = 6, eeprom_size = 64; int i; if (mac_mode == 0xffff) printf("\nThe device appears not to exist!\n" "The following info is probably bogus.\n\n"); /* Start with the unique, and show the basic status. */ printf(" Station address "); for (i = 0; i < 5; i++) printf("%2.2x:", inb(ioaddr + StationAddr + i)); printf("%2.2x.\n", inb(ioaddr + StationAddr + i)); for (i = 0; rcvr_mode[i].mask; i++) if ((rx_mode & rcvr_mode[i].mask) == rcvr_mode[i].val) break; printf(" Receive mode is 0x%2.2x: %s.\n", rx_mode, rcvr_mode[i].name); printf(" MAC mode is %4.4x: %s duplex%s.\n", mac_mode, mac_mode & 0x20 ? "full" : "half", mac_mode & ~0x20 ? " NON-ETHERNET-STANDARD FEATURES SET" : ""); printf(" Tx status %2.2x, threshold %d.\n", tx_status, inw(ioaddr + TxThreshold)); if (tx_status && ! chip_active) { printf(" Tx status stack:"); for (i = 0; i < 32; i++) { printf(" %4.4x", inw(ioaddr + TxStatus)); outw(0, ioaddr + TxStatus); if (inb(ioaddr + TxStatus) == 0) break; } printf("\n"); } if (verbose || opt_a) { unsigned intr_status = inw(ioaddr + IntrStatus); printf(" Interrupt status is %4.4x:", intr_status); if (intr_status == 0) printf(" No interrupts pending."); else for (i = 0; i < 11; i++) if ((1< 1) { printf("%s chip registers at %#lx", pcidev_tbl[part_idx].part_name, ioaddr); for (i = 0; i < pcidev_tbl[part_idx].io_size; i += 2) { if ((i & 0x0f) == 0) printf("\n 0x%2.2X:", i); if (i == IntrClear) printf(" ----"); else printf(" %4.4x", inw(ioaddr + i)); } printf("\n"); } } if (set_hwaddr || show_eeprom) { ee_addr_len = eeprom_addr_len(ioaddr); eeprom_size = 1 << ee_addr_len; printf(" EEPROM address length %d, %d words.\n", ee_addr_len, eeprom_size); for (i = 0; i < eeprom_size; i++) eeprom_contents[i] = read_eeprom(ioaddr, i, ee_addr_len); } if (emergency_rewrite && ! set_hwaddr) printf("*** Emergency EEPROM rewrite is only valid when you also " "specify a new\n*** station address with -H \n"); if (set_hwaddr) { u16 backup_ee_contents[] = { 0x2af8, 0xc262, 0x1186, 0x1102, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5000, 0x01ba, 0xaf04, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3400, 0x0100, 0x3702, 0x0300, 0x883a, 0x3f04, 0x0303, 0x0103, }; memcpy(new_ee_contents, eeprom_contents, eeprom_size << 1); if (emergency_rewrite) memcpy(new_ee_contents, backup_ee_contents, sizeof backup_ee_contents); for (i = 0; i < 3; i++) new_ee_contents[i + EEPROM_SA_OFFSET] = (new_hwaddr[i*2+1]<<8) + new_hwaddr[i*2]; #if 0 /* Only do limited write checking */ for (i = EEPROM_SA_OFFSET; i < EEPROM_SA_OFFSET + 3; i++) if (new_ee_contents[i] != eeprom_contents[i]) write_eeprom(ioaddr, i, new_ee_contents[i], ee_addr_len); #endif #if defined(EEPROM_CSUM_OFFSET) && EEPROM_CSUM_OFFSET > 0 /* The checksum for the st201 is not documented. */ { unsigned short sum = 0; for (i = 0; i < EEPROM_CSUM_OFFSET; i++) sum ^= new_ee_contents[i]; sum = (sum ^ (sum>>8)) & 0xff new_ee_contents[EEPROM_CSUM_OFFSET] = sum; write_eeprom(ioaddr, EEPROM_CSUM_OFFSET, sum, ee_addr_len); } #endif if ( ! do_write_eeprom) printf("---- These EEPROM writes will be not be done unless " "the '-w' flag is passed!\n"); for (i = 0; i < eeprom_size; i++) if (new_ee_contents[i] != eeprom_contents[i]) { if (do_write_eeprom) write_eeprom(ioaddr, i, new_ee_contents[i], ee_addr_len); else printf("Would write %4.4x to replace %4.4x at %d.\n", new_ee_contents[i], eeprom_contents[i], i); eeprom_contents[i] = read_eeprom(ioaddr, i, ee_addr_len); } } if (show_eeprom > 1) { int elided = 0; printf("EEPROM contents (%d words):", eeprom_size); for (i = 0; i < eeprom_size; i += 8) { int j; if (i != 0 && show_eeprom < 3 && memcmp(&eeprom_contents[i], &eeprom_contents[i-8], 8*2) == 0) elided = 1; else { if (elided) { printf("\n ..."); elided = 0; } printf("\n 0x%2.2x: ", i); for (j = 0; j < 8; j++) printf(" %4.4x", eeprom_contents[i + j]); if (show_eeprom > 2) { printf(" "); for (j = 0; j < 8; j++) { int ew = eeprom_contents[i + j]; printf("%c%c", isprint(ew & 0xff) ? ew & 0xff : '_', isprint(ew >> 8) ? ew >> 8 : '_' ); } } } } printf("\n"); } if (show_eeprom) { u32 sum = 0; u8 *ee = (u8*)eeprom_contents; for (i = 0; i < 128-1; i++) sum ^= eeprom_contents[i]; printf(" EEPROM Subsystem IDs, Vendor %2.2x%2.2x Device %2.2x%2.2x.\n", ee[5], ee[4], ee[7], ee[6]); printf(" EEPROM Station address is "); for (i = EEPROM_SA_OFFSET*2; i < EEPROM_SA_OFFSET*2 + 5; i++) printf("%2.2x:", ee[i]); printf("%2.2x.\n", ee[i]); printf(" Configuration %4.4x, ASIC Control %4.4x.\n" " Checksum %4.4x\n", eeprom_contents[0], eeprom_contents[1], sum); } if (show_mii) { int phys[4], phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(ioaddr, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { phys[phy_idx++] = phy; printf(" MII PHY found at address %d, status 0x%4.4x.\n", phy, mii_status); } } if (phy_idx == 0) printf(" ***WARNING***: No MII transceivers found!\n"); for (phy = 0; phy < phy_idx; phy++) { int mii_reg; printf(" MII PHY #%d transceiver registers:", phys[phy]); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mdio_read(ioaddr, phys[phy], mii_reg)); printf(".\n"); } #ifdef LIBMII show_mii_details(ioaddr, phys[0]); if (show_mii > 1) monitor_mii(ioaddr, phys[0]); #endif } #ifdef LIBFLASH { flash_in_hook = alta_flash_in; flash_out_hook = alta_flash_out; if (opt_flash_show) flash_show(ioaddr, 0); if (opt_flash_dumpfile) if (flash_dump(ioaddr, 0, opt_flash_dumpfile) < 0) { fprintf(stderr, "Failed to save the old Flash BootROM image " "into file '%s'.\n", opt_flash_dumpfile); return 3; } if (opt_flash_loadfile) if (flash_program(ioaddr, 0, opt_flash_loadfile) < 0) { fprintf(stderr, "Failed to load the new Flash BootROM image " "from file '%s'.\n", opt_flash_loadfile); return 4; } } #else if (opt_flash_loadfile || opt_flash_dumpfile || opt_flash_show) printf("Flash operations not configured into this program.\n"); if (opt_flash_show) { printf("The first few boot ROM bytes are:"); for (i = 0; i < 16; i++) printf(" %2.2x", alta_flash_in(ioaddr, i)); printf(" (%8.8x -> %2.2x).\n", inl(ioaddr + FlashAddr), inb(ioaddr + FlashData)); } #endif return 0; } static int eeprom_addr_len(long ioaddr) { return 8; } static int read_eeprom(long ioaddr, int location, int ignore_addr_len) { int boguscnt = 1000; /* Typical 190 ticks. */ outw(0x0200 | (location & 0xff), ioaddr + EECtrl); do { if (! (inw(ioaddr + EECtrl) & 0x8000)) { if (debug) printf("EEPROM read took %d ticks to read %4.4x.\n", 1000 - boguscnt, inw(ioaddr + EEData)); return inw(ioaddr + EEData); } } while (--boguscnt > 0); fprintf(stderr, "Configuration EEPROM read of location %d failed, " "status %4.4x.\n", location, inw(ioaddr + EEData)); return 0; } static void write_eeprom(long ioaddr, int location, int value, int ignore_addr_len) { int boguscnt = 10000; if ( ! do_write_eeprom) { printf("Would write 0x%4.4x to offset %d.\n", value, location); return; } /* Write enable. */ outw(0x00C0, ioaddr + EECtrl); do { if (! (inw(ioaddr + EECtrl) & 0x8000)) break; } while (--boguscnt > 0); outw(value, ioaddr + EEData); outw(0x0100 | (location & 0xff), ioaddr + EECtrl); do { if (! (inw(ioaddr + EECtrl) & 0x8000)) { if (debug) fprintf(stderr, "EEPROM write of location %d with %#x took %d" " ticks, status %4.4x\n", location, inw(ioaddr + EEData), 10000- boguscnt, inw(ioaddr + EECtrl)); return; } } while (--boguscnt > 0); fprintf(stderr, "EEPROM write of %#4.4x to location %d with failed " "with status %#x.\n", location, value, inw(ioaddr + EECtrl)); outw(0x0000 | (location & 0xff), ioaddr + EECtrl); return; } /* Read and write the MII registers using software-generated serial MDIO protocol. It is just different enough from the serial EEPROM protocol to not share code. The maxium data clock rate is 2.5 Mhz. */ #define mdio_out(value, mdio_addr) outb(value, mdio_addr) #define mdio_in(mdio_addr) inb(mdio_addr) #define mdio_delay(mdio_addr) inb(mdio_addr) /* Flush buffered write.*/ #define MDIO_IO_OFFSET MIICtrl #define MDIO_SHIFT_CLK 0x01 #define MDIO_WRITE0 0x04 #define MDIO_WRITE1 0x06 #define MDIO_ENB 0x00 #define MDIO_ENB_IN 0x00 #define MDIO_DATA_READ 0x02 /* Syncronize the MII management interface by shifting 32 one bits out. */ static void mdio_sync(long ioaddr) { long mdio_addr = ioaddr + MDIO_IO_OFFSET; int i; for (i = 32; i >= 0; i--) { mdio_out(MDIO_WRITE1, mdio_addr); mdio_delay(mdio_addr); mdio_out(MDIO_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(mdio_addr); } return; } int mdio_read(long ioaddr, int phy_id, int location) { long mdio_addr = ioaddr + MDIO_IO_OFFSET; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int i, retval = 0; if (verbose > 2) /* Debug: 5 */ printf(" mdio_read(%#lx, %d, %d)..", ioaddr, phy_id, location); /* Establish sync by sending at least 32 logic ones. */ mdio_sync(ioaddr); /* Shift the read command bits out. */ for (i = 17; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; if (verbose > 3) /* Debug: 5 */ printf("%d", (mii_cmd & (1 << i)) ? 1 : 0); mdio_out(MDIO_ENB | dataval, mdio_addr); mdio_delay(mdio_addr); mdio_out(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); if (verbose > 3) printf(" %x", (mdio_in(mdio_addr) >> 16) & 0x0f); mdio_delay(mdio_addr); } if (verbose > 3) printf("-> %x", (mdio_in(mdio_addr) >> 16) & 0x0f); /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { mdio_out(MDIO_ENB_IN, mdio_addr); mdio_delay(mdio_addr); retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); if (verbose > 3) printf(" %x", (mdio_in(mdio_addr) >> 16) & 0x0f); mdio_out(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(mdio_addr); } if (verbose > 3) printf(" == %4.4x.\n", retval); return (retval>>1) & 0xffff; } void mdio_write(long ioaddr, int phy_id, int location, int value) { long mdio_addr = ioaddr + MDIO_IO_OFFSET; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; int i; /* Establish sync by sending 32 logic ones. */ mdio_sync(ioaddr); /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; mdio_out(MDIO_ENB | dataval, mdio_addr); mdio_delay(mdio_addr); mdio_out(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(mdio_addr); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { mdio_out(MDIO_ENB_IN, mdio_addr); mdio_delay(mdio_addr); mdio_out(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(mdio_addr); } return; } /* * Local variables: * compile-command: "cc -O -Wall -Wstrict-prototypes -o alta-diag alta-diag.c -DLIBFLASH libflash.c -DLIBMII libmii.c" * simple-compile-command: "cc -O -o alta-diag alta-diag.c" * tab-width: 4 * c-indent-level: 4 * c-basic-offset: 4 * End: */ nictools-pci-1.3.8.orig/eepro100-diag.c0000644000175000017500000010246210264217064016427 0ustar alainalain/* eepro100-diag.c: Diagnostic and setup program for the Intel EEPro100. This is a diagnostic and EEPROM setup program for the Ethernet adapters based on the Intel "Speedo3" chip series: the i82557, '558 and '559. These chips are used on the EtherExpress Pro100B, and EEPro PCI 10+. Copyright 1998-2003 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 Support and updates available at http://www.scyld.com/diag/index.html Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. To use this code under other terms requires an explicit license from the copyright holder. */ static char *version_msg = "eepro100-diag.c:v2.13 2/28/2005 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: eepro100-diag [-aDEefFGhmqrRtvVwW] [-p ] [-[AF] ]\n" " For details and other options see http://www.scyld.com/diag/index.html\n"; static const char long_usage_msg[] = "Usage: %s [-aDfrRvVw] [-AF ] [-#]\n\ \n\ Show the internal state of a network adapter.\n\ \n\ The common usage is\n\ eepro100-diag -aem\n\ \n\ Frequently used options are\n\ -a --show_all_registers Print all registers.\n\ -e --show-eeprom Dump EEPROM contents, \"-ee\" shows the details.\n\ -m --show_mii Print the MII transceiver state\n\ Using -mm monitors the link.\n\ -f --force Perform operation, even on a running NIC.\n\ \n\ To operate on a single NIC, or one that hasn't been automatically found:\n\ -# --card_num INDEX Operate on the specified card index.\n\ -p --port-base IOADDR Assume an adapter at the specified I/O address.\n\ -t --chip-type TYPE Specify adapter type (with '-p'). Use '-1' to\n\ list available types indicies.\n\ \n\ To change the persistent EEPROM settings\n\ -G --parameters PARMS Set adapter-specific parameters.\n\ -H --new-hwaddr 01:23:45:67:89:ab\n\ Set a new hardware station address. Typically disabled for safety.\n\ -w --write-EEPROM Actually write the new settings into the EEPROM.\n\ \n\ -D --debug\n\ -v --verbose Report each action taken.\n\ -V --version Emit version information.\n\ \n\ -A --advertise (See the mii-diag manual page.)\n\ "; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif /* No libmii.h or libflash.h yet, thus the declarations here. */ extern int show_mii_details(long ioaddr, int phy_id); extern int monitor_mii(long ioaddr, int phy_id); /* Simple alternate functions if libmii is not used. */ extern int monitor_mii(long ioaddr, int phy_id) __attribute__((weak)); extern int show_mii_details(long ioaddr, int phy_id) __attribute__((weak)); extern int flash_pci_rom_show(long addr_ioaddr, long data_ioaddr); extern int flash_pci_rom_dump(long addr_ioaddr, long data_ioaddr, const char *filename); extern int flash_pci_rom_program(long addr_ioaddr, long data_ioaddr, const char *filename); /* We should use __u8 .. __u32, but they are not always defined. */ typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; struct option longopts[] = { /* { name has_arg *flag val } */ {"card-num", 1, 0, '#'}, /* Operate on the specified card index. */ {"Advertise", 1, 0, 'A'}, {"base-address", 1, 0, 'p'}, {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Print a long usage message. */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"restart", 0, 0, 'r'}, /* Restart autonegotiation. */ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; extern int eepro100_diag(int vend_id, int dev_id, long ioaddr, int part_idx); /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name from the kernel, a common name and the PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { const char *part_name; const char *proc_pci_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx); } pcidev_tbl[] = { { "Intel i82557/8/9 EtherExpressPro100", "Intel 82557", 0x8086, 0x1229, 0xffff, 0, 0x20, eepro100_diag }, { "Intel 82559ER EtherExpressPro/100+", 0, 0x8086, 0x1209, 0xffff, 0, 0x20, eepro100_diag }, { "Intel EtherExpressPro100+ Type 1029", 0, 0x8086, 0x1029, 0xffff, 0, 0x20, eepro100_diag }, { "Intel InBusiness i82559", 0, 0x8086, 0x1030, 0xffff, 0, 0x40, eepro100_diag }, { "Intel i82562 Pro/100 V", 0, 0x8086, 0x2449, 0xffff, 0, 0x40, eepro100_diag }, { "Intel Pro/100 VE (type 1031)", 0, 0x8086, 0x1031, 0xffff, 0, 0x40, eepro100_diag }, { "Intel Pro/100 VM-1038", 0, 0x8086, 0x1038, 0xffff, 0, 0x40, eepro100_diag }, { "Intel Pro/100 VM-1039", 0, 0x8086, 0x1039, 0xffff, 0, 0x40, eepro100_diag }, { "Intel Pro/100 VE-103a", 0, 0x8086, 0x103A, 0xffff, 0, 0x40, eepro100_diag }, { "Intel Pro/100 VE-103b", 0, 0x8086, 0x103B, 0xffff, 0, 0x40, eepro100_diag }, { "Intel Pro/100 VE-103d", 0, 0x8086, 0x103D, 0xffff, 0, 0x40, eepro100_diag }, { "Intel Pro/100 VE-unknown (1030 series)", 0, 0x8086, 0x1030, 0xfff0, 0, 0x40, eepro100_diag }, { 0, 0, 0, 0}, }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int nway_advertise = 0, fixed_speed = -1; int new_default_media = -1; /* Valid with libflash only. */ static unsigned int opt_flash_show = 0; static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int emergency_rewrite = 0; static int scan_proc_pci(int card_num); static int parse_media_type(const char *capabilities); static int get_media_index(const char *name); int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:hH:mp:qrRt:vVwWBL:S:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'A': nway_advertise = parse_media_type(optarg); break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 16); break; case 'h': fprintf(stderr, long_usage_msg, argv[0]); return 0; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtoul(optarg, NULL, 16); break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case 'W': opt_watch++; break; case 'B': opt_flash_show++; break; case 'L': opt_flash_loadfile = optarg; break; case 'S': opt_flash_dumpfile = optarg; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("Network adapter diagnostic: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for parsed contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n" " See http://www.scyld.com/expert/irq-conflict.html for more information.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if ((pci_devid >> 16) != pcidev_tbl[i].vendor || (pci_devid & pcidev_tbl[i].device_mask) != pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].part_name; i++) if (pcidev_tbl[i].proc_pci_name && strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Convert a text media name to a NWay capability word. */ static int parse_media_type(const char *capabilities) { const char *mtypes[] = { "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD", "10baseT", "10baseT-FD", "10baseT-HD", 0, }; char *endptr; int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,}; int i; if (debug) fprintf(stderr, "Advertise string is '%s'.\n", capabilities); for (i = 0; mtypes[i]; i++) if (strcasecmp(mtypes[i], capabilities) == 0) return cap_map[i]; i = strtoul(capabilities, &endptr, 16); if (*endptr == 0 && 0 < i && i <= 0xffff) return i; fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities); return 0; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to indices. This matches the Digital Tulip SROM numbering, primarily because that is the most complete list. Other chips will have to map these number to their internal values. */ struct { char *name; int value; } mediamap[] = { { "10baseT", 0 }, { "10base2", 1 }, { "AUI", 2 }, { "100baseTx", 3 }, { "10baseT-FDX", 0x204 }, { "100baseTx-FDX", 0x205 }, { "100baseT4", 6 }, { "100baseFx", 7 }, { "100baseFx-FDX", 8 }, { "MII", 11 }, { "Autosense", 0x0800 }, { 0, 0 }, }; static int get_media_index(const char *name) { char *endptr; int i; if (! name) return -1; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) return i; i = strtol(name, &endptr, 0); if (*endptr == 0) return i; fprintf(stderr, "Invalid interface specified. It must be one of\n"); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %d %s\n", mediamap[i].value, mediamap[i].name); return -1; } /* Chip-specific section. */ /* The chip-specific section for the Intel EEPro100 diagnostic. */ static char sleep_mode_msg[] = " Sleep mode is enabled. This is not recommended.\n" " Under high load the card may not respond to\n" " PCI requests, and thus cause a master abort.\n" " To clear sleep mode use the '-G 0 -w -w -f' options.\n"; static char no_xcvr_msg[] = " This NIC has no transceiver programmed into the configuration EEPROM.\n" " This is likely a manufacturing error. It may be corrected with\n" " software. Contact the board vendor for an update.\n"; static int read_eeprom(long ioaddr, int location, int addr_len); static void write_eeprom(long ioaddr, int index, int value, int addr_len); static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len); static void eepro100_eeprom(unsigned short *ee_data); int mdio_read(long ioaddr, int phy_id, int location); void mdio_write(long ioaddr, int phy_id, int location, int value); int flash_pci_rom_show(long ioaddr, long data) __attribute__((weak)); int flash_pci_rom_dump(long ioaddr, long data, const char *filename) __attribute__((weak)); int flash_pci_rom_program(long ioaddr, long data, const char *filename) __attribute__((weak)); /* Offsets to the various registers. Accesses need not be longword aligned. */ enum speedo_offsets { SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */ SCBPointer = 4, /* General purpose pointer. */ SCBPort = 8, /* Misc. commands and operands. */ SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */ SCBCtrlMDI = 16, /* MDI interface control. */ SCBEarlyRx = 20, /* Early receive byte count. */ }; /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD (5) #define EE_READ_CMD (6) #define EE_ERASE_CMD (7) /* Last-hope recovery major screw-ups: rewrite the EEPROM with the values from my card (and hope I don't met you on the net...). Only experts should use this, after hand-modifying this table. The default will probably not match your board! */ unsigned short djb_eepro100_eeprom[64] = { 0xa000, 0x49c9, 0x87ab, 0x0000, 0x0000, 0x0101, 0x4401, 0x0000, 0x6455, 0x2022, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x7fcd, }; /* Values read from the EEPROM, and the new image. */ unsigned short eeprom_contents[256]; unsigned short new_ee_contents[256]; int eepro100_diag(int vend_id, int dev_id, long ioaddr, int part_idx) { int i; int phy0, phy1; int ee_addr_len = 6; /* Modified below. */ int eeprom_size = 64, eeprom_change = 0; unsigned short status = inw(ioaddr + SCBStatus); /* It's mostly safe to use the EEPro100 EEPROM and MDIO register during operation. But warn the user, and make then pass '-f'. */ if (!opt_f) { if (status == 0xffff) { printf(" * A recognized chip has been found, but it does not " "appear to exist in\n * I/O space. Use the" " '-f' flag to see the register values anyway.\n"); return 1; } if ((status & 0x00fc) != 0x0000) { printf("A potential i82557 chip has been found, but it appears to " "be active.\nEither shutdown the network, or use the" " '-f' flag.\n"); return 1; } } if (verbose > 1 || show_regs) { static const char *tx_state[] = { "Idle", "Suspended", "Active", "Unknown"}; static const char *rx_state[] = { "Idle", "Idle/Suspended", "No Resources", "Unknown", "Ready", "Broken-5", "Broken-6", "Broken-7", "Broken-8", "Suspended - no buffers", "No resources - no buffers", "Broken-11", "Ready, but no buffers", "Broken-13", "Broken-14", "Broken-15", }; printf("i82557 chip registers at %#x:\n ", (int)ioaddr); for (i = 0; i < 0x18; i += 4) printf(" %8.8x", inl(ioaddr + i)); printf("\n"); printf(" %snterrupt sources are pending.\n", (status & 0xff00) ? "I": "No i"); printf(" The transmit unit state is '%s'.\n", tx_state[(status>>6) & 3]); printf(" The receive unit state is '%s'.\n", rx_state[(status>>2) & 15]); if (status == 0x0050) printf(" This status is normal for an activated but idle " "interface.\n"); else printf(" This status is unusual for an activated interface.\n"); if (inw(ioaddr + SCBCmd) != 0) printf(" The Command register has an unprocessed command " "%4.4x(?!).\n", inw(ioaddr + SCBCmd)); } /* Read the EEPROM. */ { int size_test = do_eeprom_cmd(ioaddr, (EE_READ_CMD << 8) << 16, 27); ee_addr_len = (size_test & 0xffe0000) == 0xffe0000 ? 8 : 6; eeprom_size = 1 << ee_addr_len; if (debug) printf("EEPROM size probe returned %#x, %d bit address.\n", size_test, ee_addr_len); for (i = 0; i < eeprom_size; i++) eeprom_contents[i] = read_eeprom(ioaddr, i, ee_addr_len); memcpy(new_ee_contents, eeprom_contents, eeprom_size << 1); } phy0 = eeprom_contents[6] & 0x8000 ? -1 : eeprom_contents[6] & 0x1f; phy1 = eeprom_contents[7] & 0x8000 ? -1 : eeprom_contents[7] & 0x1f; if (verbose > 2 || show_eeprom > 1) { unsigned short sum = 0; int last_row_zeros = 0; u16 zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0}; printf("EEPROM contents, size %dx16:\n", eeprom_size); for (i = 0; i < eeprom_size; i += 8) { int j; if (memcmp(eeprom_contents + i, zeros, 16) != 0) { last_row_zeros = 0; printf(" %#4.2x:", i); for (j = 0; j < 8; j++) { printf(" %4.4x", eeprom_contents[i + j]); sum += eeprom_contents[i + j]; } printf(" "); for (j = 0; j < 8; j++) { int ew = eeprom_contents[i + j]; printf("%c%c", isprint(ew & 0xff) ? ew & 0xff : '_', isprint(ew >> 8) ? ew >> 8 : '_' ); } printf("\n"); } else if ( ! last_row_zeros) { last_row_zeros = 1; printf(" ...\n"); } } if (sum == 0xBaBa) /* Bahhhh. */ printf(" The EEPROM checksum is correct.\n"); else printf(" ***** The EEPROM checksum is INCORRECT! *****\n" " The checksum is 0x%2.2X, it should be 0xBABA!\n", sum); } /* The user will usually want to see the interpreted EEPROM contents. */ if (verbose > 1 || show_eeprom) eepro100_eeprom(eeprom_contents); /* These two "-G " settings may change or be removed! */ /* Clear the sleep mode bit with "-G 0". */ if (opt_G && opt_GPIO == 0 && (eeprom_contents[10] & 0x0002)) { printf("Changing the chip configuration word (offset 10) to %#4.4x.\n", new_ee_contents[10]); new_ee_contents[10] = eeprom_contents[10] & ~0x0002; eeprom_change++; } if (opt_G && opt_GPIO == 1 && eeprom_contents[6] == 0) { printf("Changing the transceiver type to MII RJ45.\n"); new_ee_contents[5] = 0x0101; new_ee_contents[6] = 0x4401; eeprom_change++; } #if ! defined(ENABLE_HWADDR_UPDATE) if (emergency_rewrite) fprintf(stderr, "Full EEPROM overwrite has been disabled" " in this release of the diagnostic.\n"); if (set_hwaddr) fprintf(stderr, "Modifying the station (MAC) address has been disabled" " in this release of the diagnostic.\n"); #else /* Do not enable this code for end-users: it is too easy to misuse. */ if (emergency_rewrite && ! set_hwaddr) printf("*** Emergency EEPROM rewrite is only valid when you also " "specify a new\n*** station address with -H \n"); if (set_hwaddr) { if (emergency_rewrite) memcpy(new_ee_contents, djb_eepro100_eeprom, sizeof djb_eepro100_eeprom); for (i = 0; i < 3; i++) new_ee_contents[i] = (new_hwaddr[i*2+1]<<8) + new_hwaddr[i*2]; eeprom_change++; } #endif if (eeprom_change) { u16 checksum = 0; /* Recalculate the checksum. */ for (i = 0; i < eeprom_size - 1; i++) checksum += new_ee_contents[i]; if (new_ee_contents[i] != 0xBABA - checksum) { if (debug) printf("The checksum at location %d must be " "updated from 0x%4.4X to 0x%4.4X.\n", i, eeprom_contents[i], 0xBABA - checksum); new_ee_contents[i] = 0xBABA - checksum; } for (i = 0; i < eeprom_size; i++) if (new_ee_contents[i] != eeprom_contents[i]) { if (do_write_eeprom) { printf("Writing %#4.4x to configuration EEPROM word %d.\n", new_ee_contents[i], i); write_eeprom(ioaddr, i, new_ee_contents[i], ee_addr_len); } else printf(" Would write %4.4x to replace %4.4x at %d.\n", new_ee_contents[i], eeprom_contents[i], i); } } /* Grrr, it turns out they the PHY is not always #0. */ if (verbose > 1 || show_mii) { if (phy0 > 0 && mdio_read(ioaddr, phy0, 0) != 0xffff && mdio_read(ioaddr, phy0, 0) != 0x0000) { printf("Primary transceiver is MII PHY #%d.", phy0); show_mii_details(ioaddr, phy0); } if (phy1 > 0 && mdio_read(ioaddr, phy1, 0) != 0xffff && mdio_read(ioaddr, phy1, 0) != 0x0000) { printf("Alternate transceiver is MII PHY #%d.", phy0); show_mii_details(ioaddr, phy1); } } if (phy0 > 0 && nway_advertise > 0) { printf("Setting the media capability advertisement register of " "PHY #%d to 0x%4.4x.\n", phy0, nway_advertise | 1); mdio_write(ioaddr, phy0, 4, nway_advertise | 1); } if (show_mii > 1) { /* Monitor MII status */ monitor_mii(ioaddr, phy0); } /* Flash operations. */ if (opt_flash_show) flash_pci_rom_show(ioaddr, 0); if (opt_flash_dumpfile) if (flash_pci_rom_dump(ioaddr, 0, opt_flash_dumpfile) < 0) { fprintf(stderr, "Failed to save the old Flash BootROM image " "into file '%s'.\n", opt_flash_dumpfile); return 3; } if (opt_flash_loadfile) if (flash_pci_rom_program(ioaddr, 0, opt_flash_loadfile) < 0) { fprintf(stderr, "Failed to load the new Flash BootROM image " "from file '%s'.\n", opt_flash_loadfile); return 4; } return 0; } /* Reading and programming the EEPro100 flash requires a kernel extension that allocates a memory region and mmaps the PCI boot ROM space. The current (mid-2002) code that does this only works on a few kernel versions, and thus is not enabled by default. */ int flash_pci_rom_show(long ioaddr, long data) { printf("Flash operations not configured into this program.\n"); return -1; } int flash_pci_rom_dump(long ioaddr, long data, const char *filename) { printf("Flash operations not configured into this program.\n"); return -1; } int flash_pci_rom_program(long ioaddr, long data, const char *filename) { printf("Flash operations not configured into this program.\n"); return -1; } /* Serial EEPROM section. A "bit" grungy, but we work our way through bit-by-bit :->. */ /* EEPROM_Ctrl bits. */ #define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */ #define EE_CS 0x02 /* EEPROM chip select. */ #define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ #define EE_DATA_READ 0x08 /* EEPROM chip data out. */ #define EE_ENB (0x4800 | EE_CS) #define EE_WRITE_0 0x4802 #define EE_WRITE_1 0x4806 #define EE_OFFSET SCBeeprom /* Delay between EEPROM clock transitions. */ #define eeprom_delay(ee_addr) inw(ee_addr) /* Wait for the EEPROM to finish the previous operation. */ static int eeprom_busy_poll(long ee_ioaddr) { int i; outw(EE_ENB, ee_ioaddr); for (i = 0; i < 10000; i++) /* Typical 2000 ticks */ if (inw(ee_ioaddr) & EE_DATA_READ) break; return i; } static int read_eeprom(long ioaddr, int location, int addr_len) { return do_eeprom_cmd(ioaddr, ((EE_READ_CMD << addr_len) | location) << 16, 3 + addr_len + 16) & 0xffff; } static void write_eeprom(long ioaddr, int index, int value, int addr_len) { long ee_ioaddr = ioaddr + EE_OFFSET; int i; /* Poll for previous op finished. */ eeprom_busy_poll(ee_ioaddr); /* Typical 0 ticks */ /* Enable programming modes. */ do_eeprom_cmd(ioaddr, (0x4f << (addr_len-4)), 3 + addr_len); /* Do the actual write. */ do_eeprom_cmd(ioaddr, (((EE_WRITE_CMD< 1) printf(" EEPROM op 0x%x: ", cmd); outw(EE_ENB | EE_SHIFT_CLK, ee_addr); /* Shift the command bits out. */ do { short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0; outw(dataval, ee_addr); eeprom_delay(ee_addr); if (debug > 2) printf("%X", inw(ee_addr) & 15); outw(dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(ee_addr); retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0); } while (--cmd_len >= 0); outw(EE_ENB, ee_addr); /* Terminate the EEPROM access. */ outw(EE_ENB & ~EE_CS, ee_addr); if (debug > 1) printf(" EEPROM result is 0x%5.5x.\n", retval); return retval; } /* Read and write the MII registers using the parallel MDIO interface on the Speedo3. This is far less exciting than the typical bit-serial implementation (whew!) although we cannot control preamble generation. */ int mdio_read(long ioaddr, int phy_id, int location) { int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */ outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI); do { val = inl(ioaddr + SCBCtrlMDI); if (--boguscnt < 0) { fprintf(stderr, " mdio_read() timed out with val = %8.8x.\n", val); } } while (! (val & 0x10000000)); return val & 0xffff; } void mdio_write(long ioaddr, int phy_id, int location, int value) { int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */ outl(0x04000000 | (location<<16) | (phy_id<<21) | value, ioaddr + SCBCtrlMDI); do { val = inl(ioaddr + SCBCtrlMDI); if (--boguscnt < 0) { fprintf(stderr, " mdio_write() timed out with val = %8.8x.\n", val); } } while (! (val & 0x10000000)); return; } /* Simple alternate functions if libmii is not used. */ extern int monitor_mii(long ioaddr, int phy_id) __attribute__((weak)); extern int show_mii_details(long ioaddr, int phy_id) __attribute__((weak)); int monitor_mii(long ioaddr, int phy_id) { int i; unsigned short new_1, baseline_1 = mdio_read(ioaddr, phy_id, 1); if (baseline_1 == 0xffff) { fprintf(stderr, "No MII transceiver present to monitor.\n"); return -1; } printf(" Baseline value of MII status register is %4.4x.\n", baseline_1); for (i = 0; i < 60; i++) { new_1 = mdio_read(ioaddr, phy_id, 1); if (new_1 != baseline_1) { printf(" MII status register changed to %4.4x.\n", new_1); baseline_1 = new_1; } sleep(1); } return 0; } int show_mii_details(long ioaddr, int phy_id) { int mii_reg; printf(" MII PHY #%d transceiver registers:", phy_id); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mdio_read(ioaddr, phy_id, mii_reg)); printf(".\n"); return 0; } /* PHY media interface chips. */ static const char *phys[] = { "None", "i82553-A/B", "i82553-C", "i82503", "DP83840", "80c240", "80c24", "i82555", "unknown-8", "unknown-9", "DP83840A", "unknown-11", "unknown-12", "unknown-13", "unknown-14", "unknown-15", }; enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240, S80C24, I82555, DP83840A=10, }; static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 }; const char *connectors[] = {" RJ45", " BNC", " AUI", " MII"}; static void eepro100_eeprom(unsigned short *eeprom) { unsigned char dev_addr[6]; int i, j; int phy0 = eeprom[6] & 0x8000 ? -1 : eeprom_contents[6] & 0x1f; int phy1 = eeprom[7] & 0x8000 ? -1 : eeprom_contents[7] & 0x1f; printf("Intel EtherExpress Pro 10/100 EEPROM contents:\n" " Station address "); for (j = 0, i = 0; i < 3; i++) { dev_addr[j++] = eeprom[i]; dev_addr[j++] = eeprom[i] >> 8; } for (i = 0; i < 5; i++) printf("%2.2X:", dev_addr[i]); printf("%2.2X.\n", dev_addr[i]); if ((eeprom[3] & 0x03) != 3) printf(" Receiver lock-up bug exists. (The driver work-around *is* " "implemented.)\n"); printf(" Board assembly %4.4x%2.2x-%3.3d, Physical connectors present:", eeprom[8], eeprom[9]>>8, eeprom[9] & 0xff); for (i = 0; i < 4; i++) if (eeprom[5] & (1<>8)&7], phy0); if (((eeprom[6]>>8) & 0x3f) == DP83840) printf(" Transceiver-specific setup is required for the DP83840" " transceiver.\n"); if (eeprom[7] & 0x0700) printf(" Secondary interface chip %s, PHY %d.\n", phys[(eeprom[7]>>8)&7], phy1); if (eeprom[6] == 0) printf(no_xcvr_msg); if (eeprom[10] & 0x0002) printf(sleep_mode_msg); return; } /* * Local variables: * compile-command: "cc -O -Wall -o eepro100-diag eepro100-diag.c" * alt-compile-command: "cc -O -Wall -o eepro100-diag eepro100-diag.c -DLIBMII libmii.c" * tab-width: 4 * c-indent-level: 4 * c-basic-offset: 4 * End: */ nictools-pci-1.3.8.orig/epic-diag.c0000644000175000017500000010021510264217430016003 0ustar alainalain/* epic-diag.c: Diagnostics and EEPROM setup program for the SMC EPIC-100 chip. This is a diagnostic and EEPROM setup program for Ethernet adapters based on the SMC83C170 series EPIC/100 chip, as used on the SMC EtherPowerII boards. Copyright 1998-2002 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 Updates and additional information are available at http://www.scyld.com/diag/index.html References http://scyld.com/expert/mii-status.html http://www.scyld.com/expert/NWay.html http://www.smsc.com/main/datasheets/83c171.pdf http://www.smsc.com/main/datasheets/83c175.pdf http://www.national.com/pf/DP/DP83840A.html Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. To use this code under other terms requires an explicit license from the copyright holder. */ static char *version_msg = "epic-diag.c:v2.04 2/28/2005 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: epic-diag [-aDEefFGhmqrRtvVwW] [-p ] [-[AF] ]\n" " For details and other options see http://www.scyld.com/diag/index.html\n"; static const char long_usage_msg[] = "Usage: %s [-aDfrRvVw] [-AF ] [-#]\n\ \n\ Show the internal state of a network adapter.\n\ \n\ The common usage is\n\ diag -aem\n\ \n\ Frequently used options are\n\ -a --show_all_registers Print all registers.\n\ -e --show-eeprom Dump EEPROM contents, \"-ee\" shows the details.\n\ -m --show_mii Print the MII transceiver state\n\ Using -mm monitors the link.\n\ -f --force Perform operation, even on a running NIC.\n\ \n\ To operate on a single NIC, or one that hasn't been automatically found:\n\ -# --card_num INDEX Operate on the specified card index.\n\ -p --port-base IOADDR Assume an adapter at the specified I/O address.\n\ -t --chip-type TYPE Specify adapter type (with '-p'), use '-1' to list.\n\ \n\ To change the persistent EEPROM settings\n\ -F, --new-interface N Set the default transceiver type.\n\ -G --parameters PARMS Set adapter-specific parameters.\n\ -H --new-hwaddr 01:23:45:67:89:ab\n\ Set a new hardware station address. Typically disabled for safety.\n\ -w --write-EEPROM Actually write the new settings into the EEPROM.\n\ To read and write the boot BIOS extension Flash ROM\n\ -B Show the first few bytes of the ROM\n\ -L FILE Load the Flash from FILE.\n\ -S FILE Store the Flash image to FILE.\n\ \n\ -D --debug\n\ -v --verbose Report each action taken.\n\ -V --version Emit version information.\n\ \n\ -A --advertise (See the mii-diag manual page.)\n\ \n"; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif /* No libmii.h or libflash.h yet, thus the declarations here. */ extern int show_mii_details(long ioaddr, int phy_id); extern int monitor_mii(long ioaddr, int phy_id); extern int flash_show(long addr_ioaddr, long data_ioaddr); extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename); extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename); extern int (*flash_in_hook)(long addr, int offset); extern void (*flash_out_hook)(long addr, int offset, int val); struct option longopts[] = { /* { name has_arg *flag val } */ {"card-num", 1, 0, '#'}, /* Operate on the specified card index. */ {"Advertise", 1, 0, 'A'}, {"base-address", 1, 0, 'p'}, {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Print a long usage message. */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (or -ee,-eee). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"reset", 0, 0, 'R'}, /* Reset chip. */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; extern int epic_diag(int vend_id, int dev_id, long ioaddr, int part_idx); /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name from the kernel, a common name and the PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { const char *part_name; const char *proc_pci_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx); } pcidev_tbl[] = { {"SMSC EPIC/100 83c170", "SMC 9432 TX", 0x10B8, 0x0005, 0xffff, 0, 32, epic_diag}, {"SMSC EPIC/C 83c175", 0, 0x10B8, 0x0006, 0xffff, 0, 32, epic_diag}, { 0, 0, 0, 0}, }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int nway_advertise = 0, fixed_speed = -1; int new_default_media = -1; /* Valid with libflash only. */ static unsigned int opt_flash_show = 0; static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int emergency_rewrite = 0; static int scan_proc_pci(int card_num); static int parse_media_type(const char *capabilities); static int get_media_index(const char *name); /* Other chip-specific options. */ static int LED_setting = -1; int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:hH:mp:qrRst:vVwWBL:S:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'A': nway_advertise = parse_media_type(optarg); break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 16); break; case 'h': fprintf(stderr, long_usage_msg, argv[0]); return 0; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtoul(optarg, NULL, 16); break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case 'W': opt_watch++; break; case 'B': opt_flash_show++; break; case 'L': opt_flash_loadfile = optarg; break; case 'S': opt_flash_dumpfile = optarg; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("Network adapter diagnostic: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for parsed contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n" " See http://www.scyld.com/expert/irq-conflict.html for more information.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if ((pci_devid >> 16) != pcidev_tbl[i].vendor || (pci_devid & pcidev_tbl[i].device_mask) != pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].part_name; i++) if (pcidev_tbl[i].proc_pci_name && strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Convert a text media name to a NWay capability word. */ static int parse_media_type(const char *capabilities) { const char *mtypes[] = { "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD", "10baseT", "10baseT-FD", "10baseT-HD", 0, }; char *endptr; int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,}; int i; if (debug) fprintf(stderr, "Advertise string is '%s'.\n", capabilities); for (i = 0; mtypes[i]; i++) if (strcasecmp(mtypes[i], capabilities) == 0) return cap_map[i]; i = strtoul(capabilities, &endptr, 16); if (*endptr == 0 && 0 < i && i <= 0xffff) return i; fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities); return 0; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to indices. This matches the Digital Tulip SROM numbering, primarily because that is the most complete list. Other chips will have to map these number to their internal values. */ struct { char *name; int value; } mediamap[] = { { "10baseT", 0 }, { "10base2", 1 }, { "AUI", 2 }, { "100baseTx", 3 }, { "10baseT-FDX", 0x204 }, { "100baseTx-FDX", 0x205 }, { "100baseT4", 6 }, { "100baseFx", 7 }, { "100baseFx-FDX", 8 }, { "MII", 11 }, { "Autosense", 0x0800 }, { 0, 0 }, }; static int get_media_index(const char *name) { char *endptr; int i; if (! name) return -1; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) return i; i = strtol(name, &endptr, 0); if (*endptr == 0) return i; fprintf(stderr, "Invalid interface specified. It must be one of\n"); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %d %s\n", mediamap[i].value, mediamap[i].name); return -1; } /* Chip-specific section. */ /* Offsets to registers, using the (ugh) SMC names. */ enum epic_registers { COMMAND=0, IntrStatus=4, INTMASK=8, GENCTL=0x0C, NVCTL=0x10, EECTL=0x14, TEST1=0x1C, CRCCNT=0x20, ALICNT=0x24, MPCNT=0x28, /* Rx error counters. */ MIICtrl=0x30, MIIData=0x34, MIICfg=0x38, LAN0=64, /* MAC address. */ MC0=80, /* Multicast filter table. */ RxCtrl=96, TxCtrl=0x70, TxSTAT=0x74, PRxCDAR=0x84, RxSTAT=0xA4, PTxCDAR=0xC4, TxThresh=0xDC, }; /* Interrupt register bits, using my own meaningful names. */ enum IntrStatus { TxIdle=0x40000, RxIdle=0x20000, CntFull=0x0200, TxUnderrun=0x0100, TxEmpty=0x0080, TxDone=0x0020, RxError=0x0010, RxOverflow=0x0008, RxFull=0x0004, RxHeader=0x0002, RxDone=0x0001, }; static int read_eeprom(long ioaddr, int location, int addr_len); static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len); static void write_eeprom(long ioaddr, int index, int value, int addr_len); static int do_update(long ioaddr, int index, int addr_len, const char *field_name, int old_value, int new_value); int mdio_read(long ioaddr, int phy_id, int location); void mdio_write(long ioaddr, int phy_id, int location, int value); static void parse_eeprom(unsigned short *ee_data); /* The interrupt flags. */ const char *intr_names[28] ={ "Rx Copy Done", "Rx Header Done", "Rx Queue Empty", "Rx Buffer Overflow", "Rx CRC error", "Tx done", "Tx chain done", "Tx Queue empty", "Tx underrun", "Counter overflow", "Rx almost done", "Rx threshold crossed", "Fatal Interrupt summary", "PCI master abort", "PCI target abort", "PHY event", "Interrupt active", "Rx idle", "Tx idle", "Rx copy in progress", "Tx copy in progress", "Rx buffers empty", "Early Rx threshold passed", "Rx status valid", "PCI Data Parity Error", "PCI Address Parity Error", "PCI Master abort", "PCI Target Abort", }; /* Non-interrupting events. */ const char *event_names[16] = { "Tx Abort", "Rx frame complete", "Transmit done", }; #define EEPROM_BUF_SIZE 256 /* Last-hope recovery major boo-boos: rewrite the EEPROM with the values from my card (and hope I don't met you on the net...). */ unsigned short djb_epic_eeprom[EEPROM_BUF_SIZE] = { /* Currently invalid! */ }; /* Values read from the EEPROM, and a new image to write. */ unsigned short eeprom_contents[EEPROM_BUF_SIZE]; unsigned short new_ee_contents[EEPROM_BUF_SIZE]; #define EE_READ_CMD (6) #define EEPROM_SA_OFFSET 0x00 int epic_diag(int vendor_id, int device_id, long ioaddr, int part_idx) { int chip_active = 0, chip_lowpower = 0; unsigned int rx_ctrl = inl(ioaddr + RxCtrl); unsigned int genctrl = inl(ioaddr + GENCTL); int eeprom_size = 64, eeprom_addr_size = 6; int i; /* It's mostly safe to examine the registers and EEPROM during operation. But warn the user, and make then pass '-f'. */ if (genctrl == 0xffffffff && !opt_f) { printf(" * A recognized chip has been found, but it is not " "responding.\n Use the '-f' flag to continue anyway.\n"); return 1; } if (opt_reset) { genctrl &= ~0x0008; outl(genctrl | 0x201, ioaddr + GENCTL); printf("Resetting the EPIC.\n"); outl(genctrl, ioaddr + GENCTL); } else if (genctrl & 0x0008) { chip_lowpower = 1; genctrl &= ~0x0008; outl(genctrl, ioaddr + GENCTL); /* Wake up chip. */ } else if ((rx_ctrl & 0x003F) != 0x0000) chip_active = 1; if (opt_restart) { #if 0 outl(0xd823, ioaddr + NVCTL); #else outl(0x10, ioaddr + MIICfg); outl(genctrl | 0x4000, ioaddr + GENCTL); sleep(1); outl(genctrl & ~0x4000, ioaddr + GENCTL); #endif } /* Undocumented bit that must be set for the chip to work. */ outl(0x8, ioaddr + TEST1); /* Set the general purpose output LED lines. Oh, and we reset the modem too. */ if (LED_setting >= 0) { unsigned nvctl = inl(ioaddr + NVCTL) & ~0x70; /* Enable the modem as well. */ outl(((LED_setting<<4) & 0x30) | nvctl | 0x0040, ioaddr + NVCTL); outl(0x4C00, ioaddr + 0x80); /* Toggle the modem reset line. */ printf("Resetting the modem.\n"); outl(0x4C80, ioaddr + 0x80); outl(0x0020, ioaddr + 0x8C); /* Enable Binary Audio */ outl(((LED_setting<<4) & 0x30) | nvctl, ioaddr + NVCTL); } if (verbose || show_regs) { unsigned intr_status; if (chip_active && !opt_f) { printf("The EPIC/100 chip appears to be active, so some registers" " will not be read.\n" "To see all register values use the '-f' flag.\n"); } else chip_active = 0; /* Ignore the chip status with -f */ if (opt_a > 1) { /* Reading some registers hoses the chip operation. */ char dont_read[8] = {0x00, 0x00, 0x00, 0xce, 0xfd, 0xed, 0x7d, 0xff}; printf("EPIC chip registers at %#x", (int) ioaddr); for (i = 0; i < 0x100; i += 4) { if ((i & 0x1f) == 0) printf("\n 0x%3.3X:", i); if (chip_active && (dont_read[i>>5]) & (1<<((i>>2) & 7))) printf(" ********"); else printf(" %8.8x", inl(ioaddr + i)); } printf("\n"); } intr_status = inw(ioaddr + IntrStatus); printf(" %snterrupt sources are pending.\n", (intr_status & inw(ioaddr + INTMASK)) ? "I": "No i"); if (intr_status) { for (i = 0; i < sizeof(intr_names)/sizeof(intr_names[0]); i++) if (intr_status & (1<>1) & 3]); printf(" Last transmit %s, %d collisions%s.\n", last_tx & 1 ? "OK" : "FAILED!!", (last_tx>>8) & 0x1f, last_tx & 0x80 ? ", currently deferring to traffic!":""); printf(" Receiver control is %4.4x, %s mode.\n", rx_ctrl, rx_ctrl & 0x40 ? "monitor only" : rx_ctrl & 0x20 ? "promiscuous" : rx_ctrl & 8 ? "multicast" : "normal"); printf(" The last Rx frame was %d bytes, status %x%s%s%s%s%s%s%s.\n", inl(ioaddr + 0x68), last_rx, last_rx&0x40 ? ", Rx disabled" : "", last_rx&0x20 ? ", broadcast" : "", last_rx&0x10 ? ", multicast" : "", last_rx&0x08 ? ", Missed/Overflow" : "", last_rx&0x04 ? ", CRC Error!" : "", last_rx&0x02 ? ", Alignment Error!" : "", last_rx&0x02 ? " received OK." : "" ); } } if (opt_GPIO) { printf("Setting the GPIO register %8.8x.\n", opt_GPIO); outl(opt_GPIO, ioaddr + NVCTL); } /* Read the EEPROM. */ if (show_eeprom || set_hwaddr) { int size_test = do_eeprom_cmd(ioaddr, (EE_READ_CMD << 8) << 16, 27); eeprom_addr_size = (size_test & 0xffe0000) == 0xffe0000 ? 8 : 6; eeprom_size = 1 << eeprom_addr_size; if (debug) printf("EEPROM size probe returned %#x, %d bit address.\n", size_test, eeprom_addr_size); for (i = 0; i < 64 /* Not eeprom_size! */; i++) eeprom_contents[i] = read_eeprom(ioaddr, i, eeprom_addr_size); } if (set_hwaddr) { unsigned char sum = 0; const char *const field_names[] = { "MAC address 0/1", "MAC address 2/3", "MAC address 4/5", "Checksum/Board-ID"}; memcpy(new_ee_contents, eeprom_contents, 64 << 1); for (i = 0; i < 3; i++) { new_ee_contents[i + EEPROM_SA_OFFSET] = new_hwaddr[i*2] + (new_hwaddr[i*2+1]<<8); sum += new_hwaddr[i*2] + new_hwaddr[i*2+1]; } sum += new_ee_contents[i]; /* Board ID, implicit truncation! */ printf("Writing new MAC station address, checksum %2.2x.\n", sum); /* Explicit bit ops to avoid endian issues. */ new_ee_contents[i] = (new_ee_contents[i] & 0xff) | (-sum << 8); if (debug) printf("new_ee_contents[%d] is %4.4x.\n", i, new_ee_contents[i]); for (i = EEPROM_SA_OFFSET; i < EEPROM_SA_OFFSET + 5; i++) if (new_ee_contents[i] != eeprom_contents[i]) do_update(ioaddr, i, eeprom_addr_size, field_names[i], eeprom_contents[i], new_ee_contents[i]); /* Re-read all contents. */ for (i = 0; i < 64; i++) eeprom_contents[i] = read_eeprom(ioaddr, i, eeprom_addr_size); } if (show_eeprom > 1) { unsigned short sum = 0; printf("EEPROM contents (size: %s):", inl(ioaddr + EECTL) & 0x40 ? "64x16" : "256x16"); for (i = 0; i < eeprom_size; i++) { printf("%s %4.4x", (i & 7) == 0 ? "\n " : "", eeprom_contents[i]); sum += eeprom_contents[i]; } printf("\n The word-wide EEPROM checksum is %#4.4x.\n", sum); } /* Show the interpreted EEPROM contents. */ if (verbose > 1 || show_eeprom) parse_eeprom(eeprom_contents); /* Show up to four (not just the on-board) PHYs. */ if (verbose > 1 || show_mii) { int phys[4], phy, phy_idx = 0; int mii_reg; outl(genctrl | 0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); phys[0] = 3; /* Default MII address on SMC card. */ for (phy = 1; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(ioaddr, phy, 0); if (mii_status != 0xffff && mii_status != 0x0000) { phys[phy_idx++] = phy; printf(" MII PHY found at address %d.\n", phy); } } if (phy_idx == 0) { int mii_status = mdio_read(ioaddr, 0, 1); if (mii_status != 0xffff && mii_status != 0x0000) phys[phy_idx++] = 0; else printf(" ***WARNING***: No MII transceivers found!\n"); } for (phy = 0; phy < phy_idx; phy++) { printf(" MII PHY #%d transceiver registers:", phys[phy]); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mdio_read(ioaddr, phys[phy], mii_reg)); printf(".\n"); } #ifdef LIBMII show_mii_details(ioaddr, phys[0]); if (show_mii > 1) monitor_mii(ioaddr, phys[0]); #endif } /* The EPIC chips do not have flash boot ROM access through I/O space, only through the mapped PCI BIOS extension space. No write-enable is needed. */ if (opt_flash_loadfile || opt_flash_dumpfile || opt_flash_show) printf("Flash operations not configured into this program.\n"); if (chip_lowpower) outl(genctrl | 0x0008, ioaddr + GENCTL); return 0; } /* Serial EEPROM section. */ /* The new-style bit definitions. */ enum EEPROM_Ctrl_Bits { EE_ShiftClk=0x04, EE_ChipSelect=0x02, EE_DataOut=0x08, EE_DataIn=0x10, EE_Enb=0x03, EE_Write0=0x03, EE_Write1=0x0B, }; /* The EEPROM commands include the always-set leading bit. They must be shifted by the number of address bits. */ enum EEPROM_Cmds { EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7, }; /* EEPROM_Ctrl bits. */ #define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ #define EE_CS 0x02 /* EEPROM chip select. */ #define EE_DATA_WRITE 0x08 /* EEPROM chip data in. */ #define EE_WRITE_0 0x03 #define EE_WRITE_1 0x0B #define EE_DATA_READ 0x10 /* EEPROM chip data out. */ #define EE_ENB (0x0001 | EE_CS) #define EE_OFFSET EECTL /* Delay between EEPROM clock transitions. */ #define eeprom_delay(ee_addr) inl(ee_addr) /* This executes a generic EEPROM command, typically a write or write enable. It returns the data output from the EEPROM, and thus may also be used for reads. */ static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len) { unsigned retval = 0; long ee_addr = ioaddr + EE_OFFSET; if (debug > 1) printf(" EEPROM op 0x%x: ", cmd); outl(EE_ENB | EE_SHIFT_CLK, ee_addr); /* Shift the command bits out. */ do { short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0; outl(dataval, ee_addr); eeprom_delay(ee_addr); if (debug > 2) printf("%X", inl(ee_addr) & 15); outl(dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(ee_addr); retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); } while (--cmd_len >= 0); outl(EE_ENB, ee_addr); /* Terminate the EEPROM access. */ outl(EE_ENB & ~EE_CS, ee_addr); if (debug > 1) printf(" EEPROM result is 0x%5.5x.\n", retval); return retval; } /* Wait for the EEPROM to finish what it is doing. */ static int eeprom_busy_poll(long ee_ioaddr) { int i; outl(EE_ChipSelect, ee_ioaddr); for (i = 0; i < 10000; i++) /* Typical 2000 ticks */ if (inl(ee_ioaddr) & EE_DataIn) break; return i; } /* The abstracted functions for EEPROM access. */ static int read_eeprom(long ioaddr, int location, int addr_len) { return do_eeprom_cmd(ioaddr, ((EE_ReadCmd << addr_len) | location) << 16, 3 + addr_len + 16) & 0xffff; } static void write_eeprom(long ioaddr, int index, int value, int addr_len) { long ee_ioaddr = ioaddr + EE_OFFSET; int i; /* Poll for previous op finished. */ eeprom_busy_poll(ee_ioaddr); /* Enable programming modes. */ do_eeprom_cmd(ioaddr, (0x4f << (addr_len-4)), 3 + addr_len); /* Do the actual write. */ do_eeprom_cmd(ioaddr, (((EE_WriteCmd< 1) printf("MII control register returned %8.8x at loop %d.\n", ctrl, i); if ((ctrl & MII_READOP) == 0) break; } if (debug) printf("MII register %d:%d took %d ticks to read: %8.8x -> %8.8x%s.\n", phy_id, location, i, inl(ioaddr + MIICtrl), inl(ioaddr + MIIData), responded ? "" : ", no transceiver response"); return inw(ioaddr + MIIData); } void mdio_write(long ioaddr, int phy_id, int location, int value) { int i; outw(value, ioaddr + MIIData); outl((phy_id << 9) | (location << 4) | MII_WRITEOP, ioaddr + MIICtrl); for (i = 10000; i > 0; i--) { int ctrl = inl(ioaddr + MIICtrl); if ((ctrl & 0x08) && debug) printf("MII control register returned %8.8x at tick %d.\n", ctrl, 10000 - i); if ((ctrl & MII_WRITEOP) == 0) break; } if (debug) printf("MII register %d:%d took %d ticks to write: %8.8x -> %8.8x.\n", phy_id, location, 10000 - i, inl(ioaddr + MIICtrl), inl(ioaddr + MIIData)); return; } static void parse_eeprom(unsigned short *eeprom) { unsigned char *p = (void *)eeprom; int i; unsigned char sum = 0; for (i = 0; i < 8; i++) sum += p[i]; printf("Interpreted EEPROM contents of a SMSC EPIC:\n Station Address "); /* Little-endian assumption here. */ for (i = 0; i < 5; i++) printf("%2.2X:", p[i]); printf("%2.2X.\n" " Calculated checksum on station address is %2.2x, %scorrect.\n" " Board revision %d, name '%.20s'.\n" " PCI Subsystem ID Vendor/Device %4.4x/%4.4x.\n" " PCI Max latency %d Min grant %d (requested values in 250ns " "units)\n" " Non-volatile Control setting %4.4x:\n" " PCI BAR 1 (memory mapped register) is %s.\n" " GPIO pin 1 is an %s, initial value %d.\n" " GPIO pin 2 is an %s, initial value %d.\n" "\n", eeprom[2] >> 8, sum, sum ? "in" : "", eeprom[3] & 0xff, p + 88, eeprom[6], eeprom[7], eeprom[5] >> 8, eeprom[5] & 0xff, eeprom[4], eeprom[4] & 0x01 ? "enabled" : "disabled", eeprom[4] & 0x04 ? "output" : "input", eeprom[4] & 0x10 ? 1:0, eeprom[4] & 0x08 ? "output" : "input", eeprom[4] & 0x20 ? 1:0 ); return; } /* * Local variables: * compile-command: "cc -O -Wall -o epic-diag epic-diag.c" * alt-compile-command: "cc -O -Wall -o epic-diag epic-diag.c -DLIBMII libmii.c -DLIBFLASH libflash.c" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 * End: */ nictools-pci-1.3.8.orig/libflash.c0000644000175000017500000003774310264215030015756 0ustar alainalain/* libflash.c: Flash memory programming library. Copyright 1998-2003 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. If you use this code in your own program or make any modification the programs I release you must output the full notice required by the GPL. Contact the author for use under other terms. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 Support and updates available at http://www.scyld.com/diag/index.html References: http://www.atmel.com/atmel/products/prod9.htm http://www.ssti.com/products/products.html */ static const char version_msg[] = "libflash.c:v2.06a 7/4/2003 Copyright Donald Becker, becker@scyld.com"; /* External interface flash_show(), flash_dump() and flash_program() ADDR_IOADDR is a 32-bit I/O space register that sets the Flash ROM address. It is always accessed as outl(val, ADDR_IOADDR) DATA_IOADDR is an 8-bit I/O register from which the Flash ROM data is read. It is always accessed with inb or outb e.g. outb(val, DATA_IOADDR) FILENAME is a filename where the Flash image is stored. The caller does any register setup required. */ /* External interface to this library. Functions and variables: */ /* Show the Flash contents on stdout. */ extern int flash_show (long addr_ioaddr, long data_ioaddr); /* Read or write the Flash, writing/reading FILENAME. */ extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename); extern int flash_dump (long addr_ioaddr, long data_ioaddr, char *filename); extern int verbose; /* Set to non-zero for info. */ extern int debug; /* Currently unused. */ /* Callback hooks for accessing single words of the flash chip. Chips that have a I/O space 32 bit address register and do an 8 bit read/write register will not need this. */ int (*flash_in_hook)(long addr, int offset) = 0; void (*flash_out_hook)(long addr, int offset, int val) = 0; #include #include #include #include #include #include #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif /* Size of read() for byte oriented parts. Page oriented parts read in units of the chip page size. */ #define RD_PAGE_SIZE 4096 enum flash_flags { ERASE_FIRST=1, }; struct flash_id_table { unsigned char vendor_id, device_id; enum flash_flags flags; int mem_size, page_size; char *part_name; } static flash_id[] = { { 0x12, 0x34, 0, 8*1024, 1, "Unknown Flash EEPROM", }, /* Sector program, no erase needed parts. */ { 0xBF, 0x07, 0, 128*1024, 128, "Silicon Storage Technology SST29EE010", }, { 0xBF, 0x08, 0, 128*1024, 128, "Silicon Storage Technology SST29LE010", }, { 0x1F, 0xDC, 0, 32*1024, 64, "Atmel AT29C256", }, { 0x1F, 0xBC, 0, 32*1024, 64, "Atmel AT29LV256", }, { 0x1F, 0x5D, 0, 64*1024, 128, "Atmel AT29C512", }, { 0x1F, 0x3D, 0, 64*1024, 128, "Atmel AT29LV512", }, { 0x1F, 0xD5, 0, 128*1024, 128, "Atmel AT29C010A", }, { 0x1F, 0x35, 0, 128*1024, 128, "Atmel AT29LV010A", }, { 0x1F, 0xDA, 0, 256*1024, 256, "Atmel AT29C020", }, { 0x1F, 0xBA, 0, 256*1024, 256, "Atmel AT29LV020", }, { 0x1F, 0x5B, 0, 512*1024, 512, "Atmel AT29C040", }, { 0x1F, 0x3B, 0, 512*1024, 512, "Atmel AT29LV040", }, { 0x1F, 0xA4, 0, 512*1024, 256, "Atmel AT29C040A", }, { 0x1F, 0xC4, 0, 512*1024, 256, "Atmel AT29LV040A", }, /* Bulk-erase, byte-program parts. */ { 0x1F, 0x03, ERASE_FIRST, 64*1024, 1, "Atmel AT49BV512", }, { 0xBF, 0xD4, ERASE_FIRST, 64*1024, 1, "Silicon Storage Technology SST39VF512", }, /* AMD parts that require 90/01 read method. */ { 0x01, 0x6D, 0, 128*1024, 8*1024, "AMD Am29LV001BB", }, { 0x01, 0xED, 0, 128*1024, 8*1024, "AMD Am29LV001BT", }, { 0x01, 0x40, 0, 256*1024, 8*1024, "AMD Am29LV002BT", }, { 0x01, 0xC2, 0, 256*1024, 8*1024, "AMD Am29LV002BB", }, { 0x01, 0x34, 0, 256*1024, 8*1024, "AMD Am29F002BB", }, { 0x01, 0xB0, 0, 256*1024, 8*1024, "AMD Am29F002BT", }, { 0x01, 0x7B, 0, 512*1024, 8*1024, "AMD Am29F004BB", }, { 0x01, 0x77, 0, 512*1024, 8*1024, "AMD Am29F004BT", }, { 0x01, 0xB5, 0, 512*1024, 8*1024, "AMD Am29LV004BT", }, { 0x01, 0xB6, 0, 512*1024, 8*1024, "AMD Am29LV004BB", }, { 0x01, 0x37, 0, 1024*1024, 8*1024, "AMD Am29LV008BB", }, { 0x01, 0x3E, 0, 1024*1024, 8*1024, "AMD Am29LV008BT", }, { 0x01, 0x4C, 0, 2048*1024, 8*1024, "AMD Am29LV116DB", }, { 0x01, 0xC7, 0, 2048*1024, 8*1024, "AMD Am29LV116DT", }, { 0x01, 0x6E, 0, 128*1024, 128, "AMD Am29LV010B", }, { 0x01, 0x4F, 0, 512*1024, 128, "AMD Am29LV040B", }, { 0x01, 0x03, 0, 0, 0, "AMD Am29BL162C", }, { 0x01, 0x38, 0, 0, 0, "AMD Am29LV081B", }, { 0x01, 0x20, 0, 0, 0, "AMD Am29F010B", }, { 0x01, 0xA4, 0, 0, 0, "AMD Am29F040B", }, { 0x01, 0xD5, 0, 0, 0, "AMD Am29F080B", }, { 0x01, 0xAD, 0, 0, 0, "AMD Am29F016D", }, { 0x01, 0x3D, 0, 0, 0, "AMD Am29F017D", }, { 0x01, 0x41, 0, 0, 0, "AMD Am29F032B", }, { 0x01, 0x45, 0, 0, 0, "AMD Am29PL160C", }, { 0x01, 0x81, 0, 0, 0, "AMD Am29BL802C", }, { 0x01, 0x51, 0, 0, 0, "AMD Am29F200BT", }, { 0x01, 0x57, 0, 0, 0, "AMD Am29F200BB", }, { 0x01, 0x23, 0, 0, 0, "AMD Am29F400BT", }, { 0x01, 0xAB, 0, 0, 0, "AMD Am29F400BB", }, { 0x01, 0xD6, 0, 0, 0, "AMD Am29F800BT", }, { 0x01, 0x58, 0, 0, 0, "AMD Am29F800BB", }, { 0x01, 0xD2, 0, 0, 0, "AMD Am29F160DT", }, { 0x01, 0xD8, 0, 0, 0, "AMD Am29F160DB", }, { 0x01, 0x93, 0, 0, 0, "AMD Am29LV065D", }, { 0x01, 0x95, 0, 0, 0, "AMD Am29DS163DT", }, { 0x01, 0x96, 0, 0, 0, "AMD Am29DS163DB", }, { 0x01, 0xA3, 0, 0, 0, "AMD Am29LV033C", }, { 0x01, 0xC8, 0, 0, 0, "AMD Am29LV017D", }, { 0x01, 0xD7, 0, 0, 0, "AMD Am29LV640D", }, { 0xDA, 0xC1, 0, 128*1024, 128, "Winbond W29EE011", }, { 0,}, }; struct extended_flash_id_table { unsigned char vendor_id, device_id[3]; enum flash_flags flags; int mem_size, page_size; char *part_name; } full_flash_id[] = { /* AMD part IDs from AN-AMD25536 rev. A+1 Nov. 8, 2001 */ { 0x01, {0x7E, 0x02, 0x00,}, 0, 0, 0, "AMD Am29BDS643D", }, { 0x01, {0x7E, 0x02, 0x01,}, 0, 0, 0, "AMD Am29BDS640D", }, { 0x01, {0x7E, 0x03, 0x00,}, 0, 0, 0, "AMD Am29BDS320DB", }, { 0x01, {0x7E, 0x03, 0x01,}, 0, 0, 0, "AMD Am29BDS320DT", }, { 0x01, {0x7E, 0x06, 0x00,}, 0, 0, 0, "AMD Am29PD322DB", }, { 0x01, {0x7E, 0x06, 0x01,}, 0, 0, 0, "AMD Am29PD322DT", }, { 0x01, {0x7E, 0x0C, 0x00,}, 0, 0, 0, "AMD Am29PD640GL", }, { 0x01, {0x7E, 0x0C, 0x01,}, 0, 0, 0, "AMD Am29PD640MH", }, { 0x01, {0x7E, 0x0E, 0x00,}, 0, 0, 0, "AMD Am29PD640GB", }, { 0x01, {0x7E, 0x0E, 0x01,}, 0, 0, 0, "AMD Am29PD640GT", }, { 0x01, {0x7E, 0x10, 0x00,}, 0, 0, 0, "AMD AM29LV640MB", }, { 0x01, {0x7E, 0x10, 0x01,}, 0, 0, 0, "AMD AM29LV640MT", }, { 0x01, {0x7E, 0x11, 0x00,}, 0, 0, 0, "AMD AM29LV641MB", }, { 0x01, {0x7E, 0x11, 0x01,}, 0, 0, 0, "AMD AM29LV641MT", }, { 0x01, {0x7E, 0x12, 0x00,}, 0, 16*1024, 0, "AMD AM29LV128M", }, { 0x01, {0x7E, 0x12, 0x01,}, 0, 32*1024, 0, "AMD AM29LV256M", }, { 0x01, {0x7E, 0x13, 0x00,}, 0, 0, 0, "AMD AM29LV065M", }, { 0x01, {0x7E, 0x13, 0x01,}, 0, 0, 0, "AMD AM29LV641M", }, { 0,}, }; /* A few limits based on the table above. */ #define MAX_PAGE_SIZE 1024 #define MAX_PART_SIZE 512*1024 /* Index of internal functions. */ static int get_part_id(long addr_ioaddr, long data_ioaddr); void sst_flash_clear(long addr_ioaddr, long data_ioaddr); static void do_cmd(long addr_ioaddr, long data_ioaddr, int cmd); static inline void flash_out(long addr_ioaddr, long data_ioaddr, int offset, int val) { if (flash_out_hook) { (*flash_out_hook)(addr_ioaddr, offset, val); return; } outl(offset, addr_ioaddr); outb(val, data_ioaddr); } static inline int flash_in(long addr_ioaddr, long data_ioaddr, int offset) { if (flash_in_hook) return (*flash_in_hook)(addr_ioaddr, offset); outl(offset, addr_ioaddr); return inb(data_ioaddr) & 0xff; } static int get_part_id(long addr_ioaddr, long data_ioaddr) { int id0, id1; int old[2]; int i; old[0] = flash_in(addr_ioaddr, data_ioaddr, 0); old[1] = flash_in(addr_ioaddr, data_ioaddr, 1); #if 0 /* Check for an immediate-write Flash by checking for programming delay. However this check is falsely triggered / unreliable. */ flash_out(addr_ioaddr, data_ioaddr, 0, old[0]); if (flash_in(addr_ioaddr, data_ioaddr, 0) != old[0]) { if (verbose) printf("No BIOS ROM ID, immediate-write flash (%2.2x).\n", flash_in(addr_ioaddr, data_ioaddr, 0)); for (i = 10000; i > 0; i--) if (flash_in(addr_ioaddr, data_ioaddr, 0) == old[0]) break; return -1; } #endif do_cmd(addr_ioaddr, data_ioaddr, 0x90); /* usleep(10);*/ id0 = flash_in(addr_ioaddr, data_ioaddr, 0); id1 = flash_in(addr_ioaddr, data_ioaddr, 1); #if 0 /* Test code only. */ for (i = 0; i < 1000; i++) { printf("Flash ID is %x %x\r", id0, id1); id0 = flash_in(addr_ioaddr, data_ioaddr, 0); id1 = flash_in(addr_ioaddr, data_ioaddr, 1); } #endif if (old[0] == id0 && old[1] == id1) { /* Some SST parts only respond to the two-part ID command. */ printf("Hmmm, no response to the ID command, trying again with " "'80/60'..\n"); do_cmd(addr_ioaddr, data_ioaddr, 0x80); do_cmd(addr_ioaddr, data_ioaddr, 0x60); usleep(10); id0 = flash_in(addr_ioaddr, data_ioaddr, 0); id1 = flash_in(addr_ioaddr, data_ioaddr, 1); } if (old[0] == id0 && old[1] == id1) { printf("That did not work either, trying with '90/01'...\n"); do_cmd(addr_ioaddr, data_ioaddr, 0x90); flash_out(addr_ioaddr, data_ioaddr, 0x000, 01); id0 = flash_in(addr_ioaddr, data_ioaddr, 0); id1 = flash_in(addr_ioaddr, data_ioaddr, 1); } if (old[0] == id0 && old[1] == id1) { printf("ACKKK, this may not be a programmable Flash part!\n"); } if (verbose > 1) printf(" BIOS ROM ID %2.2X %2.2X, looking up vendor...\n", id0, id1); /* Exit ID mode. */ do_cmd(addr_ioaddr, data_ioaddr, 0xF0); usleep(10); for (i = 0; flash_id[i].vendor_id; i++) if (flash_id[i].vendor_id == id0 && flash_id[i].device_id == id1) break; if (flash_id[i].vendor_id == 0) { printf("Unknown BIOS ROM ID %2.2X %2.2X.\n", id0, id1); return -1; } if (verbose) printf("BIOS ROM ID %2.2X %2.2X, vendor %s:\n", id0, id1, flash_id[i].part_name ? flash_id[i].part_name : ""); return i; } int flash_show(long addr_ioaddr, long data_ioaddr) { unsigned char old_inval[16], inval[16]; int addr, did_dots = 0; int i, part_id, mem_size; part_id = get_part_id(addr_ioaddr, data_ioaddr); mem_size = (part_id < 0) ? 64*1024 : flash_id[part_id].mem_size; for (addr = 0; addr < mem_size; addr+=16) { for (i = 0; i < 16; i++) { inval[i] = flash_in(addr_ioaddr, data_ioaddr, addr + i); } if (addr == 0 || memcmp(inval, old_inval, sizeof(old_inval))) { printf("0x%3.3x: ", addr); for (i = 0; i < 16; i++) printf("%2.2x ", inval[i]); for (i = 0; i < 16; i++) printf("%c", isalnum(inval[i]) ? inval[i] : '.'); printf("\n"); memcpy(old_inval, inval, sizeof(old_inval)); did_dots = 0; } else if (! did_dots) { did_dots = 1; printf("...\n"); } } printf("\nBIOS ROM dump done.\n"); return 0; } int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename) { char wbuf[4096]; int fd, i, offset, cnt; int part_id = get_part_id(addr_ioaddr, data_ioaddr); int mem_size = (part_id < 0) ? 8*1024 : flash_id[part_id].mem_size; printf("Saving the boot flash ROM into file '%s'...", filename); fflush(stdout); if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0444)) < 0) { perror("flash_dump"); return -1; } for (offset = 0; offset < mem_size; offset += cnt) { int blk_size = sizeof(wbuf) < 128*1024 - offset ? sizeof(wbuf) : 128*1024 - offset; for (i = 0; i < blk_size; i++) { wbuf[i] = flash_in(addr_ioaddr, data_ioaddr, offset + i); } cnt = write(fd, wbuf, i); if (cnt < 0) { perror("save_flash"); return -1; } } printf("done.\n"); return 0; } /* Bulk erase the flash ROM. */ void sst_flash_clear(long addr_ioaddr, long data_ioaddr) { do_cmd(addr_ioaddr, data_ioaddr, 0x80); do_cmd(addr_ioaddr, data_ioaddr, 0x10); usleep(20000); /* 20 msec. */ /* While SST39VF512 specifies a max tsce of 100 ms, the */ /* AT49BV512 specifies a tEC Erase Cycle Time of 10 sec, so ... */ sleep(10); } int flash_program(long addr_ioaddr, long data_ioaddr, char *filename) { int fd, i; int offset = 0, eofflag = 0; int part_id = get_part_id(addr_ioaddr, data_ioaddr); int page_size = part_id > 0 ? flash_id[part_id].page_size : 128; int flags = flash_id[part_id].flags; if (verbose) fprintf(stderr, "%s", version_msg); if (part_id < 0) { fprintf(stderr, " This is an unknown flash chip, which cannot be " "programmed.\n"); return -1; } if ((fd = open(filename, O_RDONLY)) < 0) { perror("flash_program"); return -1; } if (page_size == 1) { /* This is a byte-by-byte part. */ unsigned char rbuf[RD_PAGE_SIZE]; if (flags & ERASE_FIRST) sst_flash_clear(addr_ioaddr, data_ioaddr); do { int rcnt = read(fd, rbuf, sizeof(rbuf)); if (rcnt < 0) { perror("flash_load"); fprintf(stderr, "read(%d,%d,%d)\n", fd, offset, (int)sizeof(rbuf)); return -1; } else if (rcnt == 0) { eofflag++; break; } for (i = 0; i < rcnt; i++) { int j; do_cmd(addr_ioaddr, data_ioaddr, 0xA0); flash_out(addr_ioaddr, data_ioaddr, offset++, rbuf[i]); /* Poll for the write to complete, look for stable read. */ for (j = 0; j < 100000; j++) if (flash_in(addr_ioaddr, data_ioaddr, 0) == flash_in(addr_ioaddr, data_ioaddr, 0)) break; if (verbose > 2) printf("Write %2.2x to %d completed after %d ticks.\n", rbuf[i], offset, j); } } while (! eofflag && offset < MAX_PART_SIZE); printf("\rFinished programming %d bytes into the flash ROM.\n", offset); return 0; } do { int rcnt, cnt = 0; unsigned char rbuf[MAX_PAGE_SIZE]; /* The flash image should be in a file, and we should never encounter short reads. But it's a disaster if we do, so we guard against it. */ do { rcnt = read(fd, rbuf + cnt, page_size - cnt); if (rcnt < 0) { perror("flash_load"); fprintf(stderr, "read(%d,%p,%d)\n", fd, rbuf + cnt, page_size - cnt); return -1; } else if (rcnt == 0) { eofflag++; break; } cnt += rcnt; } while (page_size - cnt > 0); if (cnt == 0 && eofflag) break; /* At this point rbuf[] is either a full block, or the tail of data to be written. We cannot allow blocks to span the 128 byte flash pages. */ do_cmd(addr_ioaddr, data_ioaddr, 0xA0); for (i = 0; i < cnt; i++) { flash_out(addr_ioaddr, data_ioaddr, offset + i, rbuf[i]); } if (verbose) { printf("\rWriting a block of %d bytes at offset %#x..", cnt, offset); if (verbose > 1) printf("%2.2x %2.2x %2.2x %2.2x %2.2x .", rbuf[0], rbuf[1], rbuf[2], rbuf[3], rbuf[4]); fflush(stdout); } /* Pause for 200usec. to allow the write to start. */ usleep(200); /* And then poll for the write to complete, look for stable read. */ for (i = 0; i < 100000; i++) if (flash_in(addr_ioaddr, data_ioaddr, 0) == flash_in(addr_ioaddr, data_ioaddr, 0)) break; if (verbose > 2) printf("Write completed after %d ticks.\n", i); /* Verify the write. */ for (i = 0; i < cnt; i++) { unsigned char val = flash_in(addr_ioaddr, data_ioaddr, offset + i); if (val != rbuf[i]) { fprintf(stderr, "\n Flash ROM write failed at offset %d, " "0x%2.2x vs. 0x%2.2x.\n", offset + i, val, rbuf[i]); return -1; } } offset += cnt; } while (! eofflag && offset < MAX_PART_SIZE); printf("\rFinished programming %d bytes into the flash ROM.\n", offset); return 0; } static void do_cmd(long addr_ioaddr, long data_ioaddr, int cmd) { flash_out(addr_ioaddr, data_ioaddr, 0x5555, 0xAA); flash_out(addr_ioaddr, data_ioaddr, 0x2AAA, 0x55); flash_out(addr_ioaddr, data_ioaddr, 0x5555, cmd); /* Alternate command is simply flash_out(addr_ioaddr, data_ioaddr, 0, cmd); */ } /* * Local variables: * compile-command: "cc -O -Wall -c libflash.c" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 * End: */ nictools-pci-1.3.8.orig/libmii.c0000644000175000017500000005213010264216513015431 0ustar alainalain/* libmii.c: MII diagnostic and setup library. Copyright 1997-2003 by Donald Becker. This version released under the Gnu General Public License, incorporated herein by reference. This source code may be distributed without modification using the existing notice. Any modification to this source code must include a full notice as described in the GPL Contact the author for use under other terms. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 References http://www.scyld.com/expert/NWay.html http://www.national.com/pf/DP/DP83840A.html */ static const char version_msg[] = "libmii.c:v2.11 2/28/2005 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; /* This library exports the following functions: IOADDR: A token passed to the mdio_read() function. PHY_ID: The MII transceiver address, passed uninterpreted to mdio_read(). */ void show_mii_details(long ioaddr, int phy_id); int monitor_mii(long ioaddr, int phy_id); /* This library expects to be able to call the following functions: */ extern int mdio_read(long ioaddr, int phy_id, int mii_reg_num); #include #include #include #include #include typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; static const char *media_names[] = { "10baseT", "10baseT-FD", "100baseTx", "100baseTx-FD", "100baseT4", "Flow-control", 0, }; static void ns83843(long ioaddr, int phy_id); static void qs6612(long ioaddr, int phy_id); static void smsc83c180(long ioaddr, int phy_id); static void tdk78q2120(long ioaddr, int phy_id); static void davicom_dm9101(long ioaddr, int phy_id); static void intel_i553(long ioaddr, int phy_id); static void enablesemi(long ioaddr, int phy_id); static void amd_pna(long ioaddr, int phy_id); static void amd_tx(long ioaddr, int phy_id); static void admtek(long ioaddr, int phy_id); static void lu3x31(long ioaddr, int phy_id); static void myson981(long ioaddr, int phy_id); static void via_tahoe(long ioaddr, int phy_id); static void via_vt6103(long ioaddr, int phy_id); static void via_vt6105(long ioaddr, int phy_id); static void intel(long ioaddr, int phy_id); struct mii_partnum { const char *vendor; /* Vendor name. */ u16 phy_id0; /* Vendor ID (alternate ver. of ieee_oui[]) */ u16 phy_id1; /* Vendor ID (alternate ver. of ieee_oui[]) */ unsigned char ieee_oui[3]; /* IEEE-assigned organizationally unique ID */ char flags; void (*(func))(long xcvr_if, int phy_id);/* Function to emit more info. */ } static oui_map[] = { {"Unknown transceiver type", 0x0000, 0x0000, {0,}, 0, NULL,}, {"National Semiconductor 83840A", 0x2000, 0x5c01, {0,}, 0, NULL,}, {"National Semiconductor 83843", 0x2000, 0x5c10, {0,}, 0, ns83843, }, {"Level One LXT970", 0x7810, 0x0000, {0,}, 0, NULL, }, {"Level One LXT971", 0x7810, 0x0001, {0,}, 0, NULL, }, {"Level One LXT971A",0x7810, 0x0003, {0,}, 0, NULL, }, {"Level One (unknown type)", 0, 0, {0x1e,0x04,0x00}, 0, NULL, }, {"Davicom DM9101", 0x0181, 0xB800, {0,}, 0, davicom_dm9101, }, {"Davicom (unknown type)", 0, 0, {0x00, 0x60, 0x6e}, 0, davicom_dm9101, }, {"Quality Semiconductor QS6612", 0x0181, 0x4410, {0,}, 0, qs6612}, {"Quality Semiconductor (unknown type)", 0,0, {0x00, 0x60, 0x51}, 0, NULL}, {"SMSC 83c180", 0x0282, 0x1C51, {0}, 0, smsc83c180, }, {"TDK Semi 78Q2120 rev. 2", 0x0300, 0xE542, {0,}, 0, tdk78q2120, }, {"TDK Semi 78Q2120 rev. 3", 0x0300, 0xE543, {0,}, 0, tdk78q2120, }, {"TDK Semi 78Q2120 rev. 11", 0x0300, 0xE54B, {0,}, 0, tdk78q2120, }, {"TDK transceiver (unknown type)", 0,0, {0x00, 0xc0, 0x39}, 0, tdk78q2120}, {"Intel (unknown type)", 0,0, {0x00, 0xf8, 0x00}, 0, intel_i553}, {"Enable Semiconductor EL40-331", 0x0043, 0x7411, {0,}, 0, enablesemi}, {"AMD 79c901A.1 HomePNA", 0x0000, 0x6B91, {0,}, 0, amd_pna}, {"AMD 79c901A.2 HomePNA", 0x0000, 0x6B92, {0,}, 0, amd_pna}, {"AMD 79c901A.3 HomePNA", 0x0000, 0x6B93, {0,}, 0, amd_pna}, {"AMD 79c901A.3 10baseT", 0x0000, 0x6B71, {0,}, 0, amd_tx}, {"AdHoc Technology AH101LF", 0x0022, 0x561B, {0,}, 0, tdk78q2120}, {"Altimata Communications AC101LF", 0x0022, 0x5523, {0,}, 0, tdk78q2120}, {"Altimata Comm (unknown type)", 0, 0, {0x00,0x10,0xA9}, 0, tdk78q2120}, {"ASIX (unknown type)", 0, 0, {0x00,0xC0,0xB4}, 0, tdk78q2120}, {"ADMtek AN983 Comet", 0x0022, 0x5410, {0,}, 0, admtek}, {"ADMtek AN985 Comet", 0x0022, 0x5513, {0,}, 0, admtek}, {"ADMtek (unknown type)", 0, 0, {0x00,0xe0,0x92}, 0, admtek}, {"Lucent LU6612", 0x0180, 0x7641, {0,}, 0, qs6612}, {"Lucent LU3X31", 0x0043, 0x7411, {0,}, 0, lu3x31}, {"LSI Logic (Seeq) 80225", 0, 0, {0x00,0xA0,0x7D}, 0, NULL}, {"Myson MTD981", 0x0302, 0xD000, {0,}, 0, myson981}, {"Myson (unknown type)", 0, 0, {0x00,0xC0,0xB4,}, 0, myson981}, {"Alta/Kendin Sundance", 0x0022, 0x1720, {0,}, 0, NULL}, {"Alta/Kendin Sundance", 0, 0, {0x00,0x08,0x85}, 0, NULL}, {"VIA Tahoe VT6103", 0x0101, 0x8f20, {0,}, 0, via_vt6103}, {"VIA Tahoe VT6104", 0x0101, 0x8f30, {0,}, 0, via_tahoe}, {"VIA Rhine VT6105", 0x0101, 0x8f22, {0,}, 0, via_vt6105}, {"Intel 82557 series", 0x02a8, 0x0150, {0,}, 0, intel}, {"Intel 82555 rev 1", 0x02a8, 0x0151, {0,}, 0, intel}, {"Intel 82559 transceiver", 0x02a8, 0x0154, {0,}, 0, intel}, {"Intel 82555 series transceiver", 0,0, {0x00,0xaa,0x00}, 0, intel}, {0, }, }; static u16 mii_val[32]; void show_mii_details(long ioaddr, int phy_id) { int mii_reg, i, vendor = 0; u16 bmcr, bmsr, new_bmsr; /* This may not be omitted from the output. */ printf("%s", version_msg); printf(" MII PHY #%d transceiver registers:", phy_id); for (mii_reg = 0; mii_reg < 32; mii_reg++) { mii_val[mii_reg] = mdio_read(ioaddr, phy_id, mii_reg); printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mii_val[mii_reg]); } printf(".\n"); if (mii_val[0] == 0xffff) { printf(" No MII transceiver present!.\n"); return; } bmcr = mii_val[0]; bmsr = mii_val[1]; printf(" Basic mode control register 0x%4.4x:", bmcr); if (bmcr & 0x1000) printf(" Auto-negotiation enabled.\n"); else printf(" Auto-negotiation disabled!\n" " Speed fixed at 10%s mbps, %s-duplex.\n", bmcr & 0x2000 ? "0" : "", bmcr & 0x0100 ? "full":"half"); if (bmcr & 0x8000) printf(" Transceiver currently being reset!\n"); if (bmcr & 0x4000) printf(" Transceiver in loopback mode!\n"); if (bmcr & 0x0800) printf(" Transceiver powered down!\n"); if (bmcr & 0x0400) printf(" Transceiver isolated from the MII!\n"); if (bmcr & 0x0200) printf(" Restarted auto-negotiation in progress!\n"); if (bmcr & 0x0080) printf(" Internal Collision-Test enabled!\n"); new_bmsr = mdio_read(ioaddr, phy_id, 1); printf(" Basic mode status register 0x%4.4x ... %4.4x.\n" " Link status: %sestablished.\n" " Capable of ", bmsr, new_bmsr, bmsr & 0x0004 ? "" : (new_bmsr & 0x0004) ? "previously broken, but now re" : "not "); if (bmsr & 0xF800) { for (i = 15; i >= 11; i--) if (bmsr & (1<"); printf(".\n" " %s to perform Auto-negotiation, negotiation %scomplete.\n", bmsr & 0x0008 ? "Able" : "Unable", bmsr & 0x0020 ? "" : "not "); if (bmsr & 0x0010) printf(" Remote fault detected!\n"); if (bmsr & 0x0002) printf(" *** Link Jabber! ***\n"); if (mii_val[2] ^ mii_val[3]) { /* Eliminate 0x0000 and 0xffff IDs. */ unsigned char oui_0 = mii_val[2] >> 10; unsigned char oui_1 = mii_val[2] >> 2; unsigned char oui_2 = (mii_val[2] << 6) | (mii_val[3] >> 10); printf(" Vendor ID is %2.2x:%2.2x:%2.2x:--:--:--, model %d rev. %d.\n", oui_0, oui_1, oui_2, ((mii_val[3] >> 4) & 0x3f), mii_val[3] & 0x0f); for ( i = 0; oui_map[i].vendor; i++) /* We match either the Phy ID or the IEEE OUI. */ if ((oui_map[i].phy_id0 == mii_val[2] && oui_map[i].phy_id1 == mii_val[3]) || (oui_map[i].ieee_oui[0] == oui_0 && oui_map[i].ieee_oui[1] == oui_1 && oui_map[i].ieee_oui[2] == oui_2)) { printf(" Vendor/Part: %s.\n", oui_map[i].vendor); vendor = i; break; } if (oui_map[i].vendor == NULL) printf(" No specific information is known about this transceiver" " type.\n"); } else printf(" This transceiver has no vendor identification.\n"); { int nway_advert = mii_val[4]; int lkpar = mii_val[5]; printf(" I'm advertising %4.4x:", nway_advert); for (i = 10; i >= 5; i--) if (nway_advert & (1<= 5; i--) if (lkpar & (1<= 5; i--) if (lkpar & (1< 30 ? 200000 : 1000; select(0, 0, 0, 0, &sleepval); /* Or just sleep(1); */ } printf(" Value of MII BMSR (basic mode status register) is %4.4x.\n", mdio_read(ioaddr, phy_id, 1)); return 0; } /* Emit transceiver-specific info. */ struct msg_tbl { int bitmask; char *msg; }; static void msg_if_set(const int val, const struct msg_tbl msg_tbl[]) { int i; for (i = 0; msg_tbl[i].bitmask; i++) if (msg_tbl[i].bitmask & val) printf(" %s\n", msg_tbl[i].msg); } static void msg_if_set_fmt(const int val, const struct msg_tbl msg_tbl[], const char *fmt) { int i; for (i = 0; msg_tbl[i].bitmask; i++) if (msg_tbl[i].bitmask & val) printf(fmt, msg_tbl[i].msg); } static void qs6612(long ioaddr, int phy_id) { printf(" QS6612 extra registers: Mode %4.4x.\n" " Interrupt source %4.4x, mask %4.4x.\n" " PHY control %4.4x.\n", mii_val[17], mii_val[29], mii_val[30], mii_val[31]); return; } static void ns83843(long ioaddr, int phy_id) { printf(" NatSemi 83843 extra registers:\n" " PHY status %4.4x\n" " %s link, %d Mb/sec %s duplex\n" " MII interrupts %sabled, %s pending.\n" " Events since last read\n" " Link disconnects %d\n" " False carriers %d\n" " Receive errors %d\n" " Link beat is currently %sstable\n", mii_val[0x10], mii_val[10] & 0x0001 ? "Valid" : "Invalid", mii_val[10] & 0x0002 ? 10 : 100, mii_val[10] & 0x0004 ? "full" : "half", mii_val[0x11] & 0x0002 ? "en":"dis", mii_val[0x10] & 0x0100 ? "interrupt": "none", mii_val[0x13], mii_val[0x14], mii_val[0x15], mii_val[0x16] & 0x0010 ? "UN" : ""); return; } static void smsc83c180(long ioaddr, int phy_id) { int mii_reg25 = mii_val[25]; printf(" SMSC 83c180 extra registers:\n" " Auto-negotiation status 0x%4.4x.\n" " 10baseT polarity is %s.\n" " PHY address is %d.\n" " Auto-negotiation %scomplete, 1%s0Mbps %s duplex.\n" " Rx symbol errors since last read %d.\n", mii_reg25, mii_reg25 & 0x2000 ? "normal" : "reversed", (mii_reg25>>8) & 0x1F, mii_reg25 & 0x0080 ? "did not " : "", mii_reg25 & 0x0020 ? "0" : "", mii_reg25 & 0x0040 ? "full" : "half", mdio_read(ioaddr, phy_id, 26)); return; } static const char *tdk_events[8] = { "Jabber", "Rx error", "Negotiation page received", "Link detection fault", "Link partner acknowledge", "Link status change", "Remote partner fault", "Auto-Negotiation complete"}; static const struct msg_tbl tdk_reg16[] = { {0x8000, " Transceiver is in repeater mode!"}, {0x4000, " Interrupt pin set to active high."}, {0x2000, " Reserved bit 12 is unexpectedly set."}, {0x1000, " Transmit pins are internally disconnected."}, {0x0800, " 10baseT signal quality test is disabled."}, {0x0400, " 10baseT loopback mode."}, {0, 0}, }; static void tdk78q2120(long ioaddr, int phy_id) { int mii_reg16 = mii_val[16]; int mii_reg17 = mii_val[17]; int mii_reg18 = mii_val[18]; int i; printf(" TDK format vendor-specific registers 16..18 are " "0x%4.4x 0x%4.4x 0x%4.4x\n", mii_reg16, mii_reg17, mii_reg18); printf(" Link polarity is %s %s.\n" "%s%s" " Auto-negotiation %s, 1%s0Mbps %s duplex.\n" " Rx link in %s state, PLL %s.\n", mii_reg16 & 0x0020 ? "OVERRIDDEN to" : "detected as", mii_reg16 & 0x0010 ? "reversed" : "normal", mii_reg16 & 0x0002 ? " 100baseTx Coding and scrambling is disabled!\n":"", mii_reg16 & 0x0001 ? " Rx_CLK power-save mode is enabled!\n":"", mii_reg18 & 0x1000 ? "had no common media" : "complete", mii_reg18 & 0x0400 ? "0" : "", mii_reg18 & 0x0800 ? "full" : "half", mii_reg18 & 0x0200 ? "pass" : "fail", mii_reg18 & 0x0100 ? "slipped since last read" : "locked"); msg_if_set(mii_reg16, tdk_reg16); if (mii_reg17 & 0x00ff) { printf(" Events since last read:"); for (i = 0; i < 8; i++) if (mii_reg17 & (1 << i)) printf(" %s", tdk_events[i]); } else printf(" No new link status events."); if (mii_reg17 & 0xff00) { printf("\n Events that will raise an interrupt:"); for (i = 0; i < 8; i++) if (mii_reg17 & (0x100 << i)) printf(" %s", tdk_events[i]); } printf("\n"); return; } static void davicom_dm9101(long ioaddr, int phy_id) { printf(" Davicom vendor specific registers: 0x%4.4x 0x%4.4x 0x%4.4x.\n", mii_val[16], mii_val[17], mii_val[18]); } static void intel_i553(long ioaddr, int phy_id) { printf(" This transceiver is 100baseT4 only! Register 16 is %4.4x.\n", mii_val[16]); } /* http://www.enablesemi.com/cgi-bin/byteserve/Products/Docs/3VCardBus.pdf */ static void enablesemi(long ioaddr, int phy_id) { printf(" Isolated %d times, %d false carrier events, %d Rx errors.\n", mii_val[18], mii_val[19], mii_val[21]); printf(" Cable polarity is %s, 100Mb PLL is %slocked.\n", mii_val[28]&0x8000 ? "reversed" : "normal", mii_val[27]&0x2000 ? "" : "un"); } /* The amd79c901 contains both PNA and 10/100 management registers. http://www.amd.com/products/npd/techdocs/22304.pdf */ static void amd_pna(long ioaddr, int phy_id) { printf(" HomePNA transceiver in %s speed, %s power mode.\n", mii_val[16] & 4 ? "high" : "low", mii_val[16] & 2 ? "high" : "low"); printf(" HomePNA noise level %d, peak power %d..\n", mii_val[25] >> 8, mii_val[25] & 0xff); } static void amd_tx(long ioaddr, int phy_id) { int mii_reg25 = mii_val[25]; printf(" AMD vendor specific registers: 0x%4.4x 0x%4.4x 0x%4.4x.\n", mii_val[16], mii_val[17], mii_val[18]); printf(" The link is %s in 10%s %s duplex mode, autonegotiation state " "has%s changed.\n", mii_reg25 & 8 ? "up" : "down", mii_reg25 & 1 ? "0baseTx" : "baseT", mii_reg25 & 4 ? "full" : "half", mii_reg25 & 2 ? "" : " not"); } static const struct msg_tbl admtek_reg21[] = { {0x4000, " Link test diabled: Ignoring lack of 10baseT link beat."}, {0x2000, " Link forced up."}, {0x1000, " Tx jabber check disabled."}, {0x0080, " Transmitting 'Far End Fault'!"}, {0x0040, " Rx error count full."}, {0x0008, " Remote loop back enabled."}, {0, 0}, }; static void admtek(long ioaddr, int phy_id) { printf(" ADMtek vendor specific registers information:\n" " Cable length is approximately %d meters.\n" " The receiver has lost lock %d times since last check and " "had %d error events.\n", ((mii_val[20] & 0x00f0) >> 4)*10, mii_val[23], mii_val[23]); msg_if_set(mii_val[21], admtek_reg21); tdk78q2120(ioaddr, phy_id); } static void lu3x31(long ioaddr, int phy_id) { printf(" Lucent vendor specific registers 17: 0x%4.4x" " 29: 0x%4.4x 30: 0x%4.4x 31: 0x%4.4x.\n", mii_val[17], mii_val[29], mii_val[30], mii_val[31]); } static const struct msg_tbl myson_reg16[] = { {0x0080, " Far end fault enabled."}, {0x0040, " Transformer ratio 1.25:1."}, {0x0020, " Polarity correction diabled."}, {0x0010, " Link is forced up regardless of link beat."}, {0x0004, " Bypass Jabber check."}, {0x0001, " 100baseFx mode selected."}, {0, 0}, }; static void myson981(long ioaddr, int phy_id) { int i, mii_reg17 = mii_val[17]; printf(" Myson mtd981 extra registers: %4.4x %4.4x %4.4x %4.4x.\n", mii_val[16], mii_val[17], mii_val[18], mii_val[19]); msg_if_set(mii_val[16] & 0xC800, tdk_reg16); msg_if_set(mii_val[16], myson_reg16); if (mii_reg17 & 0x00ff) { printf(" Events since last read:"); for (i = 0; i < 8; i++) if (mii_reg17 & (1 << i)) printf(" %s", tdk_events[i]); } else printf(" No new link status events."); if (mii_reg17 & 0xff00) { printf("\n Events that will raise an interrupt:"); for (i = 0; i < 8; i++) if (mii_reg17 & (0x100 << i)) printf(" %s", tdk_events[i]); } printf("\n"); return; } /* These are much like the TDK events in reversed order. */ static const struct msg_tbl via_reg17[] = { {0x0001, "Auto-Negotiation complete"}, {0x0002, "Remote fault detected"}, {0x0004, "Link failure detected"}, {0x0008, "Bad Start Stream detected"}, {0x0010, "Parallel detection fault"}, {0x0020, "Extended negotiation page received"}, {0x0040, "5B/4B code error detected"}, {0x0080, "Jabber detected"}, {0, 0}, }; static void via_tahoe(long ioaddr, int phy_id) { int mii_reg16 = mii_val[16]; int mii_reg17 = mii_val[17]; int mii_reg18 = mii_val[18]; printf(" VIA Tahoe extended registers: 16 %4.4x #17 %4.4x #18 %4.4x.\n", mii_reg16, mii_reg17, mii_reg18); msg_if_set_fmt(mii_reg17, via_reg17, " %s\n"); printf(" Link %s 10%s Mbps %s duplex\n", mii_reg18 & 0x2000 ? "up" : "down", mii_reg18 & 0x0400 ? "0" : "", mii_reg18 & 0x0800 ? "full" : "half"); } /* Information from http://www.via.com.tw/en/datasheet/DS6103110.pdf */ static void via_vt6103(long ioaddr, int phy_id) { printf(" VIA vt6103 error counts since the last check:\n" " The link has failed %d times.\n" " The receiver has lost lock %d times.\n" " There have been %d false carrier/SQE error.\n", mii_val[21], mii_val[22], mii_val[23]); } /* Information from http://www.via.com.tw/en/Networking/DS6105LOM100.pdf */ static void via_vt6105(long ioaddr, int phy_id) { printf(" VIA vt6105 PHY status:\n" " Duplex %s speed %s\n", mii_val[20] & 0x0001 ? "full" : "half", mii_val[20] & 0x0002 ? "100" : "10"); } /* Information from http://www.via.com.tw/en/Networking/DS6105LOM100.pdf */ static void intel(long ioaddr, int phy_id) { printf(" Intel 8255* PHY #%d extended management registers:\n" " Error counts, cleared when read:\n" " False carriers %d\n" " Link disconnects %d\n" " Receive errors %d\n" " Rx symbol errors %d.\n" " Rx 10Mbps Early End-Of-Frame errors %d.\n" " Rx 100Mbps Early End-Of-Frame errors %d.\n" " Tx jabber errors %d.\n", mii_val[18], mii_val[19], mii_val[20], mii_val[21], mii_val[22], mii_val[23], mii_val[24], mii_val[25]); } /* * Local variables: * compile-command: "cc -O -Wall -c libmii.c" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 * End: */ nictools-pci-1.3.8.orig/myson-diag.c0000644000175000017500000010046710264214554016245 0ustar alainalain/* myson-diag.c: Linux diagnostic/setup for the Myson mtd803 Ethernet chip. This is a diagnostic and EEPROM setup program for PCI adapters based on the following chips: Myson MTD803. Copyright 1998-2002 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 410 Severn Ave., Suite 210 Annapolis MD 21403 Support and updates available at http://www.scyld.com/diag/index.html http://scyld.com/expert/mii-status.html http://scyld.com/expert/NWay.html Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. */ static char *version_msg = "myson-diag.c:v1.07 8/07/2002 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: myson-diag [-aEefFGhmqrRtvVwW] [-p ] [-[AF] ]\n" " For details and other options see http://www.scyld.com/diag/index.html\n"; static const char long_usage_msg[] = "Usage: %s [-aDfrRvVw] [-AF ] [-#]\n" "\n" " Show the internal state of a network adapter.\n" "\n" " The common usage is\n" " myson-diag -aem\n" "\n" " Frequently used options are\n" " -a --show_all_registers Print all registers.\n" " -e --show-eeprom Dump EEPROM contents, \"-ee\" shows the details.\n" " -m --show_mii Print the MII transceiver state\n" " Using -mm monitors the link.\n" " -f --force Perform operation, even on a running NIC.\n" "\n" " To operate on a single NIC, or one that hasn't been automatically found:\n" " -# --card_num INDEX Operate on the specified card index.\n" " -p --port-base IOADDR Assume an adapter at the specified I/O address.\n" " -t --chip-type TYPE Specify adapter type with '-p', use '-1' to list.\n" "\n" " To change the persistent EEPROM settings\n" " -G --parameters PARMS Set adapter-specific parameters.\n" " -H --new-hwaddr 01:23:45:67:ab:cd\n" " Set a new hardware station address. Typically diabled, \n" " -w --write-EEPROM Actually write the new settings into the EEPROM.\n" "\n" " -D --debug\n" " -v --verbose Report each action taken.\n" " -V --version Emit version information.\n" "\n" " -A --advertise (See the mii-diag manual page.)\n" "\n"; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include /* The following are required only with unaligned field accesses. */ #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif /* No libmii.h or libflash.h yet, thus the declarations here. */ extern int show_mii_details(long ioaddr, int phy_id); extern int monitor_mii(long ioaddr, int phy_id); extern int flash_show(long addr_ioaddr, long data_ioaddr); extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename); extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename); extern int (*flash_in_hook)(long addr, int offset); extern void (*flash_out_hook)(long addr, int offset, int val); /* We should use __u8 .. __u32, but they are not always defined. */ typedef unsigned int u32; typedef unsigned short u16; typedef unsigned char u8; struct option longopts[] = { /* { name has_arg *flag val } */ {"card-num", 1, 0, '#'}, /* Operate on the specified card index. */ {"Advertise", 1, 0, 'A'}, {"base-address", 1, 0, 'p'}, {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Print a long usage message. */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; extern int myson_diag(int vend_id, int dev_id, long ioaddr, int part_idx); /* Chip-specific flags. Only the 803 has an on-chip transceiver. */ enum { HasMIIXcvr=1, HasChipXcvr=2 }; /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name and a PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { const char *part_name; const char *proc_pci_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx); } pcidev_tbl[] = { { "Myson MTD800", 0, 0x1516, 0x0800, 0xffff, HasMIIXcvr, 256, myson_diag }, { "Myson MTD803", 0, 0x1516, 0x0803, 0xffff, HasChipXcvr, 256, myson_diag }, { "Myson MTD891", 0, 0x1516, 0x0891, 0xffff, HasMIIXcvr, 256, myson_diag }, { 0, 0, 0, 0}, }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int nway_advertise = 0, fixed_speed = -1; int new_default_media = -1; /* Valid with libflash only. */ static unsigned int opt_flash_show = 0; static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int emergency_rewrite = 0; static int scan_proc_pci(int card_num); static int parse_media_type(const char *capabilities); static int get_media_index(const char *name); /* Chip-specific options, if any, go here. */ int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:hH:mp:qrRt:vVwWBL:S:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'A': nway_advertise = parse_media_type(optarg); break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 16); break; case 'h': fprintf(stderr, long_usage_msg, argv[0]); return 0; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtoul(optarg, NULL, 16); break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case 'W': opt_watch++; break; case 'B': opt_flash_show++; break; case 'L': opt_flash_loadfile = optarg; break; case 'S': opt_flash_dumpfile = optarg; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("Network adapter diagnostic: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for parsed contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n" " See http://www.scyld.com/expert/irq-conflict.html for more information.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if ((pci_devid >> 16) != pcidev_tbl[i].vendor || (pci_devid & pcidev_tbl[i].device_mask) != pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].part_name; i++) if (pcidev_tbl[i].proc_pci_name && strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Convert a text media name to a NWay capability word. */ static int parse_media_type(const char *capabilities) { const char *mtypes[] = { "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD", "10baseT", "10baseT-FD", "10baseT-HD", 0, }; int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,}; int i; if (debug) fprintf(stderr, "Advertise string is '%s'.\n", capabilities); for (i = 0; mtypes[i]; i++) if (strcasecmp(mtypes[i], capabilities) == 0) return cap_map[i]; if ((i = strtoul(capabilities, NULL, 16)) <= 0xffff) return i; fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities); return 0; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to indices. This matches the Digital Tulip SROM numbering, primarily because that is the most complete list. Other chips will have to map these number to their internal values. */ struct { char *name; int value; } mediamap[] = { { "10baseT", 0 }, { "10base2", 1 }, { "AUI", 2 }, { "100baseTx", 3 }, { "10baseT-FDX", 0x204 }, { "100baseTx-FDX", 0x205 }, { "100baseT4", 6 }, { "100baseFx", 7 }, { "100baseFx-FDX", 8 }, { "MII", 11 }, { "Autosense", 0x0800 }, { 0, 0 }, }; static int get_media_index(const char *name) { int i; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) return i; if (name && atoi(name) >= 00) return atoi(name); fprintf(stderr, "Invalid interface specified: it must be one of\n "); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %s", mediamap[i].name); fprintf(stderr, ".\n"); return -1; } /* Chip-specific section. */ /* The chip-specific section for the Myson MTD-803 diagnostic. */ static void myson_eeprom(unsigned short *ee_data); static int eeprom_addr_len(long ioaddr); static int read_eeprom(long ioaddr, int location, int addr_len); static void write_eeprom(long ioaddr, int index, int value, int addr_len); int mdio_read(long ioaddr, unsigned int phy_id, unsigned int location); void mdio_write(long ioaddr, unsigned int phy_id, unsigned int location, int value); /* Offsets to the various registers. Most accesses must be longword aligned. */ enum register_offsets { StationAddr=0x00, MulticastFilter0=0x08,MulticastFilter1=0x0C, FlowCtrlAddr=0x10, RxConfig=0x18, TxConfig=0x1a, PCIBusConfig=0x1c, TxStartDemand=0x20, RxStartDemand=0x24, RxCurrentPtr=0x28, TxRingPtr=0x2c, RxRingPtr=0x30, IntrStatus=0x34, IntrEnable=0x38, FlowCtrlThreshold=0x3c, MIICtrl=0x40, EECtrl=0x42, RxErrCnts=0x44, TxErrCnts=0x48, PHYMgmt=0x4c, }; /* Bits in the interrupt status/mask registers. */ enum intr_status_bits { IntrRxErr=0x0002, IntrRxDone=0x0004, IntrTxDone=0x0008, IntrTxEmpty=0x0010, IntrRxEmpty=0x0020, StatsMax=0x0040, RxEarly=0x0080, TxEarly=0x0100, RxOverflow=0x0200, TxUnderflow=0x0400, IntrPCIErr=0x2000, NWayDone=0x4000, LinkChange=0x8000, }; /* The textual names of the interrupt indications. */ static const char *intr_names[] ={ "Unknown-0000", "Rx Early error", "Rx Done event", "Tx Done event", "Tx queue emptied", "Out of Rx buffers", "Statistics counters full", "Rx packet started", "Tx started", "Rx FIFO overflow", "Transmit FIFO underrun", "Bus-error-0800", "Bus-error-1000", "PCI bus fault", "Autonegotation completed", "Link status change", "Rx flow control Xoff", "Rx flow control Xon", "Link detection fault", }; /* Bits in the RxMode register. */ enum rx_mode_bits { AcceptErr=0x02, AcceptRunt=0x08, AcceptBroadcast=0x40, AcceptMulticast=0x20, AcceptAllPhys=0x80, AcceptMyPhys=0x00, }; /* Values read from the EEPROM, and a new image to write. */ #define MAX_EEPROM_SIZE 256 unsigned short eeprom_contents[MAX_EEPROM_SIZE]; unsigned short new_ee_contents[MAX_EEPROM_SIZE]; #define EEPROM_SA_OFFSET 0x08 #define EEPROM_CSUM_OFFSET 0 /* 0 means none. */ /* A table for emitting the configuration of a register. */ struct config_name { int val, mask; const char*name;} static rcvr_mode[] = { {0x41, 0xff, "Normal unicast with no multicast"}, {0x61, 0xff, "Normal unicast and hashed multicast"}, {0xe1, 0xff, "Promiscuous"}, {0x00, 0x01, "Receiver disabled"}, {0x00, 0x00, "Unknown/invalid"}, }; #include int myson_diag(int vendor_id, int device_id, long ioaddr, int part_idx) { int chip_active = inl(ioaddr + IntrEnable); int rx_mode = inl(ioaddr + RxConfig); int ee_addr_len = 6, eeprom_size = 64; int i; /* Always show the basic status. */ { unsigned int sa0 = inl(ioaddr + StationAddr); unsigned int sa1 = inl(ioaddr + StationAddr + 4); printf(" Station address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", sa0 & 0xff, (sa0 >> 8) & 0xff, (sa0 >> 16) & 0xff, (sa0 >> 24) & 0xff, sa1 & 0xff, (sa1 >> 8) & 0xff); } for (i = 0; rcvr_mode[i].mask; i++) if ((rx_mode & rcvr_mode[i].mask) == rcvr_mode[i].val) break; printf(" Receive mode is 0x%2.2x: %s.\n", rx_mode, rcvr_mode[i].name); if (verbose || show_regs) { unsigned intr_status; if (chip_active && !opt_f) { printf(" This device appears to be active, so some registers" " will not be read.\n" " To see all register values use the '-f' flag.\n"); } else chip_active = 0; /* Ignore the chip status with -f */ if (opt_a > 1) { /* If reading some registers hoses normal chip operation, perhaps clearing error counters or interrupts, add those registers to this bitmap. */ char dont_read[8] = {0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00}; printf("%s chip registers at %#lx", pcidev_tbl[part_idx].part_name, ioaddr); for (i = 0; i < pcidev_tbl[part_idx].io_size; i += 4) { if ((i & 0x1f) == 0) printf("\n 0x%3.3X:", i); if (chip_active && (dont_read[i>>5] & (1<<((i>>2) & 7)))) printf(" ********"); else printf(" %8.8x", inl(ioaddr + i)); } printf("\n"); } intr_status = inl(ioaddr + IntrStatus); if (intr_status == 0xffffffff && !opt_f) { printf(" * A recognized chip has been found, but it does not " "appear to exist in\n * I/O space. Use the" " '-f' flag to see the register values anyway.\n"); return 1; } printf(" %snterrupt sources are pending (%4.4x).\n", (intr_status & 0x03ff) ? "I": "No i", intr_status); if (intr_status) { for (i = 0; i < sizeof(intr_names)/sizeof(intr_names[0]); i++) if (intr_status & (1<\n"); if (set_hwaddr) { u16 backup_ee_contents[] = { 0x7310, 0x0083, 0x0000, 0x0000, 0x4020, 0x1516, 0x0803, 0x0000, 0x0200, 0xb02a, 0x9927, 0x0000, 0x0200, 0xb02a, 0x9927, 0x0000, 0x00F2, 0x0000, }; memcpy(new_ee_contents, eeprom_contents, eeprom_size << 1); if (emergency_rewrite) memcpy(new_ee_contents, backup_ee_contents, sizeof backup_ee_contents); for (i = 0; i < 3; i++) new_ee_contents[i + EEPROM_SA_OFFSET] = new_ee_contents[i + EEPROM_SA_OFFSET + 4] = new_hwaddr[i*2] + (new_hwaddr[i*2+1]<<8); for (i = 0; i < eeprom_size; i++) if (new_ee_contents[i] != eeprom_contents[i]) { if (do_write_eeprom) write_eeprom(ioaddr, i, new_ee_contents[i], ee_addr_len); else printf("Would write %4.4x to replace %4.4x at %d.\n", new_ee_contents[i], eeprom_contents[i], i); } } if (show_eeprom > 1) { printf("EEPROM contents (%d words):", eeprom_size); for (i = 0; i < eeprom_size; i += 8) { int j; printf("\n0x%2.2x: ", i); for (j = 0; j < 8; j++) printf(" %4.4x", eeprom_contents[i + j]); if (show_eeprom > 2) { printf(" "); for (j = 0; j < 8; j++) { int ew = eeprom_contents[i + j]; printf("%c%c", isalnum(ew & 0xff) ? ew & 0xff : '_', isalnum(ew >> 8) ? ew >> 8 : '_' ); } } } printf("\n"); } if (show_eeprom) myson_eeprom(eeprom_contents); if (show_mii) { int phys[4], phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(ioaddr, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { phys[phy_idx++] = phy; printf(" MII PHY found at address %d, status 0x%4.4x.\n", phy, mii_status); } } if (pcidev_tbl[part_idx].flags & HasChipXcvr) { /* Has on-chip xcvr */ phys[phy_idx++] = 32; } else if (phy_idx == 0) printf(" ***WARNING***: No MII transceivers found!\n"); for (phy = 0; phy < phy_idx; phy++) { int mii_reg; printf(" MII PHY #%d transceiver registers:", phys[phy]); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mdio_read(ioaddr, phys[phy], mii_reg)); printf(".\n"); } #ifdef LIBMII show_mii_details(ioaddr, phys[0]); if (show_mii > 1) monitor_mii(ioaddr, phys[0]); #endif } if (opt_flash_loadfile || opt_flash_dumpfile || opt_flash_show) printf("Flash operations not support in this version.\n"); return 0; } /* Serial EEPROM section. A "bit" grungy, but we work our way through bit-by-bit :->. */ /* The EEPROM commands always start with 01.. preamble bits. Commands are prepended to the variable-length address. */ enum EEPROM_Cmds { EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7, }; /* Chip-specific EEPROM_Ctrl bits. Some implementations have a data pin direction bit instead of separate data in and out bits. */ #define EE_OFFSET MIICtrl /* Register offset in I/O space. */ enum EEPROM_Ctrl_Bits { EE_ShiftClk=0x04<<16, EE_Enable=0x80<<16, EE_ChipSelect=0x08<<16, EE_DataOut=0x02<<16, EE_DataIn=0x01<<16, EE_Write0=0x88<<16, EE_Write1=0x8A<<16, }; /* Delay between EEPROM clock transitions. This forces out buffered PCI writes. */ #define eeprom_delay(ee_addr) do { int _i = 10; while(--_i >= 0) inl(ee_addr);} while(0) /* Execute a generic EEPROM command. Return all data output from the EEPROM, and thus may be used for EEPROM sizing, read, erase or write. */ static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len) { unsigned retval = 0; long ee_addr = ioaddr + EE_OFFSET; if (debug > 1) printf(" EEPROM op 0x%x: ", cmd); /* Shift the command bits out. */ do { int dataval = (cmd & (1 << cmd_len)) ? EE_Write1 : EE_Write0; outl(dataval, ee_addr); eeprom_delay(ee_addr); if (debug > 2) printf("%X", (inl(ee_addr)>>16) & 0x0f); outl(dataval | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); retval = (retval << 1) | ((inl(ee_addr) & EE_DataIn) ? 1 : 0); } while (--cmd_len >= 0); /* Terminate the EEPROM access. */ outl(EE_Enable & ~EE_ChipSelect, ee_addr); outl(0, ee_addr); if (debug > 1) printf(" EEPROM result is 0x%5.5x.\n", retval); return retval; } /* Wait for the EEPROM to finish what it is doing. */ static int eeprom_busy_poll(long ee_ioaddr) { int i; outl(EE_Write0, ee_ioaddr); eeprom_delay(ee_ioaddr); for (i = 0; i < 10000; i++) /* Typical 2000 ticks */ if (inl(ee_ioaddr) & EE_DataIn) break; return i; } /* The abstracted functions for EEPROM access. */ /* Return the number of address bits this EEPROM accepts. */ static int eeprom_addr_len(long ioaddr) { return do_eeprom_cmd(ioaddr, EE_ReadCmd << (6+16), 3 + 6 + 16) & 0x10000 ? 8 : 6; } static int read_eeprom(long ioaddr, int location, int addr_len) { return do_eeprom_cmd(ioaddr, ((EE_ReadCmd << addr_len) | location) << 16, 3 + addr_len + 16) & 0xffff; } static void write_eeprom(long ioaddr, int index, int value, int addr_len) { long ee_ioaddr = ioaddr + EE_OFFSET; int i; /* Poll for previous op finished. */ eeprom_busy_poll(ee_ioaddr); /* Enable programming modes. */ do_eeprom_cmd(ioaddr, (0x4f << (addr_len-4)), 3 + addr_len); /* Do the actual write. */ do_eeprom_cmd(ioaddr, (((EE_WriteCmd<> 8, ee_data[12] & 0xff, ee_data[12] >> 8); if (! opt_f) return; } printf("Decoded EEPROM contents:\n" " PCI Subsystem IDs -- Vendor %#4.4x, Device %#4.4x.\n" " PCI timer settings -- minimum grant %d, maximum latency %d.\n", ee_data[5], ee_data[6], ee_data[4] & 0xff, ee_data[4] >> 8); printf(" Ethernet MAC Station Address " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", ee_data[8] & 0xff, ee_data[8]>>8, ee_data[9] & 0xff, ee_data[9]>>8, ee_data[10] & 0xff, ee_data[10]>>8); printf(" Wake-On-LAN password " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", ee_data[12] & 0xff, ee_data[12]>>8, ee_data[13] & 0xff, ee_data[13]>>8, ee_data[14] & 0xff, ee_data[14]>>8); printf(" Configuration 0 is %4.4x, 2/1 is %4.4x.\n", ee_data[1], ee_data[16]); return; } /* MII - MDIO (Media Independent Interface - Management Data I/O) accesses. */ #if ! defined(MII_USE_PARALLEL) /* Read and write the MII registers using software-generated serial MDIO protocol. It is just different enough from the serial EEPROM protocol to not share code. The maxium data clock rate is 2.5 Mhz. */ #define mdio_delay() inl(mdio_addr) /* Force out buffered writes. */ #define MDIO_IO_OFFSET MIICtrl #define MDIO_SHIFT_CLK 0x01 #define MDIO_DATA_BIT 0x04 /* Derived values. */ #define MDIO_DATA_WRITE0 0x08 #define MDIO_DATA_WRITE1 0x0C #define MDIO_ENB 0x800000 #define MDIO_ENB_IN 0x00 #define MDIO_DATA_READ 0x02 /* Syncronize the MII management interface by shifting 32 one bits out. */ static void mdio_sync(long ioaddr) { long mdio_addr = ioaddr + MDIO_IO_OFFSET; int i; for (i = 32; i >= 0; i--) { outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); mdio_delay(); outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } return; } int mdio_read(long ioaddr, unsigned int phy_id, unsigned int location) { long mdio_addr = ioaddr + MDIO_IO_OFFSET; int i; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; if (verbose > 2) /* Debug: 5 */ printf(" mdio_read(%#lx, %d, %d)..", ioaddr, phy_id, location); if (location > 32) return -1; if (phy_id >= 32) { if (location < 6) return inw(ioaddr + PHYMgmt + location*2); else if (location == 16) return inw(ioaddr + PHYMgmt + 6*2); else if (location == 17) return inw(ioaddr + PHYMgmt + 7*2); else return 0; } /* Establish sync by sending at least 32 logic ones. */ mdio_sync(ioaddr); /* Shift the read command bits out. */ for (i = 17; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0; if (verbose > 3) /* Debug: 5 */ printf("%d", (read_cmd & (1 << i)) ? 1 : 0); outl(MDIO_ENB | dataval, mdio_addr); mdio_delay(); outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); if (verbose > 3) printf(" %x", (inl(mdio_addr) >> 16) & 0x0f); mdio_delay(); } if (verbose > 3) printf("-> %x", (inl(mdio_addr) >> 16) & 0x0f); /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { outl(MDIO_ENB_IN, mdio_addr); mdio_delay(); retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); if (verbose > 3) printf(" %x", (inl(mdio_addr) >> 16) & 0x0f); outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } if (verbose > 3) printf(" == %4.4x.\n", retval); return (retval>>1) & 0xffff; } void mdio_write(long ioaddr, unsigned int phy_id, unsigned int location, int value) { long mdio_addr = ioaddr + MDIO_IO_OFFSET; int i; int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; if (location > 32) return; if (phy_id >= 32) { if (location < 6) outw(value, ioaddr + PHYMgmt + location*2); else if (location == 16) outw(value, ioaddr + PHYMgmt + 6*2); else if (location == 17) outw(value, ioaddr + PHYMgmt + 7*2); return; } /* Establish sync by sending 32 logic ones. */ mdio_sync(ioaddr); /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; outl(MDIO_ENB | dataval, mdio_addr); mdio_delay(); outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { outl(MDIO_ENB_IN, mdio_addr); mdio_delay(); outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } return; } #else /* Parallel version, where the chip handles generates the serial protocol. These routines assume the MDIO controller is idle, and do not exit until the command is finished. */ int mdio_read(long ioaddr, int phy_id, int location) { int i = 10000; if (verbose > 2) /* Debug: 5 */ printf(" mdio_read(%#lx, %d, %d)..", ioaddr, phy_id, location); outw((phy_id<<8) + location, ioaddr + MII_Addr); outw(1, ioaddr + MII_Cmd); while (--i > 0) if ((inw(ioaddr + MII_Status) & 1) == 0) break; return inw(ioaddr + MII_Rd_Data); } void mdio_write(long ioaddr, int phy_id, int location, int value) { int i = 10000; outw((phy_id<<8) + location, ioaddr + MII_Addr); outw(value, ioaddr + MII_Wr_Data); /* Wait for the command to finish. */ while (--i > 0) if ((inw(ioaddr + MII_Status) & 1) == 0) break; return; } #endif /* * Local variables: * compile-command: "cc -O -Wall -Wstrict-prototypes -o myson-diag myson-diag.c `[ -f libmii.c ] && echo -DLIBMII libmii.c` `[ -f libmii.c ] && echo -DLIBFLASH libflash.c`" * simple-compile-command: "cc -O -Wall -o myson-diag myson-diag.c" * tab-width: 4 * c-indent-level: 4 * c-basic-offset: 4 * End: */ nictools-pci-1.3.8.orig/natsemi-diag.c0000644000175000017500000007550510264214554016544 0ustar alainalain/* natsemi-diag.c: National Semiconductor DP83815 diagnostic and setup. This is a diagnostic and EEPROM setup program for Ethernet adapters based on the National Semiconductor DP83810 / 83815 Written 1998-2002 by Donald Becker. Copyright Donald Becker and Scyld Computing Corporation This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 410 Severn Ave., Suite 210 Annapolis MD 21403 Support and updates available at http://www.scyld.com/diag/index.html http://scyld.com/expert/mii-status.html http://scyld.com/expert/NWay.html Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. */ static char *version_msg = "natsemi-diag.c:v2.07 12/17/2002 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: natsemi-diag [-aEefFGhmqrRtvVwW] [-p ] [-[AF] ]\n" " For details and other options see http://www.scyld.com/diag/index.html\n"; static const char long_usage_msg[] = "Usage: %s [-aDfrRvVw] [-AF ] [-#]\n" "\n" " Show the internal state of a network adapter.\n" "\n" " The common usage is\n" " natsemi-diag -aem\n" "\n" " Frequently used options are\n" " -a --show_all_registers Print all registers.\n" " -e --show-eeprom Dump EEPROM contents, \"-ee\" shows the details.\n" " -m --show_mii Print the MII transceiver state\n" " Using -mm monitors the link.\n" " -f --force Perform operation, even on a running NIC.\n" "\n" " To operate on a single NIC, or one that hasn't been automatically found:\n" " -# --card_num INDEX Operate on the specified card index.\n" " -p --port-base IOADDR Assume an adapter at the specified I/O address.\n" " -t --chip-type TYPE Specify adapter type with '-p', use '-1' to list.\n" "\n" " To change the persistent EEPROM settings\n" " -G --parameters PARMS Set adapter-specific parameters.\n" " -H --new-hwaddr 01:23:45:67:ab:cd\n" " Set a new hardware station address. Typically diabled, \n" " -w --write-EEPROM Actually write the new settings into the EEPROM.\n" " To read and write the boot BIOS extension Flash ROM\n" " -B Show the first few bytes of the ROM\n" " -L FILE Load the Flash from FILE.\n" " -S FILE Store the Flash image to FILE.\n" "\n" " -D --debug\n" " -v --verbose Report each action taken.\n" " -V --version Emit version information.\n" "\n" " -A --advertise (See the mii-diag manual page.)\n" "\n"; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include #include #include /* The following are required only with unaligned field accesses. */ #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif /* No libmii.h or libflash.h yet, thus the declarations here. */ extern int show_mii_details(long ioaddr, int phy_id); extern int monitor_mii(long ioaddr, int phy_id); extern int flash_show(long addr_ioaddr, long data_ioaddr); extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename); extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename); extern int (*flash_in_hook)(long addr, int offset); extern void (*flash_out_hook)(long addr, int offset, int val); /* We should use __u8 .. __u32, but they are not always defined. */ typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; struct option longopts[] = { /* { name has_arg *flag val } */ {"card-num", 1, 0, '#'}, /* Operate on the specified card index. */ {"Advertise", 1, 0, 'A'}, {"base-address", 1, 0, 'p'}, {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Print a long usage message. */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; extern int natsemi_diag(int vend_id, int dev_id, long ioaddr, int part_idx); /* Chip-specific flags. Yes, it's grungy to have the enum here. */ /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name from the kernel, a common name and the PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { const char *part_name; const char *proc_pci_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx); } pcidev_tbl[] = { {"NatSemi DP83815", "National Semiconductor DP83815", 0x100B, 0x0020, 0xffff, 0, 256, natsemi_diag}, { 0, 0, 0, 0}, }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int nway_advertise = 0, fixed_speed = -1; int new_default_media = -1; /* Valid with libflash only. */ static unsigned int opt_flash_show = 0; static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int emergency_rewrite = 0; static int scan_proc_pci(int card_num); static int parse_media_type(const char *capabilities); static int get_media_index(const char *name); int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:hH:mp:qrRt:TvVwWBL:S:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'A': nway_advertise = parse_media_type(optarg); break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 16); break; case 'h': fprintf(stderr, long_usage_msg, argv[0]); return 0; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtoul(optarg, NULL, 16); break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'T': do_test++; break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case 'W': opt_watch++; break; case 'B': opt_flash_show++; break; case 'L': opt_flash_loadfile = optarg; break; case 'S': opt_flash_dumpfile = optarg; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("Network adapter diagnostic: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for parsed contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n" " See http://www.scyld.com/expert/irq-conflict.html for more information.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if ((pci_devid >> 16) != pcidev_tbl[i].vendor || (pci_devid & pcidev_tbl[i].device_mask) != pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].part_name; i++) if (pcidev_tbl[i].proc_pci_name && strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Convert a text media name to a NWay capability word. */ static int parse_media_type(const char *capabilities) { const char *mtypes[] = { "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD", "10baseT", "10baseT-FD", "10baseT-HD", 0, }; char *endptr; int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,}; int i; if (debug) fprintf(stderr, "Advertise string is '%s'.\n", capabilities); for (i = 0; mtypes[i]; i++) if (strcasecmp(mtypes[i], capabilities) == 0) return cap_map[i]; i = strtoul(capabilities, &endptr, 16); if (*endptr == 0 && 0 < i && i <= 0xffff) return i; fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities); return 0; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to EEPROM setting. These match the natsemi internal values. */ struct { char *name; int value; } mediamap[] = { { "Force 10baseT half duplex", 0 }, { "Advertise 10 Mbps half and full duplex", 1 }, { "Force 100 Mbps half duplex", 2 }, { "Advertise 10/100 Mbps half duplex", 3 }, { "Force 10 Mbps, full duplex", 4 }, { "Advertise 100 Mbps half and full duplex", 5 }, { "Force 100 Mbps full duplex", 6 }, { "Advertise 10/100 Mbps half and full duplex", 7 }, { 0, 0 }, }; static int get_media_index(const char *name) { char *endptr; int i; if (! name) return -1; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) return i; i = strtol(name, &endptr, 0); if (*endptr == 0) return i; fprintf(stderr, "Invalid interface specified. It must be one of\n"); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %d %s\n", mediamap[i].value, mediamap[i].name); return -1; } /* Chip-specific section. */ /* The National Semiconductor DP83810 series. */ static void natsemi_eeprom(unsigned short *ee_data); /* Offsets to the DP83815 registers.*/ enum register_offsets { ChipCmd=0x00, ChipConfig=0x04, EECtrl=0x08, TestControl=0x0C, IntrStatus=0x10, IntrMask=0x14, IntrEnable=0x18, TxRingPtr=0x20, TxConfig=0x24, RxRingPtr=0x30, RxConfig=0x34, WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C, BootRomAddr=0x50, BootRomData=0x54, StatsCtrl=0x5C, StatsData=0x60, RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64, }; /* The textual names of the interrupt indications. */ static const char *intr_names[] ={ "Rx Done event", "Rx event", "Receive error", "Rx started", "Receiver idle", "Rx overrun", "Tx complete", "Tx packet in FIFO", "Transmit error", "Tx queue emptied", "Tx underrun", "Statistics counters full", "Driver software intr", "Wake-up packet", "Link change wakeup", "Error summary", "Rx status overrun", "Intr-17", "Intr-18", "Intr-19", "PCI target abort", "PCI master abort", "PCI system error", "PCI parity error", "Receiver reset done", "Transmitter reset done", }; /* A table for emitting the configuration of a register. */ struct config_name { int val, mask; const char*name;}; static struct config_name rcvr_mode[] = { {0x00000000, 0x80000000, "Receive disabled"}, {0xf0000000, 0xf0000000, "Promiscuous"}, {0xe0000000, 0xf0100000, "Normal unicast and all multicast"}, {0xc0200000, 0xf0300000, "Normal unicast and hashed multicast"}, {0xc0000000, 0xf0300000, "Normal unicast and match filter"}, {0x00, 0x00, "Unknown/invalid"}, }; /* Autonegotation selection bits in the EEPROM and ChipCmd. */ static const char *aneg_sel[8] = { "10 Mbps, half", "10 Mbps half and full", "100 Mbps half", "10/100 Mbps half", "10 Mbps, full", "100 Mbps half and full", "100 Mbps full", "10/100 Mbps half and full" }; /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses. */ /* Delay between EEPROM clock transitions. This flushes the write buffer to prevent quick double-writes. */ #define eeprom_delay(ee_addr) inl(ee_addr); inl(ee_addr) enum EEPROM_Ctrl_Bits { EE_ShiftClk=0x04, EE_DataIn=0x01, EE_ChipSelect=0x08, EE_DataOut=0x02, }; #define EE_Write0 (EE_ChipSelect) #define EE_Write1 (EE_ChipSelect | EE_DataIn) /* The EEPROM commands always start with 01.. preamble bits. Commands are prepended to the variable-length address. */ enum EEPROM_Cmds { EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7, }; /* Values read from the EEPROM, and a new image to write. */ #define EEPROM_SIZE 256 static unsigned short eeprom_contents[EEPROM_SIZE]; static unsigned short new_ee_contents[EEPROM_SIZE]; #define EEPROM_SA_OFFSET 7 #define EE_OFFSET EECtrl /* Register offset in I/O space. */ /* Execute a generic EEPROM command. Return all data output from the EEPROM, and thus may be used for EEPROM sizing, read, erase or write. */ static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len) { unsigned retval = 0; long ee_addr = ioaddr + EE_OFFSET; if (debug > 1) printf(" EEPROM op 0x%x: ", cmd); outl(EE_ChipSelect | EE_ShiftClk, ee_addr); /* Shift the command bits out. */ do { short dataval = (cmd & (1 << cmd_len)) ? EE_Write1 : EE_Write0; outl(dataval, ee_addr); eeprom_delay(ee_addr); if (debug > 2) printf("%X", inl(ee_addr) & 15); outl(dataval | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); retval = (retval << 1) | ((inl(ee_addr) & EE_DataOut) ? 1 : 0); } while (--cmd_len >= 0); outl(EE_ChipSelect, ee_addr); /* Terminate the EEPROM access. */ outl(0, ee_addr); if (debug > 1) printf(" EEPROM result is 0x%5.5x.\n", retval); return retval; } /* Wait for the EEPROM to finish what it is doing. */ static int eeprom_busy_poll(long ee_ioaddr) { int i; outl(EE_ChipSelect, ee_ioaddr); for (i = 0; i < 10000; i++) /* Typical 2000 ticks */ if (inl(ee_ioaddr) & EE_DataOut) break; return i; } static int bit_reverse_16(int val) { int i, result = 0; for (i = 0; i < 16; i++) { result = (result << 1) | (val & 1); val >>= 1; } return result; } /* The abstracted functions for EEPROM access. */ static int read_eeprom(long ioaddr, int location, int addr_len) { return do_eeprom_cmd(ioaddr, ((EE_ReadCmd << addr_len) | location) << 16, 3 + addr_len + 16) & 0xffff; } static void write_eeprom(long ioaddr, int index, int value, int addr_len) { long ee_ioaddr = ioaddr + EE_OFFSET; int i; /* Poll for previous op finished. */ eeprom_busy_poll(ee_ioaddr); /* Enable programming modes. */ do_eeprom_cmd(ioaddr, (0x4f << (addr_len-4)), 3 + addr_len); /* Do the actual write. */ do_eeprom_cmd(ioaddr, (((EE_WriteCmd<> 8) & 0xff, i < 4 ? ':' : '\n'); } printf(" Transceiver setting %s %s duplex.\n", chip_config & 0x2000 ? "Autonegotation advertise" : "force", aneg_sel[(chip_config>>13) & 7]); if (opt_G) { printf("Setting the configuration register to %8.8x.\n", opt_GPIO); outl(opt_GPIO, ioaddr + ChipConfig); } if (verbose > 1 || show_regs) { unsigned int intr_status = inl(ioaddr + IntrStatus); char dont_read[8] = {0x10,0x00,0x01,0xff,0x00,0xff,0x00,0x00}; if (chip_active && !opt_f) { printf(" This device appears to be active, so some registers" " will not be read.\n" " To see all register values use the '-f' flag.\n"); } else chip_active = 0; /* Ignore the chip status with -f */ printf("%s chip registers at %#lx", pcidev_tbl[part_idx].part_name, ioaddr); for (i = 0; i < pcidev_tbl[part_idx].io_size; i += 4) { if ((i & 0x1f) == 0) printf("\n 0x%3.3X:", i); if (chip_active && (dont_read[i>>5]) & (1<<((i>>2) & 7))) printf(" ********"); else printf(" %8.8x", (int)inl(ioaddr + i)); } printf("\n"); if (intr_status == 0xffffffff && !opt_f) { printf(" * A recognized chip has been found, but it does not " "appear to exist in\n * I/O space. Use the" " '-f' flag to see the register values anyway.\n"); return 1; } printf(" %snterrupt sources are pending (%8.8x).\n", (intr_status & 0x03ff) ? "I": "No i", intr_status); if (intr_status) { for (i = 0; i < sizeof(intr_names)/sizeof(intr_names[0]); i++) if (intr_status & (1< 1) { printf(" Rx filter contents: "); for (i = 0; i < 16; i+=2) { outw(i, ioaddr + RxFilterAddr); printf(" %4.4x", (int)inl(ioaddr + RxFilterData)); } printf("\n"); } } outl(rx_mode, ioaddr + RxFilterAddr); if (do_test && chip_active && !opt_f) printf(" Running these diagnostic test is not recommended while the " "device is active.\n" " To run them anyway, use the '-f' flag.\n"); else if (do_test) { int result; outl(0x80, ioaddr + TestControl); for (i = 0; i < 10000; i++) { /* Typical 260 iterations. */ if (inl(ioaddr + TestControl) & 0x40) break; } result = inl(ioaddr + TestControl); if (debug) printf(" Internal SRAM test took %d ticks.\n", i); printf(" Internal SRAM test result is %4.4x: %s.\n", result, result & 0x38 ? "failed" : "passed"); if (result & 0x38) { if (result & 0x20) fprintf(stderr, " *** Rx FIFO test failed!\n"); if (result & 0x10) fprintf(stderr, " *** Tx FIFO test failed!\n"); if (result & 0x10) fprintf(stderr, " *** Rx Filter test failed!\n"); if ( ! opt_f) return 2; } outl(0x02, ioaddr + TestControl); for (i = 0; i < 10000; i++) { /* Typical 2500 iterations. */ if ( ! (inl(ioaddr + TestControl) & 0x02)) break; } result = inl(ioaddr + TestControl); if (debug) printf(" EEPROM internal test took %d ticks.\n", i); printf(" Configuration EEPROM checksum test result is %4.4x: %s.\n", result, result & 1 ? "failed" : "passed"); } if (set_hwaddr || show_eeprom || new_default_media >= 0) { ee_addr_len = do_eeprom_cmd(ioaddr, EE_ReadCmd << (6+16), 3 + 6 + 16) & 0x10000 ? 8 : 6; eeprom_size = 1 << ee_addr_len; printf(" EEPROM address length %d, %d words.\n", ee_addr_len, eeprom_size); /* Bit-reverse the result. Damn designers mixed big-endian and LE. */ for (i = 0; i < eeprom_size; i++) eeprom_contents[i] = bit_reverse_16(read_eeprom(ioaddr, i, ee_addr_len)); memcpy(new_ee_contents, eeprom_contents, sizeof eeprom_contents); } if (emergency_rewrite && ! set_hwaddr) printf("*** Emergency EEPROM rewrite is only valid when you also " "specify a new\n*** station address with -H \n"); if (set_hwaddr) { u16 backup_ee_contents[] = { 0x1385, 0xf311, 0x0b34, 0x41f3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1915, }; if (emergency_rewrite) memcpy(new_ee_contents, backup_ee_contents, sizeof backup_ee_contents); /* Grrr, damn designers dropped a bit and "fixed" the hardware by documenting the EEPROM layout to work that way. */ new_ee_contents[6] &= ~0x8000; new_ee_contents[6] |= new_hwaddr[0] & 1 ? 0x8000 : 0; new_ee_contents[7] = (new_hwaddr[0] >> 1) + (new_hwaddr[1]<<7) + (new_hwaddr[2]<<15); new_ee_contents[8] = (new_hwaddr[2] >> 1) + (new_hwaddr[3]<<7) + (new_hwaddr[4]<<15); new_ee_contents[9] = (new_hwaddr[4] >> 1) + (new_hwaddr[5]<<7) + (new_ee_contents[9] & 0x8000); eeprom_change++; } if (new_default_media >= 0) { new_ee_contents[3] &= ~0x0070; new_ee_contents[3] |= (new_default_media << 4) & 0x00F0; eeprom_change++; } if (eeprom_change) { int sum = 0; /* Calculate the new checksum. */ for (i = 0; i < 11; i++) { unsigned short tmp = bit_reverse_16(new_ee_contents[i]); sum += tmp + (tmp>>8); } new_ee_contents[i] = 0xaa00 + (bit_reverse_16(0xaa - sum + 1) >> 8); for (i = 0; i < 16; i++) if (new_ee_contents[i] != eeprom_contents[i]) { if (do_write_eeprom) write_eeprom(ioaddr, i, new_ee_contents[i], ee_addr_len); else printf("Would write %4.4x to replace %4.4x at %d.\n", new_ee_contents[i], eeprom_contents[i], i); } } if (show_eeprom > 1) { printf("EEPROM contents (%d words):", eeprom_size); for (i = 0; i < eeprom_size; i += 8) { int j; printf("\n0x%2.2x: ", i); for (j = 0; j < 8; j++) printf(" %4.4x", eeprom_contents[i + j]); if (show_eeprom > 2) { printf(" "); for (j = 0; j < 8; j++) { int ew = eeprom_contents[i + j]; printf("%c%c", isprint(ew & 0xff) ? ew & 0xff : '_', isprint(ew >> 8) ? ew >> 8 : '_' ); } } } printf("\n"); } if (show_eeprom) natsemi_eeprom(eeprom_contents); if (show_mii) { #ifdef LIBMII show_mii_details(ioaddr, 1); if (show_mii > 1) monitor_mii(ioaddr, 1); #else int mii_reg; printf(" Internal PHY with MII management register."); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mdio_read(ioaddr, 1, mii_reg)); printf(".\n"); #endif } #ifdef LIBFLASH { flash_in_hook = natsemi_flash_in; flash_out_hook = natsemi_flash_out; if (opt_flash_show) flash_show(ioaddr, 0); if (opt_flash_dumpfile) if (flash_dump(ioaddr, 0, opt_flash_dumpfile) < 0) { fprintf(stderr, "Failed to save the old Flash BootROM image " "into file '%s'.\n", opt_flash_dumpfile); return 3; } if (opt_flash_loadfile) if (flash_program(ioaddr, 0, opt_flash_loadfile) < 0) { fprintf(stderr, "Failed to load the new Flash BootROM image " "from file '%s'.\n", opt_flash_loadfile); return 4; } } #else if (opt_flash_loadfile || opt_flash_dumpfile || opt_flash_show) printf("Flash operations not configured into this program.\n"); if (opt_flash_show) { printf("The first few boot ROM bytes are:"); for (i = 0; i < 8; i++) printf(" %2.2x", natsemi_flash_in(ioaddr, i)); printf(".\n"); } #endif return 0; } static void natsemi_eeprom(unsigned short *ee_data) { int i, sum = 0; unsigned int val; printf("Decoded EEPROM contents:\n" " PCI Subsystem IDs -- Vendor %#4.4x, Device %#4.4x.\n" " PCI timer settings -- minimum grant %d, maximum latency %d.\n", ee_data[0], ee_data[1], ee_data[2] >> 8, ee_data[2] & 0xff); printf(" Ethernet MAC Station Address " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", (ee_data[7]<<1) & 0xff, (ee_data[7]>>7) & 0xff, ((ee_data[8]<<1) + (ee_data[7]>>15)) & 0xff, (ee_data[8]>>7)&0xff, ((ee_data[9]<<1) + (ee_data[8]>>15)) & 0xff, (ee_data[9]>>7)&0xff); printf(" Wake-On-LAN password " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", ee_data[4] & 0xff, ee_data[4]>>8, ee_data[5] & 0xff, ee_data[5]>>8, ee_data[6] & 0xff, ee_data[6]>>8); val = (ee_data[3] >> 4) & 0x0F; printf(" Transceiver setting 0x--%x-: %s %s duplex.\n", val, val & 1 ? "advertise" : "force", aneg_sel[val & 7]); if (val & 8) printf(" Flow control enabled.\n"); for (i = 0; i < 11; i++) { unsigned short tmp = bit_reverse_16(ee_data[i]); sum += tmp + (tmp>>8); } sum = bit_reverse_16(0xaa - sum + 1) >> 8; printf(" EEPROM active region checksum read as %4.4x, vs aa%2.2x " "calculated value.\n", ee_data[11], sum); return; } /* * Local variables: * compile-command: "cc -O -Wall -o natsemi-diag natsemi-diag.c" * tab-width: 4 * c-indent-level: 4 * c-basic-offset: 4 * End: */ nictools-pci-1.3.8.orig/ne2k-pci-diag.c0000644000175000017500000007743510264220564016516 0ustar alainalain/* ne2k-pci-diag.c: Diagnostics/EEPROM setup for PCI NE2000 clones. This is a diagnostic and EEPROM setup program for PCI NE2000 Ethernet adapters. Copyright 1998-2002 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 Support and updates available at http://www.scyld.com/diag/index.html References http://www.scyld.com/diag/index.html RealTek RTL8029AS datasheet, available from www.RealTek.com.tw. Holtek HT80232 ECON-PCI datasheet, www.holtek.com.tw http://www.winbond.com.tw/PDF/sheet/w89c940f.pdf http://www.VIA.com.tw/products/prodamazon.htm Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. */ static char *version_msg = "ne2k-pci-diag.c:v2.06 2/28/2005 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: ne2k-pci-diag [-aEefFmqrRtvVwW] [-p [-t ]]\n"; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif struct option longopts[] = { /* { name has_arg *flag val } */ {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Give help */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; enum ne2k_chip_flags { ONLY_16BIT_IO=1, HOLTEK_EE=2, RTL_EE=4, WINBOND_EE=8, VIA_EE=16, BOGUS_WINBOND=0x100, }; extern int ne2k_diag(int vend_id, int dev_id, long ioaddr, int part_idx); /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name and a PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { const char *part_name; const char *proc_pci_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx); } pcidev_tbl[] = { { "Generic PCI NE2000 clone", "Generic PCI NE2000 clone", 0xffff, 0x2000, 0xffff, 0, 32, ne2k_diag}, /* First three are ordered for the 'unknown_eeprom_message' message. */ { "Realtek 8029", "RealTek RTL8029", 0x10ec, 0x8029, 0xffff, RTL_EE, 32, ne2k_diag}, { "Winbond 89C940", "Winbond 89C940", 0x1050, 0x0940, 0xffff, WINBOND_EE, 32, ne2k_diag}, { "Holtek HT80229", "Holtek HT80229", 0x12c3, 0x5598, 0xffff, HOLTEK_EE, 64, ne2k_diag}, { "Via 82C926", "Via 82C926", 0x1106, 0x0926, 0xffff, VIA_EE, 32, ne2k_diag}, { "Compex RL2000", "Compex RL2000", 0x11f6, 0x1401, 0xffff, 0, 32, ne2k_diag}, { "KTI ET32P2", "KTI ET32P2", 0x8e2e, 0x3000, 0xffff, 0, 32, ne2k_diag}, { "NetVin NV5000", "NetVin NV5000", /* Renumbered RTL8029. */ 0x4a14, 0x5000, 0xffff, RTL_EE, 32, ne2k_diag}, { "SureCom NE34", "SureCom NE34", 0x10bd, 0x0e34, 0xffff, 0, 32, ne2k_diag}, { "Winbond 940 (unprogrammed)","Winbond 940 (unprogrammed)", 0x1050, 0x5a5a, 0xffff, WINBOND_EE, 32, ne2k_diag}, { "Holtek HT80232", "Holtek HT80232", 0x12c3, 0x0058, 0xffff, ONLY_16BIT_IO | HOLTEK_EE, 64, ne2k_diag}, { "Winbond 89C940 (misprogrammed)", 0, 0x8c4a, 0x1980, 0xffff, WINBOND_EE | BOGUS_WINBOND, 32, ne2k_diag}, { 0, } }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int new_default_media = -1; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int emergency_rewrite = 0; static int scan_proc_pci(int card_num); static int get_media_index(const char *name); int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:mp:qrRst:TvVwH:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 16); break; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtoul(optarg, NULL, 16); break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'T': do_test++; break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("ne2k-pci-diag: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for parsed contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n" " See http://www.scyld.com/expert/irq-conflict.html for more information.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if ((pci_devid >> 16) != pcidev_tbl[i].vendor || (pci_devid & pcidev_tbl[i].device_mask) != pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].part_name; i++) if (pcidev_tbl[i].proc_pci_name && strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to indices. This matches the Digital Tulip SROM numbering, primarily because that is the most complete list. Other chips will have to map these number to their internal values. */ struct { char *name; int value; } mediamap[] = { { "10baseT", 0 }, { "10base2", 1 }, { "AUI", 2 }, { "100baseTx", 3 }, { "10baseT-FDX", 0x204 }, { "100baseTx-FDX", 0x205 }, { "100baseT4", 6 }, { "100baseFx", 7 }, { "100baseFx-FDX", 8 }, { "MII", 11 }, { "Autosense", 0x0800 }, { 0, 0 }, }; static int get_media_index(const char *name) { int i; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) return i; if (name && atoi(name) >= 00) return atoi(name); fprintf(stderr, "Invalid interface specified: it must be one of\n "); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %s", mediamap[i].name); fprintf(stderr, ".\n"); return -1; } /* Chip-specific section. */ /* The chip-specific section for the PCI NE2000 diagnostic. */ /* Constants with useful names (you will still need the datasheet though). */ #define EEPROM_SIZE 64 /* Values read from the EEPROM, and the new image. */ unsigned short eeprom_contents[EEPROM_SIZE]; unsigned short new_ee_contents[EEPROM_SIZE]; /* Values from 8390.h, here to avoid version skew and bogus email. */ #define NS_CMD (dev->base_addr) #define NS_BASE (dev->base_addr) #define NS_DATAPORT 0x10 /* NatSemi-defined port window offset. */ #define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */ #define NS_RESET 0x1f /* Issue a read to reset, a write to clear. */ #define NE1SM_START_PG 0x20 /* First page of TX buffer */ #define NE1SM_STOP_PG 0x40 /* Last page +1 of RX ring */ #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ #define E8390_CMD 0x00 /* The command register (for all pages) */ #define E8390_STOP 0x01 /* Stop and reset the chip */ #define E8390_START 0x02 /* Start the chip, clear reset */ #define E8390_RREAD 0x08 /* Remote read */ #define E8390_NODMA 0x20 /* Remote DMA */ #define E8390_PAGE0 0x00 /* Select page chip registers */ #define E8390_PAGE1 0x40 /* using the two high-order bits */ #define E8390_PAGE2 0x80 /* Page 2 is has only a few defined. */ #define E8390_PAGE3 0xC0 /* Page 3 is propriatary data. */ #define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */ #define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */ /* Page 0 register offsets. */ #define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */ #define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */ #define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */ #define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */ #define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */ #define EN0_TSR 0x04 /* Transmit status reg RD */ #define EN0_TPSR 0x04 /* Transmit starting page WR */ #define EN0_NCR 0x05 /* Number of collision reg RD */ #define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */ #define EN0_FIFO 0x06 /* FIFO RD */ #define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */ #define EN0_ISR 0x07 /* Interrupt status reg RD WR */ #define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */ #define EN0_RSARLO 0x08 /* Remote start address reg 0 */ #define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */ #define EN0_RSARHI 0x09 /* Remote start address reg 1 */ #define EN0_RCNTLO 0x0a /* Remote byte count reg WR */ #define EN0_RCNTHI 0x0b /* Remote byte count reg WR */ #define EN0_RSR 0x0c /* rx status reg RD */ #define EN0_RXCR 0x0c /* RX configuration reg WR */ #define EN0_TXCR 0x0d /* TX configuration reg WR */ #define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */ #define EN0_DCFG 0x0e /* Data configuration reg WR */ #define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */ #define EN0_IMR 0x0f /* Interrupt mask reg WR */ #define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */ /* The EEPROM commands include the alway-set leading bit. */ enum EEPROM_Cmds { EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7, }; /* Info for the rtl8029 configuration. */ static const char *const rtl_xcvr[4] = { "10baseT/coax (autoselected on 10baseT link beat)", "10baseT with link test disabled", "10base5 / AUI", "10base2"}; static int rtl_romsize[4] = { 0, 8, 16, 32}; static void do_ne2k_eeprom(long ioaddr, int part_idx); static int read_eeprom(int chip_flags, long ioaddr, int offset, int addr_len); static int do_update(int chip_flags, long ioaddr, int index, int addr_len, const char *field_name, int old_value, int new_value); static void parse_8029_eeprom(unsigned short *ee_data); static void parse_holtek_eeprom(unsigned short *ee_data); static void parse_winbond_eeprom(unsigned short *ee_data); int ne2k_diag(int vend_id, int dev_id, long ioaddr, int part_idx) { int chip_active = 0; int saved_window = inb(E8390_CMD); int capabilities = pcidev_tbl[part_idx].flags; int i; /* It's mostly safe to examine the registers and EEPROM during operation. But warn the user, and make then pass '-f'. */ if ((inb(ioaddr + E8390_CMD) & 0xC0) == 0x00) chip_active = 1; if (verbose || show_regs) { unsigned intr_status; int j; if (chip_active && ! opt_f) { printf("The 8390 core appears to be active, so some registers" " will not be read.\n" "To see all register values use the '-f' flag.\n"); } printf("Initial window %d, registers values by window:\n", saved_window >> 6); for (j = 0; j < 0x100; j+=0x40) { printf(" Window %d:", j>>6); outw(j, ioaddr + E8390_CMD); for (i = 0; i < 16; i++) { printf(" %2.2x", inb(ioaddr + i)); } printf(".\n"); } if (capabilities & RTL_EE) { int config2 = inb(ioaddr + 5); int config3 = inb(ioaddr + 6); printf(" RTL8029 transceiver: %s %s duplex.\n" " %s %dK boot ROM.\n", rtl_xcvr[config2>>6], config3 & 0x40 ? " forced full" :"half", config2 & 0x20 ? " flow control enabled," : "", rtl_romsize[config2 & 3]); } outb(0, ioaddr + E8390_CMD); intr_status = inb(ioaddr + EN0_ISR); printf("\n %snterrupt sources are pending (%2.2x).\n", (intr_status & 0xff) ? "I": "No i", intr_status); if (intr_status) { const char *intr_names[] = { "Rx packet", "Tx done", "Rx error", "Tx error", "Rx overflow", "Counter full", "Transfer done", "Resetting" }; for (i = 0; i < 13; i++) if (intr_status & (1< /* First, the definitions for the serial EEPROM bits. */ struct ee_ctrl_bits { int offset; unsigned char shift_clk, /* Bit that drives SK (shift clock) pin */ read_bit, /* Mask bit for DO pin value */ write_0, write_1, /* Enable chip and drive DI pin with 0 / 1 */ disable; /* Disable chip. */ } ee_ctrl_tbl[] = { { 0x01, 0x04, 0x01, 0x88, 0x8A, 0x00 }, /* RTL8029 */ { 0x22, 0x12, 0x04, 0x11, 0x19, 0x00 }, /* HolTek */ { 0x10, 0x04, 0x01, 0x88, 0x8A, 0x00 }, /* VIA */ }; /* This executes a generic EEPROM command, typically a write or write enable. It returns the data output from the EEPROM, and thus may also be used for reads and EEPROM sizing. */ static int do_eeprom_cmd(int chip_flags, long ioaddr, int cmd, int cmd_len) { struct ee_ctrl_bits ee = ee_ctrl_tbl[chip_flags & RTL_EE ? 0 : 1]; long ee_addr = ioaddr + ee.offset; unsigned retval = 0; if (debug > 1) printf(" EEPROM op 0x%x: ", cmd); /* Shift the command bits out. */ do { short dataval = (cmd & (1 << cmd_len)) ? ee.write_1 : ee.write_0; outb(dataval, ee_addr); inb(ee_addr); /* Timing delay */ if (debug > 2) printf("%X", inb(ee_addr) & 15); outb(dataval | ee.shift_clk, ee_addr); inb(ee_addr); /* Timing delay */ retval = (retval << 1) | ((inb(ee_addr) & ee.read_bit) ? 1 : 0); } while (--cmd_len >= 0); outb(ee.write_0, ee_addr); /* Terminate the EEPROM access. */ outb(ee.disable, ee_addr); if (debug > 1) printf(" EEPROM result is 0x%5.5x.\n", retval); return retval; } /* Wait for the EEPROM to finish what it is doing. */ static int eeprom_busy_poll(int chip_flags, long ioaddr) { struct ee_ctrl_bits ee = ee_ctrl_tbl[chip_flags & RTL_EE ? 0 : 1]; long ee_addr = ioaddr + ee.offset; int i; outb(ee.write_0, ee_addr); for (i = 0; i < 10000; i++) /* Typical 2000 ticks */ if (inb(ee_addr) & ee.read_bit) break; return i; } /* The abstracted functions for serial EEPROM access. */ static int read_eeprom(int chip_flags, long ioaddr, int location, int addr_len) { if (chip_flags & WINBOND_EE) { int boguscnt; outb(0x80, ioaddr + 2); /* Read command. */ outw(location, ioaddr + 4); /* Address to read. */ for (boguscnt = 10000; boguscnt >= 0; boguscnt--) if ((inb(ioaddr + 2) & 0x80) == 0) break; inw(ioaddr + 4); return inw(ioaddr + 4); } else return do_eeprom_cmd(chip_flags, ioaddr, ((EE_ReadCmd << addr_len) | location) << 16, 3 + addr_len + 16) & 0xffff; } static void write_eeprom(int chip_flags, long ioaddr, int index, int value, int addr_len) { int i; if (chip_flags & WINBOND_EE) { /* The chip handles the write for us. */ int boguscnt; /* The chip should already be in PAGE3 from the read. */ outb(0xC0, ioaddr + 2); /* Write command. */ outw(index, ioaddr + 4); /* Address to write. */ outw(value, ioaddr + 4); /* Data to write. */ for (boguscnt = 10000; boguscnt >= 0; boguscnt--) if ((inb(ioaddr + 2) & 0x80) == 0) break; return; } /* Poll for previous op finished. */ eeprom_busy_poll(chip_flags, ioaddr); /* Enable programming modes. */ do_eeprom_cmd(chip_flags, ioaddr, (0x4f << (addr_len-4)), 3 + addr_len); /* Do the actual write. */ do_eeprom_cmd(chip_flags, ioaddr, (((EE_WriteCmd<>6]); printf(" PCI Vendor ID %#4.4x Device ID %#4.4x\n" " Subsystem ID: vendor %#4.4x device %#4.4x\n", ee_data[60], ee_data[61], ee_data[62], ee_data[63]); return; } static void parse_holtek_eeprom(unsigned short *ee_data) { unsigned char *p = (void *)ee_data; int i; printf("Parsing the EEPROM of a HolTek NE2000 clone:\n"); printf(" Station Address "); for (i = 0; i < 5; i++) printf("%2.2X:", p[i]); printf("%2.2X (used as the ethernet address).\n", p[i]); printf(" PCI Vendor ID %#4.4x, Subsystem IDs: vendor %#4.4x device " "%#4.4x\n System control 0x%2.2x MAC config 0x%2.2x\n", ee_data[6], ee_data[4], ee_data[5], ee_data[3]>>8, ee_data[3]&0xff); return; } static const char *const winbond_xcvr[4] = { "10baseT", "10base2", "AUI", "10baseT extended length / reduced squelch level",}; static const char *const winbond_rom[8] = { "No", "No", "8KB", "16KB", "32KB", "64KB", "128KB", "256KB" }; static const char winbond_bogus_msg[] = "\n\ This board has bogus information written into the configuration EEPROM.\n\ The configuration table is for a Realtek chip, but this board is using\n\ a Winbond 89c940 chip. This misprogramming usually results in an invalid\n\ station address, and prevents the board from being detected by standard\n\ drivers.\n\ \n\ To reprogram the configuration EEPROM select a new station address such as\n\ 40:00:00:12:34:56 and run this diagnostic with the options\n\ --write-EEPROM --emergency-rewrite --new-hwaddr 40:00:00:12:34:56\n\ "; static void parse_winbond_eeprom(unsigned short *ee_data) { unsigned char *p = (void *)ee_data; int i; printf("Parsing the EEPROM of a Winbond PCI NE2000:\n"); printf(" Station Address "); for (i = 0; i < 5; i++) printf("%2.2X:", p[i]); printf("%2.2X (used as the ethernet address).\n", p[i]); printf(" PCI ID Vendor %#4.4x device %#4.4x revision %d.\n" " PCI maximum latency %d minimum grant %d.\n" " System control 0x%2.2x:\n" " %s transceiver, %s\n" " %s boot ROM", ee_data[9], ee_data[10], p[22], p[17], p[16], p[23], winbond_xcvr[p[23] & 3], p[23] & 8 ? "no link beat required" : "autoselect by link beat", winbond_rom[p[23]>>5]); if (ee_data[9] == 0x8c4a) printf("%s", winbond_bogus_msg); return; } static char unknown_eeprom_message[] = "\n\ No information is known about how to read or write the configuration\n\ EEPROM of this NIC board. It is likely that this NIC is using a common\n\ chip with a unique PCI ID. It may be possible to read the EEPROM by\n\ explicitly specifying the chip type and I/O address:\n\ ne2k-pci-diag -t 1 -p # For Realtek rtl8029 chip\n\ ne2k-pci-diag -t 2 -p # For Winbond 89C940 chip\n\ ne2k-pci-diag -t 3 -p # For Holtek HT80229 chip\n\ If one of these is required, please send a report to becker@scyld.com.\n\ "; static char no_rewrite_msg[] = "\n\ *** Emergency EEPROM rewrite is not yet available for this chip type.\n\ ** See the Scyld diagnostic web page for updates and more information.\n\ ** http://www.scyld.com/diag/index.html\n"; /* The examples below have 00:11:22:33:44:55 as the station address. */ static unsigned short winbond_default_eeprom[] = { 0x1100, 0x3322, 0x5544, 0x0000, 0x0000, 0x0000, 0x0000, 0x5757, 0x0000, 0x1050, 0x0940, 0x0000, }; static unsigned short via_default_eeprom[] = { 0x1100, 0x3322, 0x5544, 0x0000, /* [3] == checksum+boardID */ 0x0000, 0x0000, 0x0000, 0x0123, /* [7] = subvendor ID */ 0x5742, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xBBAA, 0x73CC}; /* Config AA BB and CC, 0x73 locks. */ /* Read, display, and possibly change the configuration EEPROM. */ static void do_ne2k_eeprom(long ioaddr, int part_idx) { int capabilities = pcidev_tbl[part_idx].flags; int ee_addr_len = 6; /* No known boards use a larger EEPROM. */ int i; /* Read the EEPROM. */ if (capabilities & (RTL_EE | HOLTEK_EE | WINBOND_EE)) { if (capabilities & (RTL_EE | WINBOND_EE)) outb(E8390_PAGE3, ioaddr + E8390_CMD); for (i = 0; i < EEPROM_SIZE; i++) eeprom_contents[i] = read_eeprom(capabilities, ioaddr, i, ee_addr_len); } else if (capabilities & VIA_EE) { /* This may not be true, but we don't have an unprogrammed board to confirm functionality. Contact me (becker@scyld.com) if you want to work with me to get the EEPROM operations working. */ printf("The VIA Amazon EEPROM is locked." " It cannot be read or updated.\n"); return; } else { if (show_eeprom) printf(unknown_eeprom_message); return; } if (emergency_rewrite && ! (capabilities & (WINBOND_EE))) fprintf(stderr, no_rewrite_msg); if (emergency_rewrite && ! set_hwaddr) fprintf(stderr, "*** Emergency EEPROM rewrite is only valid when you" " also specify a new\n" "*** station address with -H \n"); if (set_hwaddr) { int eeprom_sa_offset = capabilities & RTL_EE ? 1 : 0; const char *const field_names[] = { "MAC address 0/1", "MAC address 2/3", "MAC address 4/5", }; memcpy(new_ee_contents, eeprom_contents, sizeof(eeprom_contents)); if (emergency_rewrite) { if (capabilities & WINBOND_EE) memcpy(new_ee_contents, winbond_default_eeprom, sizeof winbond_default_eeprom); else if (capabilities & VIA_EE) memcpy(new_ee_contents, via_default_eeprom, sizeof via_default_eeprom); } for (i = 0; i < 3; i++) { new_ee_contents[i + eeprom_sa_offset] = new_hwaddr[i*2] + (new_hwaddr[i*2+1]<<8); } if (emergency_rewrite && (capabilities & (WINBOND_EE))) { printf("Writing new configuration EEPROM contents.\n"); for (i = 0; i < EEPROM_SIZE; i++) if (new_ee_contents[i] != eeprom_contents[i]) do_update(capabilities, ioaddr, i, ee_addr_len, "EEPROM", eeprom_contents[i], new_ee_contents[i]); } else { printf("Writing new MAC station address.\n"); for (i = eeprom_sa_offset; i < eeprom_sa_offset + 3; i++) if (new_ee_contents[i] != eeprom_contents[i]) do_update(capabilities, ioaddr, i, ee_addr_len, field_names[i - eeprom_sa_offset], eeprom_contents[i], new_ee_contents[i]); } /* Re-read all contents. */ for (i = 0; i < EEPROM_SIZE; i++) eeprom_contents[i] = read_eeprom(capabilities, ioaddr, i, ee_addr_len); } #if ! defined(ENABLE_EEPROM_UPDATE) if (new_default_media >= 0) { printf("This release of the diagnostic does not include the code to\n" "write the default transceiver setting.\n"); } #else if ((new_default_media & 0xff) > 4) { fprintf(stderr "Media type %s (index %d) is invalid for this " "board.\n", (new_default_media > 10) ? "" : mediamap[new_default_media & 31].name, new_default_media); } else if (new_default_media >= 0) { int offset = -1; int word; if (capability & WINBOND_EE) { offset = 12; word = eeprom_contents[offset] & ~0x0300; word |= (new_default_media & 3)<<8; } else if (capability & RTL_EE) { offset = 0; word = eeprom_contents[offset] & ~0x40C0; /* Full duplex:0x4000. 10base2:0x00C0 10base5:0x0080*/ word |= (new_default_media == 0) ? 0x00 : 0xC0; } else if (capability & HOLTEK_EE) { offset = 3; word = eeprom_contents[offset] & ~0x8f00; /* 0x0400 Link beat required, 0x0800 polarity correction. */ word |= (new_default_media == 0) ? 0x0C00 : 0x0E00; } do_update(capabilities, ioaddr, offset, ee_addr_len, "Transceiver setting", eeprom_contents[offset], word); } #endif if (show_eeprom) { int eeprom_words = EEPROM_SIZE; /* Really 2< 1 */ printf(" "); for (j = 0; j < 8; j++) { int ew = eeprom_contents[i + j]; printf("%c%c", isprint(ew & 0xff) ? ew & 0xff : '_', isprint(ew >> 8) ? ew >> 8 : '_' ); } } } for (i = 0; i < EEPROM_SIZE; i++) sum += eeprom_contents[i]; printf("\n The word-wide EEPROM checksum is %#4.4x.\n", sum); } /* The user will usually want to see the interpreted EEPROM contents. */ if (verbose || show_eeprom) { if (capabilities & RTL_EE) parse_8029_eeprom(eeprom_contents); else if (capabilities & HOLTEK_EE) parse_holtek_eeprom(eeprom_contents); else if (capabilities & WINBOND_EE) parse_winbond_eeprom(eeprom_contents); } return; } /* * Local variables: * compile-command: "cc -O -Wall -o ne2k-pci-diag ne2k-pci-diag.c" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 * End: */ nictools-pci-1.3.8.orig/ns820-diag.c0000644000175000017500000010406410264220744015745 0ustar alainalain/* ns820-diag.c: National Semiconductor DP83820 series diagnostic and setup. This is a diagnostic and EEPROM setup program for PCI adapters based on the National Semiconductor DP83820 series. Written 1998-2002 by Donald Becker. Copyright Donald Becker and Scyld Computing Corporation This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 Updates and additional information are available at http://www.scyld.com/diag/index.html http://scyld.com/expert/mii-status.html http://scyld.com/expert/NWay.html Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. To use this code under other terms requires an explicit license from the copyright holder. */ static char *version_msg = "ns820-diag.c:v2.05 2/28/2005 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: ns820-diag [-aEefFGhmqrRtTvVwW] [-p ] [-[AF] ]\n" " For details and other options see http://www.scyld.com/diag/index.html\n"; static const char long_usage_msg[] = "Usage: %s [-aDfrRvVw] [-AF ] [-#]\n\ \n\ Show the internal state of a network adapter.\n\ \n\ The common usage is\n\ ns820-diag -aem\n\ \n\ Frequently used options are\n\ -a --show_all_registers Print all registers.\n\ -e --show-eeprom Dump EEPROM contents, \"-ee\" shows the details.\n\ -m --show_mii Print the MII transceiver state\n\ Using -mm monitors the link.\n\ -f --force Perform operation, even on a running NIC.\n\ \n\ To operate on a single NIC, or one that hasn't been automatically found:\n\ -# --card_num INDEX Operate on the specified card index.\n\ -p --port-base IOADDR Assume an adapter at the specified I/O address.\n\ -t --chip-type TYPE Specify adapter type with '-p', use '-1' to list.\n\ \n\ To change the persistent EEPROM settings\n\ -G --parameters PARMS Set adapter-specific parameters.\n\ -H --new-hwaddr 01:23:45:67:ab:cd\n\ Set a new hardware station address. Typically diabled, \n\ -w --write-EEPROM Actually write the new settings into the EEPROM.\n\ \n\ -D --debug\n\ -v --verbose Report each action taken.\n\ -V --version Emit version information.\n\ \n\ -A --advertise (See the mii-diag manual page.)\n\ "; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include #include /* The following are required only with unaligned field accesses. */ #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif /* No libmii.h or libflash.h yet, thus the declarations here. */ extern int show_mii_details(long ioaddr, int phy_id); extern int monitor_mii(long ioaddr, int phy_id); extern int flash_show(long addr_ioaddr, long data_ioaddr); extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename); extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename); extern int (*flash_in_hook)(long addr, int offset); extern void (*flash_out_hook)(long addr, int offset, int val); /* We should use __u8 .. __u32, but they are not always defined. */ typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; struct option longopts[] = { /* { name has_arg *flag val } */ {"card-num", 1, 0, '#'}, /* Operate on the specified card index. */ {"Advertise", 1, 0, 'A'}, {"base-address", 1, 0, 'p'}, {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Print a long usage message. */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; extern int ns820_diag(int vend_id, int dev_id, long ioaddr, int part_idx); /* Chip-specific flags. Yes, it's grungy to have the enum here. */ /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name from the kernel, a common name and the PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { const char *part_name; const char *proc_pci_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx); } pcidev_tbl[] = { {"National Semiconductor DP83820 series", 0, 0x100B, 0x0022, 0xffff, 0, 256, ns820_diag}, { 0, 0, 0, 0}, }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int nway_advertise = 0, fixed_speed = -1; int new_default_media = -1; /* Valid with libflash only. */ static unsigned int opt_flash_show = 0; static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int emergency_rewrite = 0; static int scan_proc_pci(int card_num); static int parse_media_type(const char *capabilities); static int get_media_index(const char *name); /* Chip-specific options, if any, go here. */ int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:hH:mp:qrRt:TvVwWBL:S:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'A': nway_advertise = parse_media_type(optarg); break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 16); break; case 'h': fprintf(stderr, long_usage_msg, argv[0]); return 0; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtoul(optarg, NULL, 16); break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'T': do_test++; break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case 'W': opt_watch++; break; case 'B': opt_flash_show++; break; case 'L': opt_flash_loadfile = optarg; break; case 'S': opt_flash_dumpfile = optarg; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("Network adapter diagnostic: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for parsed contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n" " See http://www.scyld.com/expert/irq-conflict.html for more information.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if ((pci_devid >> 16) != pcidev_tbl[i].vendor || (pci_devid & pcidev_tbl[i].device_mask) != pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].part_name; i++) if (pcidev_tbl[i].proc_pci_name && strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Convert a text media name to a NWay capability word. */ static int parse_media_type(const char *capabilities) { const char *mtypes[] = { "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD", "10baseT", "10baseT-FD", "10baseT-HD", 0, }; char *endptr; int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,}; int i; if (debug) fprintf(stderr, "Advertise string is '%s'.\n", capabilities); for (i = 0; mtypes[i]; i++) if (strcasecmp(mtypes[i], capabilities) == 0) return cap_map[i]; i = strtoul(capabilities, &endptr, 16); if (*endptr == 0 && 0 < i && i <= 0xffff) return i; fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities); return 0; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to indices. This matches the Digital Tulip SROM numbering, primarily because that is the most complete list. Other chips will have to map these number to their internal values. */ struct { char *name; int value; } mediamap[] = { { "10baseT", 0 }, { "10base2", 1 }, { "AUI", 2 }, { "100baseTx", 3 }, { "10baseT-FDX", 0x204 }, { "100baseTx-FDX", 0x205 }, { "100baseT4", 6 }, { "100baseFx", 7 }, { "100baseFx-FDX", 8 }, { "MII", 11 }, { "Autosense", 0x0800 }, { 0, 0 }, }; static int get_media_index(const char *name) { char *endptr; int i; if (! name) return -1; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) return i; i = strtol(name, &endptr, 0); if (*endptr == 0) return i; fprintf(stderr, "Invalid interface specified. It must be one of\n"); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %d %s\n", mediamap[i].value, mediamap[i].name); return -1; } /* Chip-specific section. */ /* The chip-specific section for the dp83820 series. */ static int read_eeprom(long ioaddr, int location, int addr_len); static void write_eeprom(long ioaddr, int index, int value, int addr_len); int mdio_read(long ioaddr, int phy_id, int location); void mdio_write(long ioaddr, int phy_id, int location, int value); /* Offsets to the various registers. */ enum register_offsets { ChipCmd=0x00, ChipConfig=0x04, EECtrl=0x08, TestControl=0x0C, IntrStatus=0x10, IntrMask=0x14, IntrEnable=0x18, TxRingPtr=0x20, TxRingPtrHi=0x24, TxConfig=0x28, GeneralIO=0x2C, RxRingPtr=0x30, RxRingPtrHi=0x34, RxConfig=0x38, WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C, BootRomAddr=0x50, BootRomData=0x54, ChipRevReg=0x58, StatsCtrl=0x5C, RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64, }; /* Bits in the interrupt status/mask registers. */ enum intr_status_bits { IntrRxDone=0x0001, IntrRxIntr=0x0002, IntrRxErr=0x0004, IntrRxEarly=0x0008, IntrRxIdle=0x0010, IntrRxOverrun=0x0020, IntrTxDone=0x0040, IntrTxIntr=0x0080, IntrTxErr=0x0100, IntrTxIdle=0x0200, IntrTxUnderrun=0x0400, StatsMax=0x0800, LinkChange=0x4000, WOLPkt=0x2000, RxResetDone=0x1000000, TxResetDone=0x2000000, IntrPCIErr=0x00f00000, IntrNormalSummary=0x0251, IntrAbnormalSummary=0xED20, }; /* The textual names of the interrupt indications. */ static const char *intr_names[] ={ "Rx Done event", "Rx event", "Receive error", "Rx started", "Receiver idle", "Rx overrun", "Tx complete", "Tx packet in FIFO", "Transmit error", "Tx queue emptied", "Tx underrun", "Statistics counters full", "Driver software intr", "Wake-up packet", "Link change wakeup", "Error summary", "Rx status overrun", "PCI target abort", "PCI master abort", "PCI system error", "PCI parity error", "Receiver reset done", "Transmitter reset done", }; /* Values read from the EEPROM, and a new image to write. */ #define EEPROM_SIZE 256 unsigned short eeprom_contents[EEPROM_SIZE]; unsigned short new_ee_contents[EEPROM_SIZE]; #define EE_OFFSET EECtrl /* Register offset in I/O space. */ /* The EEPROM commands include the alway-set leading bit. */ enum EEPROM_Cmds { EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7, }; static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len); static void natsemi820_eeprom(unsigned short *ee_data); /* Support for Flash operations. */ static int natsemi_flash_in(long ioaddr, int offset) { outl(offset, ioaddr + BootRomAddr); return inl(ioaddr + BootRomData) & 0xff; } #ifdef LIBFLASH static void natsemi_flash_out(long ioaddr, int offset, int val) { outl(offset, ioaddr + BootRomAddr); outl(val, ioaddr + BootRomData); } #endif /* A table for emitting the configuration of a register. */ struct config_name { int val, mask; const char*name;}; static struct config_name rcvr_mode[] = { {0x00000000, 0x80000000, "Receive disabled"}, {0xf0000000, 0xf0000000, "Promiscuous"}, {0xe0000000, 0xf0100000, "Normal unicast and all multicast"}, {0xc0200000, 0xf0300000, "Normal unicast and hashed multicast"}, {0xc0000000, 0xf0300000, "Normal unicast and match filter"}, {0x00, 0x00, "Unknown/invalid"}, }; int ns820_diag(int vendor_id, int device_id, long ioaddr, int part_idx) { unsigned int chip_active = inl(ioaddr + IntrEnable); unsigned int rx_mode = inl(ioaddr + RxFilterAddr); int ee_addr_len = 6, eeprom_size = 64, eeprom_change = 0; int i; if (chip_active == 0xffffffff && !opt_f) { printf(" * A recognized chip has been found, but it does not " "appear to exist in\n * I/O space. Use the" " '-f' flag to see the register values anyway.\n"); return 1; } /* Always show the basic status. */ printf(" Natsemi 83820 series with station address "); for (i = 0; i < 6; i+=2) { unsigned short rf_data; outw(i, ioaddr + RxFilterAddr); rf_data = inl(ioaddr + RxFilterData); printf("%2.2x:%2.2x%c", rf_data & 0xff, (rf_data >> 8) & 0xff, i < 4 ? ':' : '\n'); } if (opt_G) { printf("Setting the configuration register to %8.8x.\n", opt_GPIO); outl(opt_GPIO, ioaddr + ChipConfig); } if (verbose > 1 || show_regs) { unsigned int intr_status = inl(ioaddr + IntrStatus); unsigned int tx_config = inl(ioaddr + TxConfig); char dont_read[8] = {0x10,0x00,0x01,0x00,0x00,0x00,0x00,0x00}; if (chip_active && !opt_f) { printf(" This device appears to be active, so some registers" " will not be read.\n" " To see all register values use the '-f' flag.\n"); } else chip_active = 0; /* Ignore the chip status with -f */ printf("%s chip registers at %#lx", pcidev_tbl[part_idx].part_name, ioaddr); for (i = 0; i < pcidev_tbl[part_idx].io_size; i += 4) { if ((i & 0x1f) == 0) printf("\n 0x%3.3X:", i); if (chip_active && (dont_read[i>>5]) & (1<<((i>>2) & 7))) printf(" ********"); else printf(" %8.8x", (int)inl(ioaddr + i)); } printf("\n"); if (intr_status == 0xffffffff && !opt_f) { printf(" * A recognized chip has been found, but it does not " "appear to exist in\n * I/O space. Use the" " '-f' flag to see the register values anyway.\n"); return 1; } printf(" %snterrupt sources are pending (%8.8x).\n", (intr_status & 0x03ff) ? "I": "No i", intr_status); if (intr_status) { for (i = 0; i < sizeof(intr_names)/sizeof(intr_names[0]); i++) if (intr_status & (1< 1) { printf(" Rx filter contents: "); for (i = 0; i < 16; i+=2) { outw(i, ioaddr + RxFilterAddr); printf(" %4.4x", (int)inl(ioaddr + RxFilterData)); } printf("\n"); } printf(" Tx threshold %d bytes, FIFO fill %d bytes.\n", (tx_config & 0xff) << 5, (tx_config & 0xff00) >> 3); } outl(rx_mode, ioaddr + RxFilterAddr); if (do_test && chip_active && !opt_f) printf(" Running these diagnostic test is not recommended while the " "device is active.\n" " To run them anyway, use the '-f' flag.\n"); else if (do_test) { int result; outl(0x0400, ioaddr + TestControl); for (i = 0; i < 10000; i++) { /* Typical 1050 iterations. */ if (inl(ioaddr + TestControl) & 0x0200) break; } result = inl(ioaddr + TestControl); if (debug) printf(" Internal SRAM test took %d ticks.\n", i); printf(" Internal SRAM test result is %4.4x: %s.\n", result, result & 0x01B8 ? "failed" : "passed"); if (result & 0x01B8) { if (result & 0x0100) fprintf(stderr, " *** Rx status FIFO test failed!\n"); if (result & 0x0080) fprintf(stderr, " *** Rx data FIFO test failed!\n"); if (result & 0x20) fprintf(stderr, " *** Tx data FIFO test failed!\n"); if (result & 0x0010) fprintf(stderr, " *** Rx multicast filter test failed!\n"); if (result & 0x0008) fprintf(stderr, " *** Rx match filter test failed!\n"); if ( ! opt_f) return 2; } outl(0x02, ioaddr + TestControl); for (i = 0; i < 10000; i++) { /* Typical 3350 iterations. */ if ( ! (inl(ioaddr + TestControl) & 0x02)) break; } result = inl(ioaddr + TestControl); if (debug) printf(" EEPROM internal test took %d ticks.\n", i); printf(" Configuration EEPROM checksum test result is %4.4x: %s.\n", result, result & 1 ? "failed" : "passed"); } if (set_hwaddr || show_eeprom || new_default_media >= 0) { ee_addr_len = do_eeprom_cmd(ioaddr, EE_ReadCmd << (6+16), 3 + 6 + 16) & 0x10000 ? 8 : 6; eeprom_size = 1 << ee_addr_len; printf(" EEPROM address length %d, %d words.\n", ee_addr_len, eeprom_size); for (i = 0; i < eeprom_size; i++) eeprom_contents[i] = read_eeprom(ioaddr, i, ee_addr_len); memcpy(new_ee_contents, eeprom_contents, sizeof eeprom_contents); } if (emergency_rewrite && ! set_hwaddr) printf("*** Emergency EEPROM rewrite is only valid when you also " "specify a new\n*** station address with -H \n"); if (set_hwaddr) { u16 backup_ee_contents[] = { 0x4900, 0x1186, 0x340b, 0x0200, 0x0000, 0x00b4, 0x0000, 0x0000, 0x0000, 0x24a7, 0x37ba, 0x5000, }; if (emergency_rewrite) memcpy(new_ee_contents, backup_ee_contents, sizeof backup_ee_contents); /* NatSemi corrected the endian mix-up and dropped bits of the earlier series. */ new_ee_contents[12] = new_hwaddr[0] + (new_hwaddr[1]<<8); new_ee_contents[11] = new_hwaddr[2] + (new_hwaddr[3]<<8); new_ee_contents[10] = new_hwaddr[4] + (new_hwaddr[5]<<8); eeprom_change++; } if (eeprom_change) { int sum = 0x55; /* Calculate the new checksum. */ for (i = 0; i < 13; i++) sum += new_ee_contents[i] + (new_ee_contents[i]>>8); new_ee_contents[13] = ((-sum & 0xff) << 8) | 0x0055; for (i = 0; i < 16; i++) if (new_ee_contents[i] != eeprom_contents[i]) { if (do_write_eeprom) write_eeprom(ioaddr, i, new_ee_contents[i], ee_addr_len); else printf("Would write %4.4x to replace %4.4x at %d.\n", new_ee_contents[i], eeprom_contents[i], i); } } if (show_eeprom > 1) { printf("EEPROM contents (%d words):", eeprom_size); for (i = 0; i < eeprom_size; i += 8) { int j; printf("\n0x%2.2x: ", i); for (j = 0; j < 8; j++) printf(" %4.4x", eeprom_contents[i + j]); if (show_eeprom > 2) { printf(" "); for (j = 0; j < 8; j++) { int ew = eeprom_contents[i + j]; printf("%c%c", isprint(ew & 0xff) ? ew & 0xff : '_', isprint(ew >> 8) ? ew >> 8 : '_' ); } } } printf("\n"); } if (show_eeprom) natsemi820_eeprom(eeprom_contents); if (show_mii > 1) { int phys[4], phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(ioaddr, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { phys[phy_idx++] = phy; printf(" MII PHY found at address %d, status 0x%4.4x.\n", phy, mii_status); } } if (phy_idx == 0) printf(" ***WARNING***: No MII transceivers found!\n"); for (phy = 0; phy < phy_idx; phy++) { int mii_reg; printf(" MII PHY #%d transceiver registers:", phys[phy]); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mdio_read(ioaddr, phys[phy], mii_reg)); printf(".\n"); } #ifdef LIBMII show_mii_details(ioaddr, phys[0]); if (show_mii > 1) monitor_mii(ioaddr, phys[0]); #endif } else if (show_mii) { int mii_reg; for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mdio_read(ioaddr, 1, mii_reg)); printf(".\n"); #ifdef LIBMII show_mii_details(ioaddr, 1); #endif } printf(" General purpose I/O register is %8.8x.\n", inl(ioaddr + GeneralIO)); #ifdef LIBFLASH { flash_in_hook = natsemi_flash_in; flash_out_hook = natsemi_flash_out; if (opt_flash_show) flash_show(ioaddr, 0); if (opt_flash_dumpfile) if (flash_dump(ioaddr, 0, opt_flash_dumpfile) < 0) { fprintf(stderr, "Failed to save the old Flash BootROM image " "into file '%s'.\n", opt_flash_dumpfile); return 3; } if (opt_flash_loadfile) if (flash_program(ioaddr, 0, opt_flash_loadfile) < 0) { fprintf(stderr, "Failed to load the new Flash BootROM image " "from file '%s'.\n", opt_flash_loadfile); return 4; } } #else if (opt_flash_loadfile || opt_flash_dumpfile || opt_flash_show) printf("Flash operations not configured into this program.\n"); if (opt_flash_show) { printf("The first few boot ROM bytes are:"); for (i = 0; i < 8; i++) printf(" %2.2x", natsemi_flash_in(ioaddr, i)); printf(".\n"); } #endif return 0; } static void natsemi820_eeprom(unsigned short *ee_data) { int i, sum = 0x55; printf("Decoded EEPROM contents:\n" " PCI Subsystem IDs -- Vendor %#4.4x, Device %#4.4x.\n" " PCI timer settings -- minimum grant %d, maximum latency %d.\n", ee_data[1], ee_data[0], ee_data[2] & 0xff, ee_data[2] >> 8); printf(" Wake-On-LAN password " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", ee_data[9] & 0xff, ee_data[9]>>8, ee_data[8] & 0xff, ee_data[8]>>8, ee_data[7] & 0xff, ee_data[7]>>8); printf(" Ethernet MAC Station Address " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", ee_data[12] & 0xff, ee_data[12]>>8, ee_data[11] & 0xff, ee_data[11]>>8, ee_data[10] & 0xff, ee_data[10]>>8); printf(" General Purpose I/O register %4.4x.\n", ee_data[4]); for (i = 0; i < 13; i++) sum += ee_data[i] + (ee_data[i]>>8); sum = -sum & 0xff; printf(" EEPROM active region checksum read as %4.4x, vs %2.2x55 " "calculated value.\n", ee_data[13], sum); return; } /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses. */ /* Delay between EEPROM clock transitions. This flushes the write buffer to prevent quick double-writes. */ #define eeprom_delay(ee_addr) inl(ee_addr); inl(ee_addr) enum EEPROM_Ctrl_Bits { EE_ShiftClk=0x04, EE_DataIn=0x01, EE_ChipSelect=0x08, EE_DataOut=0x02, }; #define EE_Write0 (EE_ChipSelect) #define EE_Write1 (EE_ChipSelect | EE_DataIn) /* Execute a generic EEPROM command. Return all data output from the EEPROM, and thus may be used for EEPROM sizing, read, erase or write. */ static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len) { unsigned retval = 0; long ee_addr = ioaddr + EE_OFFSET; if (debug > 1) printf(" EEPROM op 0x%x: ", cmd); outl(EE_ChipSelect | EE_ShiftClk, ee_addr); /* Shift the command bits out. */ do { short dataval = (cmd & (1 << cmd_len)) ? EE_Write1 : EE_Write0; outl(dataval, ee_addr); eeprom_delay(ee_addr); if (debug > 2) printf("%X", inl(ee_addr) & 15); outl(dataval | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); retval = (retval << 1) | ((inl(ee_addr) & EE_DataOut) ? 1 : 0); } while (--cmd_len >= 0); outl(EE_ChipSelect, ee_addr); /* Terminate the EEPROM access. */ outl(0, ee_addr); if (debug > 1) printf(" EEPROM result is 0x%5.5x.\n", retval); return retval; } /* Wait for the EEPROM to finish what it is doing. */ static int eeprom_busy_poll(long ee_ioaddr) { int i; outl(EE_ChipSelect, ee_ioaddr); for (i = 0; i < 10000; i++) /* Typical 2000 ticks */ if (inl(ee_ioaddr) & EE_DataOut) break; return i; } /* The abstracted functions for EEPROM access. */ static int read_eeprom(long ioaddr, int location, int addr_len) { return do_eeprom_cmd(ioaddr, ((EE_ReadCmd << addr_len) | location) << 16, 3 + addr_len + 16) & 0xffff; } static void write_eeprom(long ioaddr, int index, int value, int addr_len) { long ee_ioaddr = ioaddr + EE_OFFSET; int i; /* Poll for previous op finished. */ eeprom_busy_poll(ee_ioaddr); /* Enable programming modes. */ do_eeprom_cmd(ioaddr, (0x4f << (addr_len-4)), 3 + addr_len); /* Do the actual write. */ do_eeprom_cmd(ioaddr, (((EE_WriteCmd<= 0; i--) { mdio_out(MDIO_ENB | MDIO_WRITE1, mdio_addr); mdio_delay(mdio_addr); mdio_out(MDIO_ENB | MDIO_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(mdio_addr); } return; } int mdio_read(long ioaddr, int phy_id, int location) { long mdio_addr = ioaddr + MDIO_IO_OFFSET; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int i, retval = 0; if (verbose > 2) /* Debug: 5 */ printf(" mdio_read(%#lx, %d, %d)..", ioaddr, phy_id, location); /* Establish sync by sending at least 32 logic ones. */ mdio_sync(ioaddr); /* Shift the read command bits out. */ for (i = 17; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; if (verbose > 3) /* Debug: 5 */ printf("%d", (mii_cmd & (1 << i)) ? 1 : 0); mdio_out(MDIO_ENB | dataval, mdio_addr); mdio_delay(mdio_addr); mdio_out(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); if (verbose > 3) printf(" %x", (mdio_in(mdio_addr) >> 16) & 0x0f); mdio_delay(mdio_addr); } if (verbose > 3) printf("-> %x", (mdio_in(mdio_addr) >> 16) & 0x0f); /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { mdio_out(MDIO_ENB_IN, mdio_addr); mdio_delay(mdio_addr); retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); if (verbose > 3) printf(" %x", (mdio_in(mdio_addr) >> 16) & 0x0f); mdio_out(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(mdio_addr); } if (verbose > 3) printf(" == %4.4x.\n", retval); return (retval>>1) & 0xffff; } void mdio_write(long ioaddr, int phy_id, int location, int value) { long mdio_addr = ioaddr + MDIO_IO_OFFSET; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; int i; /* Establish sync by sending 32 logic ones. */ mdio_sync(ioaddr); /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; mdio_out(MDIO_ENB | dataval, mdio_addr); mdio_delay(mdio_addr); mdio_out(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(mdio_addr); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { mdio_out(MDIO_ENB_IN, mdio_addr); mdio_delay(mdio_addr); mdio_out(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(mdio_addr); } return; } /* * Local variables: * compile-command: "cc -O -Wall -Wstrict-prototypes -o ns820-diag ns820-diag.c `[ -f libmii.c ] && echo -DLIBMII libmii.c` `[ -f libmii.c ] && echo -DLIBFLASH libflash.c`" * simple-compile-command: "cc -O -Wall -o ns820-diag ns820-diag.c" * tab-width: 4 * c-indent-level: 4 * c-basic-offset: 4 * End: */ nictools-pci-1.3.8.orig/pcnet-diag.c0000644000175000017500000005617210264221322016203 0ustar alainalain/* pcnet-diag.c: Diagnostic and setup for AMD PCnet/PCI ethercards. This is a diagnostic and EEPROM setup program for the Ethernet adapters based on the AMD PCnet/PCI series chips. Note: The EEPROM setup code is not implemented. Copyright 1998-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 Updates and additional information are available at http://www.scyld.com/diag/index.html http://scyld.com/expert/mii-status.html http://scyld.com/expert/NWay.html Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. To use this code under other terms requires an explicit license from the copyright holder. */ static char *version_msg = "pcnet-diag.c:v2.03 2/28/2005 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: pcnet-diag [-aDEefFGhmqrRtvVwW] [-p ] [-[AF] ]\n" " For details and other options see http://www.scyld.com/diag/index.html\n"; static const char long_usage_msg[] = "Usage: %s [-aDfrRvVw] [-AF ] [-#]\n\ \n\ Show the internal state of a network adapter.\n\ \n\ The common usage is\n\ diag -aem\n\ \n\ Frequently used options are\n\ -a --show_all_registers Print all registers.\n\ -e --show-eeprom Dump EEPROM contents, \"-ee\" shows the details.\n\ -m --show_mii Print the MII transceiver state\n\ Using -mm monitors the link.\n\ -f --force Perform operation, even on a running NIC.\n\ \n\ To operate on a single NIC, or one that hasn't been automatically found:\n\ -# --card_num INDEX Operate on the specified card index.\n\ -p --port-base IOADDR Assume an adapter at the specified I/O address.\n\ -t --chip-type TYPE Specify adapter type (with '-p'). Use '-1' to\n\ list available types indicies.\n\ \n\ To change the persistent EEPROM settings\n\ -F, --new-interface N Set the default transceiver type.\n\ -G --parameters PARMS Set adapter-specific parameters.\n\ -H --new-hwaddr 01:23:45:67:89:ab\n\ Set a new hardware station address. Typically disabled for safety.\n\ -w --write-EEPROM Actually write the new settings into the EEPROM.\n\ To read and write the boot BIOS extension Flash ROM\n\ -B Show the first few bytes of the ROM\n\ -L FILE Load the Flash from FILE.\n\ -S FILE Store the Flash image to FILE.\n\ \n\ -D --debug\n\ -v --verbose Report each action taken.\n\ -V --version Emit version information.\n\ \n\ -A --advertise (See the mii-diag manual page.)\n\ \n"; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include #else #include #endif /* No libmii.h or libflash.h yet, thus the declarations here. */ extern int show_mii_details(long ioaddr, int phy_id); extern int monitor_mii(long ioaddr, int phy_id); extern int flash_show(long addr_ioaddr, long data_ioaddr); extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename); extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename); extern int (*flash_in_hook)(long addr, int offset); extern void (*flash_out_hook)(long addr, int offset, int val); /* We should use __u8 .. __u32, but they are not always defined. */ typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; struct option longopts[] = { /* { name has_arg *flag val } */ {"card-num", 1, 0, '#'}, /* Operate on the specified card index. */ {"Advertise", 1, 0, 'A'}, {"base-address", 1, 0, 'p'}, {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Print a long usage message. */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; extern int pcnet_diag(int vendor_id, int device_id, long ioaddr, int part_idx); enum pcnet_flags { PCNET_HAS_MII }; /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name from the kernel, a common name and the PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { const char *part_name; const char *proc_pci_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx); } pcidev_tbl[] = { { "AMD PCnet-PCI 79c970", "AMD 79C970", 0x1022, 0x2000, 0xffff, 0, 32, pcnet_diag }, { "AMD PCnet-Home 79c978 Homenet", 0, 0x1022, 0x2001, 0xffff, 0, 32, pcnet_diag }, { "AMD PCnet/PCI series", "AMD PCnet32, unknown type", 0x1022, 0x0000, 0, 0, 32, pcnet_diag }, { 0, 0, 0, 0}, }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int nway_advertise = 0, fixed_speed = -1; int new_default_media = -1; /* Valid with libflash only. */ static unsigned int opt_flash_show = 0; static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int emergency_rewrite = 0; static int scan_proc_pci(int card_num); static int parse_media_type(const char *capabilities); static int get_media_index(const char *name); int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:hH:mp:qrRst:vVwWBL:S:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'A': nway_advertise = parse_media_type(optarg); break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 16); break; case 'h': fprintf(stderr, long_usage_msg, argv[0]); return 0; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtoul(optarg, NULL, 16); break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case 'W': opt_watch++; break; case 'B': opt_flash_show++; break; case 'L': opt_flash_loadfile = optarg; break; case 'S': opt_flash_dumpfile = optarg; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("Network adapter diagnostic: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for numeric contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n" " See http://www.scyld.com/expert/irq-conflict.html for more information.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if ((pci_devid >> 16) != pcidev_tbl[i].vendor || (pci_devid & pcidev_tbl[i].device_mask) != pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].part_name; i++) if (pcidev_tbl[i].proc_pci_name && strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Convert a text media name to a NWay capability word. */ static int parse_media_type(const char *capabilities) { const char *mtypes[] = { "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD", "10baseT", "10baseT-FD", "10baseT-HD", 0, }; char *endptr; int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,}; int i; if (debug) fprintf(stderr, "Advertise string is '%s'.\n", capabilities); for (i = 0; mtypes[i]; i++) if (strcasecmp(mtypes[i], capabilities) == 0) return cap_map[i]; i = strtoul(capabilities, &endptr, 16); if (*endptr == 0 && 0 < i && i <= 0xffff) return i; fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities); return 0; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to indices. This matches the Digital Tulip SROM numbering, primarily because that is the most complete list. Other chips will have to map these number to their internal values. */ struct { char *name; int value; } mediamap[] = { { "10baseT", 0 }, { "10base2", 1 }, { "AUI", 2 }, { "100baseTx", 3 }, { "10baseT-FDX", 0x204 }, { "100baseTx-FDX", 0x205 }, { "100baseT4", 6 }, { "100baseFx", 7 }, { "100baseFx-FDX", 8 }, { "MII", 11 }, { "HomePNA", 18 }, { "Autosense", 0x0800 }, { 0, 0 }, }; static int get_media_index(const char *name) { char *endptr; int i; if (! name) return -1; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) return i; i = strtol(name, &endptr, 0); if (*endptr == 0) return i; fprintf(stderr, "Invalid interface specified. It must be one of\n"); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %d %s\n", mediamap[i].value, mediamap[i].name); return -1; } struct mdio_ops { void (*mdio_sync_func)(long ioaddr); int (*mdio_read_func)(long ioaddr, int phy_id, int location); void (*mdio_write_func)(long ioaddr, int phy_id, int location, int value); } mdio_ops = {0, 0}; void mdio_sync(long ioaddr) { if (mdio_ops.mdio_sync_func) mdio_ops.mdio_sync_func(ioaddr); } int mdio_read(long ioaddr, int phy_id, int location) { if (mdio_ops.mdio_read_func) return mdio_ops.mdio_read_func(ioaddr, phy_id, location); return 0; } void mdio_write(long ioaddr, int phy_id, int location, int value) { if (mdio_ops.mdio_write_func) mdio_ops.mdio_write_func(ioaddr, phy_id, location, value); } /* Chip-specific section. */ /* AMD names for the chip registers, using 32 bit mode. */ enum pcnet_offsets { AROM=0, RDP=0x10, RAP=0x14, PCnetReset=0x18, BDP=0x1C, }; /* PCnet/PCI Chip-specific section. */ static const char *pcnet_intr_names[16] ={ "Initialized", "Started", "Stopped", "Tx busy", "Tx enabled", "Rx enabled", "Intr enable", "Interrupt flag", "Initialization done", "Tx done", "Rx done", "Memory error", "Rx Missed Frame", "Collision error", "unknown-0x4000", "Error summary", }; static const char *pcnet_xcvrs[4] = { "10baseT", "HomePNA", "External MII", "undefined" }; static int pcnet_mdio_read(long ioaddr, int phy_id, int location); static void pcnet_mdio_write(long ioaddr, int phy_id, int location, int value); static int pcnet_read_eeprom(long ioaddr, int location); int pcnet_diag(int vendor_id, int device_id, long ioaddr, int part_idx) { u32 saved_RAP = inl(ioaddr + RAP); u8 mac_addr[8]; int i; /* Note: this chip only works on little-endian anyway. */ ((u32*)mac_addr)[0] = inl(ioaddr + AROM); ((u32*)mac_addr)[1] = inl(ioaddr + AROM + 4); printf(" Station MAC address is %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); if (show_regs) { int num_regs = pcidev_tbl[part_idx].io_size; u32 csr0; /* Assume the chip is in 32 bit mode, but assert just in case. */ outl(0, ioaddr + RAP); outl(0, ioaddr + RDP); csr0 = inl(ioaddr + RDP); printf("The chip is %s.\n" "The transmitter is %s%s, the receiver is %s.\n", csr0&4 ? "stopped" : csr0&2 ? "started" : csr0&1 ? ", initialization has completed" : "initializing(?)", csr0&0x10 ? "running":"stopped", csr0&8 ? " (busy)":"", csr0&0x20 ? "running":"stopped"); if (csr0 & 0x0080) { printf("Interrupt sources are pending!\n"); for (i = 0; i < 15; i++) if (csr0 & (1< 1) { printf("%s chip registers at %#lx:", pcidev_tbl[part_idx].part_name, ioaddr); for (i = 0; i < num_regs; i += 4) printf("%s %8.8x", (i % 32) == 0 ? "\n " : "", inl(ioaddr + i)); printf("\n"); printf(" Control and Status Registers:"); for (i = 0; i < 128; i ++) { outl(i, ioaddr + RAP); printf("%s %8.8x", (i % 8) == 0 ? "\n " : "", inl(ioaddr + RDP)); } printf("\nBus Configuration Registers:"); for (i = 0; i < 64; i ++) { outl(i, ioaddr + RAP); printf("%s %4.4x", (i % 8) == 0 ? "\n " : "", inl(ioaddr + BDP) & 0xffff); } printf("\n"); } } if (show_eeprom) { u16 eeprom_contents[64]; u8 checksum = 1; printf("EEPROM contents:"); for (i = 0; i < 64; i++) printf("%s %4.4x", (i & 7) == 0 ? "\n ":"", eeprom_contents[i] = pcnet_read_eeprom(ioaddr, i)); for (i = 0; i < 82; i++) checksum += ((u8*)eeprom_contents)[i]; printf("\nEEPROM checksum is %2.2x (%s).\n", checksum, checksum ? "INCORRECT" : "correct"); } if (show_mii) { int phys[4], phy, phy_idx = 0; mdio_ops.mdio_read_func = pcnet_mdio_read; mdio_ops.mdio_write_func = pcnet_mdio_write; mdio_sync(ioaddr); for (phy = 0; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(ioaddr, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { phys[phy_idx++] = phy; printf(" MII PHY found at address %d, status 0x%4.4x.\n", phy, mii_status); } } if (phy_idx) { if (nway_advertise > 0) { printf(" Setting the media capability advertisement register" " of PHY #%d to 0x%4.4x.\n", phys[0], nway_advertise | 1); mdio_write(ioaddr, phys[0], 4, nway_advertise | 1); } if (opt_restart) { printf("Restarting negotiation...\n"); mdio_write(ioaddr, phys[0], 0, 0x0000); mdio_write(ioaddr, phys[0], 0, 0x1200); } } if (phy_idx == 0) printf(" ***WARNING***: No MII transceivers found!\n"); #ifdef LIBMII else { if (show_mii > 1) show_mii_details(ioaddr, phys[0]); if (opt_watch || show_mii > 2) monitor_mii(ioaddr, phys[0]); } #else else for (phy = 0; phy < phy_idx; phy++) { int mii_reg; printf(" MII PHY #%d transceiver registers:", phys[phy]); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mdio_read(ioaddr, phys[phy], mii_reg)); printf(".\n"); } #endif } outl(saved_RAP, ioaddr + RAP); return 0; } /* MII management register interaction is trivial on the PCnet. */ static int pcnet_mdio_read(long ioaddr, int phy_id, int location) { outl(33, ioaddr + RAP); outl((phy_id<<5) + location, ioaddr + BDP); outl(34, ioaddr + RAP); return inl(ioaddr + BDP) & 0xffff; } static void pcnet_mdio_write(long ioaddr, int phy_id, int location, int value) { outl(33, ioaddr + RAP); outl((phy_id<<5) + location, ioaddr + BDP); outl(34, ioaddr + RAP); outl(value, ioaddr + BDP); return; } /* The PCnet has a typical software-serial EEPROM interface. */ #define eeprom_delay() inl(ee_addr) /* EEPROM_Ctrl bits. */ #define EE_DATA_READ 0x01 /* Data bit to/from EEPROM. */ #define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ #define EE_CS 0x04 /* EEPROM chip select. */ #define EE_WRITE_0 0x14 #define EE_WRITE_1 0x15 #define EE_ENB (0x10 | EE_CS) /* The EEPROM commands include the alway-set leading bit. */ #define EE_ADDR_SZ 6 #define EE_WRITE_CMD (5<= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_WRITE_1 : EE_WRITE_0; outl(dataval, ee_addr); eeprom_delay(); outl(dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(); } outl(EE_ENB, ee_addr); for (i = 16; i > 0; i--) { outl(EE_ENB | EE_SHIFT_CLK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); outl(EE_ENB, ee_addr); eeprom_delay(); } /* Terminate the EEPROM access. */ outl(EE_ENB & ~EE_CS, ee_addr); if (debug > 2) printf(" EEPROM value at %d is %5.5x.\n", location, retval); return retval; } /* * Local variables: * compile-command: "cc -O -Wall -Wstrict-prototypes -o pcnet-diag pcnet-diag.c `[ -f libmii.c ] && echo -DLIBMII libmii.c`" * simple-compile-command: "cc -O -o pcnet-diag pcnet-diag.c" * tab-width: 4 * c-indent-level: 4 * c-basic-offset: 4 * End: */ nictools-pci-1.3.8.orig/rtl8139-diag.c0000644000175000017500000011622510440246366016227 0ustar alainalain/* rtl8139-diag.c: Diagnostics/EEPROM setup for RealTek RTL8129/8139 chips. This is a diagnostic and EEPROM setup program for Ethernet adapters based on the RealTek RTL8129 and RTL8139 chips. Copyright 1998-2003 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 References http://www.scyld.com/diag/index.html http://www.realtek.com.tw/cn/cn.html http://scyld.com/expert/mii-status.html http://scyld.com/expert/NWay.html Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. To use this code under other terms requires an explicit license from the copyright holder. */ static char *version_msg = "rtl8139-diag.c:v2.13 2/28/2005 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: rtl8139-diag [-aDEefFGhmqrRtvVwW] [-p ] [-[AF] ]\n" " For details and other options see http://www.scyld.com/diag/index.html\n"; static const char long_usage_msg[] = "Usage: %s [-aDfrRvVw] [-AF ] [-#]\n" "\n" " Show the internal state of a network adapter.\n" "\n" " The common usage is\n" " rtl8139-diag -aem\n" "\n" " Frequently used options are\n" " -a --show_all_registers Print all registers.\n" " -e --show-eeprom Dump EEPROM contents, \"-ee\" shows the details.\n" " -m --show_mii Print the MII transceiver state\n" " Using -mm monitors the link.\n" " -f --force Perform operation, even on a running NIC.\n" "\n" " To operate on a single NIC, or one that hasn't been automatically found:\n" " -# --card_num INDEX Operate on the specified card index.\n" " -p --port-base IOADDR Assume an adapter at the specified I/O address.\n" " -t --chip-type TYPE Specify adapter type with '-p', use '-1' to list.\n" "\n" " To change the persistent EEPROM settings\n" " -G --parameters PARMS Set adapter-specific parameters.\n" " -H --new-hwaddr 01:23:45:67:89:ab\n" " Set a new hardware station address. Typically disabled for safety.\n" " -w --write-EEPROM Actually write the new settings into the EEPROM.\n" " To read and write the boot BIOS extension Flash ROM\n" " -B Show the first few bytes of the ROM\n" " -L FILE Load the Flash from FILE.\n" " -S FILE Store the Flash image to FILE.\n" "\n" " -D --debug\n" " -v --verbose Report each action taken.\n" " -V --version Emit version information.\n" "\n" " -A --advertise (See the mii-diag manual page.)\n" "\n"; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif /* No libmii.h or libflash.h yet, thus the declarations here. */ extern int show_mii_details(long ioaddr, int phy_id); extern int monitor_mii(long ioaddr, int phy_id); extern int flash_show(long addr_ioaddr, long data_ioaddr); extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename); extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename); extern int (*flash_in_hook)(long addr, int offset); extern void (*flash_out_hook)(long addr, int offset, int val); /* We should use __u8 .. __u32, but they are not always defined. */ typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; struct option longopts[] = { /* { name has_arg *flag val } */ {"card-num", 1, 0, '#'}, /* Operate on the specified card index. */ {"Advertise", 1, 0, 'A'}, {"base-address", 1, 0, 'p'}, {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Print a long usage message. */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"restart", 0, 0, 'r'}, /* Restart autonegotiation. */ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; /* The diagnostic functions supported. */ extern int rtl81x9_diag(int vend_id, int dev_id, long ioaddr, int part_idx); enum realtek_flags { HasMII=1, }; /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name and a PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { const char *part_name; const char *proc_pci_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx); } pcidev_tbl[] = { { "Realtek 8129", 0, 0x10ec, 0x8129, 0xffff, HasMII, 128, rtl81x9_diag }, { "RealTek RTL8139", 0, 0x10ec, 0x8139, 0xffff, 0, 128, rtl81x9_diag }, { "SMC1211TX EZCard 10/100 (RealTek RTL8139)", 0, 0x1113, 0x1211, 0xffff, 0, 128, rtl81x9_diag}, { "Accton MPX5030 (RealTek RTL8139)", 0, 0x1113, 0x1211, 0xffff, 0, 128, rtl81x9_diag }, { "D-Link DFE-530TX+ (RealTek RTL8139C)", 0, 0x1186, 0x1300, 0xffff, 0, 256, rtl81x9_diag }, { "D-Link DFE-690TXD CardBus (RealTek RTL8139C)", 0, 0x1186, 0x1340, 0xffff, 0, 256, rtl81x9_diag }, { "D-Link NIC (Unknown type, assuming realtek RTL8139C)", 0, 0x1186, 0x1300, 0xff00, 0, 256, rtl81x9_diag }, { "RealTek (unknown chip type)", 0, 0x10ec, 0x8100, 0xff00, 0, 128, rtl81x9_diag }, { "LevelOne FPC-0106Tx (RTL8139C)", 0, 0x018a, 0x1060, 0xffff, 0, 128, rtl81x9_diag }, { "Compaq HNE-300 (RTL8139C)", 0, 0x021b, 0x8139, 0xffff, 0, 128, rtl81x9_diag }, { "Edimax EP-4103DL CardBus (RTL8139C)", 0, 0x13d1, 0xab06, 0xffff, 0, 128, rtl81x9_diag }, { "Siemens SpeedStream 1012v2 CardBus (RTL8139C)", 0, 0x02ac, 0x1012, 0xffff, 0, 128, rtl81x9_diag }, { "Siemens SpeedStream 1020 (RTL8139C)", 0, 0x1432, 0x9130, 0xffff, 0, 128, rtl81x9_diag }, { 0, 0, 0, 0}, }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int nway_advertise = 0, fixed_speed = -1; int new_default_media = -1; /* Valid with libflash only. */ static unsigned int opt_flash_show = 0; static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int emergency_rewrite = 0; static int scan_proc_pci(int card_num); static int parse_media_type(const char *capabilities); static int get_media_index(const char *name); int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:hH:mp:qrRt:vVwWBL:S:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'A': nway_advertise = parse_media_type(optarg); break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 16); break; case 'h': fprintf(stderr, long_usage_msg, argv[0]); return 0; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtoul(optarg, NULL, 16); break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case 'W': opt_watch++; break; case 'B': opt_flash_show++; break; case 'L': opt_flash_loadfile = optarg; break; case 'S': opt_flash_dumpfile = optarg; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("rtl8139-diag: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for parsed contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n" " See http://www.scyld.com/expert/irq-conflict.html for more information.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if ((pci_devid >> 16) != pcidev_tbl[i].vendor || (pci_devid & pcidev_tbl[i].device_mask) != pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].part_name; i++) if (pcidev_tbl[i].proc_pci_name && strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Convert a text media name to a NWay capability word. */ static int parse_media_type(const char *capabilities) { const char *mtypes[] = { "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD", "10baseT", "10baseT-FD", "10baseT-HD", 0, }; char *endptr; int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,}; int i; if (debug) fprintf(stderr, "Advertise string is '%s'.\n", capabilities); for (i = 0; mtypes[i]; i++) if (strcasecmp(mtypes[i], capabilities) == 0) return cap_map[i]; i = strtoul(capabilities, &endptr, 16); if (*endptr == 0 && 0 < i && i <= 0xffff) return i; fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities); return 0; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to indices. This matches the Digital Tulip SROM numbering, primarily because that is the most complete list. Other chips will have to map these number to their internal values. */ struct { char *name; int value; } mediamap[] = { { "10baseT", 0 }, { "10base2", 1 }, { "AUI", 2 }, { "100baseTx", 3 }, { "10baseT-FDX", 0x204 }, { "100baseTx-FDX", 0x205 }, { "100baseT4", 6 }, { "100baseFx", 7 }, { "100baseFx-FDX", 8 }, { "MII", 11 }, { "Autosense", 0x0800 }, { 0, 0 }, }; static int get_media_index(const char *name) { char *endptr; int i; if (! name) return -1; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) return i; i = strtol(name, &endptr, 0); if (*endptr == 0) return i; fprintf(stderr, "Invalid interface specified. It must be one of\n"); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %d %s\n", mediamap[i].value, mediamap[i].name); return -1; } /* Chip-specific section. */ /* The chip-specific section for the RealTek 8129/8139 diagnostic. */ static int eeprom_addr_len(long ioaddr); static int read_eeprom(long ioaddr, int location, int addr_len); static void write_eeprom(long ioaddr, int index, int value, int addr_len); #if defined(ENABLE_EEWRITE) static int do_update(long ioaddr, unsigned short *ee_values, int index, char *field_name, int new_value, int ee_addr_len); #endif static void mdio_sync(long ioaddr); int mdio_read(long ioaddr, int phy_id, int location); const char *intr_names[16] ={ "Rx Complete", "Rx Error", "Transmit OK", "Transmit Error", "Rx Buffer Overflow", "Rx Buffer Underrun", "Rx FIFO Overflow", "unknown-0080", "unknown-0100", "unknown-0200", "PCS timeout - packet too long", "PCI System Error", }; /* Symbolic offsets to registers. */ enum RTL8129_registers { MAC0=0, /* Ethernet hardware address. */ MAR0=8, /* Multicast filter. */ TxStat0=0x10, /* Transmit status (Four 32bit registers). */ TxAddr0=0x20, /* Tx descriptors (also four 32bit). */ RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36, ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A, IntrMask=0x3C, IntrStatus=0x3E, TxConfig=0x40, RxConfig=0x44, /* Must enable Tx/Rx before writing. */ Timer=0x48, /* A general-purpose counter. */ RxMissed=0x4C, /* 24 bits valid, write clears. */ Cfg9346=0x50, Config0=0x51, Config1=0x52, FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B, MultiIntr=0x5C, TxSummary=0x60, MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68, NWayExpansion=0x6A, FlashAccess=0xD4, }; /* Utility functions for showing register states. */ /* Table formats. Tables are zero terminated. */ struct bits_to_name { int bits; const char *msg; }; struct bitfield_to_name { int val, mask; const char *msg;}; /* Use MSG_TBL to describe the bits set in VAL. */ void msg_if_set(const int val, const struct bits_to_name msg_tbl[]) { int i; for (i = 0; msg_tbl[i].bits; i++) if (msg_tbl[i].bits & val) printf(" %s\n", msg_tbl[i].msg); } /* Find the first matching MSG_TBL entry to describe VAL. Return the message from that entry. The message table is terminated with an entry using a zero mask, and the string from entry is the no-match default. */ const char *msg_match(const int val, const struct bitfield_to_name msg_tbl[]) { int i; for (i = 0; msg_tbl[i].mask; i++) if ((val & msg_tbl[i].mask) == msg_tbl[i].val) break; return msg_tbl[i].msg; } /* Chip version from TxConfig. */ static const struct bitfield_to_name chip_ver_table[] = { { 0x60000000, 0xfc800000, "rtl8139"}, { 0x70000000, 0xfc800000, "rtl8139A"}, { 0x70800000, 0xfc800000, "rtl8139A-G"}, { 0x78800000, 0xfc800000, "rtl8139B-G"}, /* No manual entry! */ { 0x78000000, 0xfc800000, "rtl8139B"}, { 0x7C000000, 0xfc800000, "rtl8130"}, { 0x74000000, 0xfc800000, "rtl8139C"}, { 0x74800000, 0xfc800000, "rtl8139C+"}, { 0x00000000, 0x00000000, "Unknown version"}, }; /* Receiver filter in RxConfig. */ static const struct bitfield_to_name rcvr_mode[] = { {0x0a, 0x3f, "Unicast and no multicast"}, {0x0e, 0x3f, "Normal unicast and hashed multicast"}, {0x0f, 0x3f, "Promiscuous"}, {0x00, 0x3f, "Reception disabled"}, {0x00, 0x00, "Unknown/invalid"}, }; /* Tx status registers. */ static const struct bits_to_name tx_status_table[] = { { 0x80000000, " Tx carrier lost"}, { 0x40000000, " Tx aborted"}, { 0x20000000, " Tx out-of-window collision"}, { 0x00004000, " Tx FIFO underrun"}, { 0, 0}, }; static int rtl81x9_eeprom(long ioaddr, int flags); /* Values read from the EEPROM, and a new image to write. */ static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len); #ifdef LIBFLASH /* Support for Flash operations. These functions are exported to the flash library. Note that early chip versions use FlashAccess offset 0x74, while current chips use 0xD4. */ static int rtl_flash_in(long ioaddr, int offset) { outl(0x1C0000 | (offset & 0x1ffff), ioaddr + FlashAccess); return inl(ioaddr + FlashAccess) >> 24; } static void rtl_flash_out(long ioaddr, int offset, int val) { outl((val<<24) | 0x1a0000 | (offset & 0x1ffff), ioaddr + FlashAccess); } #endif int rtl81x9_diag(int vendor_id, int device_id, long ioaddr, int part_idx) { int flags = pcidev_tbl[part_idx].flags; /* Capabilities. */ unsigned intr_status = inw(ioaddr + IntrStatus); int chip_cmd = inb(ioaddr + ChipCmd); int chip_active = 0; int i; /* It's mostly safe to examine the registers and EEPROM during operation. But warn the user, and make then pass '-f'. */ if ((chip_cmd & 0x000C) != 0x0000) chip_active = 1; if (show_regs) { if (chip_active && !opt_f) { printf("The RealTek chip appears to be active, so some registers" " will not be read.\n" "To see all register values use the '-f' flag.\n"); } else chip_active = 0; /* Ignore the chip status with -f */ printf("RealTek chip registers at %#lx", ioaddr); for (i = 0; i < 0x80; i += 4) { if ((i & 0x1f) == 0) printf("\n 0x%3.3X:", i); printf(" %8.8x", inl(ioaddr + i)); } printf(".\n"); } if (intr_status == 0xffff && !opt_f) { printf(" * A recognized chip has been found, but it does not " "appear to exist in\n * I/O space. Use the" " '-f' flag to show the status anyway.\n"); return 1; } /* Always show the basic status. */ printf("Realtek station address "); for (i = 0; i < 5; i++) printf("%2.2x:", inb(ioaddr + i)); printf("%2.2x, ", inb(ioaddr + i)); { int tx_config = inl(ioaddr + TxConfig); int rx_config = inl(ioaddr + RxConfig); unsigned char cfg0 = inb(ioaddr + Config0); unsigned char cfg1 = inb(ioaddr + Config1); const char *xcvr_mode[] = { "MII", "an invalid transceiver", "MII/symbol", "4B/5B scambler"}; printf("chip type '%s'.\n" " Receiver configuration: %s\n" " Rx FIFO threshold %d bytes, maximum burst %d bytes, " "%dKB ring\n" " Transmitter %sabled with %s settings, maximum burst" " %d bytes.\n", msg_match(tx_config, chip_ver_table), msg_match(rx_config, rcvr_mode), 16 << ((rx_config >> 13) & 7), 16 << ((rx_config >> 8) & 7), 8 << ((rx_config >> 11) & 3), chip_cmd & 0x04 ? "en" : "dis", (tx_config & 0x30700f0) ? "NONSTANDARD!" : "normal", 16 << ((tx_config >> 8) & 7)); if (opt_a) for (i = 0; i < 4; i++) { int tx_status = inl(ioaddr + TxStat0 + i*4); printf(" Tx entry #%d status %8.8x %scomplete, %d bytes.\n", i, tx_status, tx_status & 0x8000 ? "" : "in", tx_status & 0x7ff); msg_if_set(tx_status, tx_status_table); } printf(" Flow control: Tx %sabled Rx %sabled.\n", inb(ioaddr + GPPinData) & 0x80 ? "en" : "dis", inb(ioaddr + GPPinData) & 0x40 ? "en" : "dis"); printf(" The chip configuration is 0x%2.2x 0x%2.2x, %s %s-duplex" " mode.\n", cfg0, cfg1, cfg0 & 0x20 ? "10baseT" : xcvr_mode[cfg0>>6], cfg1 & 0x40 ? "full" : "half"); printf(" %snterrupt sources are pending.\n", (intr_status & 0x03ff) ? "I": "No i"); if (intr_status) { for (i = 0; i < 16; i++) if (intr_status & (1< 1) { show_mii_details(ioaddr, phys[0]); if (show_mii > 2) monitor_mii(ioaddr, phys[0]); } #else else for (phy = 0; phy < phy_idx; phy++) { int mii_reg; printf(" MII PHY #%d transceiver registers:", phys[phy]); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mdio_read(ioaddr, phys[phy], mii_reg)); printf(".\n"); } #endif } if (show_mii && ! (flags & HasMII)) { printf(" The RTL8139 does not use a MII transceiver.\n" " It does have internal MII-compatible registers:\n" " Basic mode control register 0x%4.4x.\n" " Basic mode status register 0x%4.4x.\n" " Autonegotiation Advertisement 0x%4.4x.\n" " Link Partner Ability register 0x%4.4x.\n" " Autonegotiation expansion 0x%4.4x.\n" " Disconnects 0x%4.4x.\n" " False carrier sense counter 0x%4.4x.\n" " NWay test register 0x%4.4x.\n" " Receive frame error count 0x%4.4x.\n", inw(ioaddr + MII_BMCR), inw(ioaddr + MII_BMSR), inw(ioaddr + NWayAdvert), inw(ioaddr + NWayLPAR), inw(ioaddr + NWayExpansion), inw(ioaddr + 0x6C), inw(ioaddr + 0x6E), inw(ioaddr + 0x70), inw(ioaddr + 0x72)); #ifdef LIBMII if (show_mii > 1) { show_mii_details(ioaddr, 32); if (show_mii > 2) monitor_mii(ioaddr, 32); } #endif } #ifdef LIBFLASH { flash_in_hook = rtl_flash_in; flash_out_hook = rtl_flash_out; /* Turn on the Flash chip. */ outl(0x020000, ioaddr + FlashAccess); if (opt_flash_show) flash_show(ioaddr, 0); if (opt_flash_dumpfile) if (flash_dump(ioaddr, 0, opt_flash_dumpfile) < 0) { fprintf(stderr, "Failed to save the old Flash BootROM image " "into file '%s'.\n", opt_flash_dumpfile); return 3; } if (opt_flash_loadfile) if (flash_program(ioaddr, 0, opt_flash_loadfile) < 0) { fprintf(stderr, "Failed to load the new Flash BootROM image " "from file '%s'.\n", opt_flash_loadfile); return 4; } /* Turn off the Flash chip. */ outl(0x000000, ioaddr + FlashAccess); } #else if (opt_flash_loadfile || opt_flash_dumpfile || opt_flash_show) printf("Flash operations not configured into this program.\n"); #endif if (do_test) { printf("FIFO buffer test not yet available.\n"); } return 0; } /* Configuration EEPROM contents and updates. */ #define MAX_EEPROM_SIZE 256 /* In 16 bit words. */ #define EEPROM_SA_OFFSET 7 unsigned short eeprom_contents[MAX_EEPROM_SIZE]; unsigned short new_ee_contents[MAX_EEPROM_SIZE]; static void rtl8139_eeprom_decode(unsigned short *eeprom) { unsigned char *p = (void *)eeprom; int i, sum = 0; printf("Decoded EEPROM contents:\n" " PCI IDs -- Vendor %#4.4x, Device %#4.4x.\n" " PCI Subsystem IDs -- Vendor %#4.4x, Device %#4.4x.\n" " PCI timer settings -- minimum grant %d, maximum latency %d.\n" " General purpose pins -- direction 0x%2.2x value 0x%2.2x.\n" " Station Address ", eeprom[1], eeprom[2], eeprom[3], eeprom[4], p[10], p[11], p[13], p[12] ); for (i = 14; i < 19; i++) printf("%2.2X:", p[i]); printf("%2.2X.\n" " Configuration register 0/1 -- 0x%2.2x / 0x%2.2x.\n", p[i], p[21], p[22]); for (i = 0; i < 24; i++) sum += p[i]; printf(" EEPROM active region checksum is %4.4x.\n", sum); return; } static int rtl81x9_eeprom(long ioaddr, int flags) { int ee_addr_len = 6, eeprom_size = 64; int i; /* Read the EEPROM. */ if (set_hwaddr || show_eeprom || new_default_media >= 0) { ee_addr_len = eeprom_addr_len(ioaddr); eeprom_size = 1 << ee_addr_len; for (i = 0; i < eeprom_size; i++) eeprom_contents[i] = read_eeprom(ioaddr, i, ee_addr_len); memcpy(new_ee_contents, eeprom_contents, eeprom_size << 1); } /* The user will usually want to see the interpreted EEPROM contents. */ if (show_eeprom) rtl8139_eeprom_decode(eeprom_contents); if (show_eeprom > 1) { int previous_row_same = 0; printf("EEPROM contents (%d words):", eeprom_size); for (i = 0; i < eeprom_size; i += 8) { int j; if (i == 0 || /* Always show first row. */ (memcmp(eeprom_contents+i, eeprom_contents+i - 8, 16) != 0)) { previous_row_same = 0; printf("\n 0x%2.2x: ", i); for (j = 0; j < 8; j++) printf(" %4.4x", eeprom_contents[i + j]); if (show_eeprom > 2) { printf(" "); for (j = 0; j < 8; j++) { int ew = eeprom_contents[i + j]; printf("%c%c", isprint(ew & 0xff) ? ew & 0xff : '_', isprint(ew >> 8) ? ew >> 8 : '_' ); } } } else if ( ! previous_row_same) { previous_row_same = 1; printf("\n ..."); } } printf("\n"); } if (emergency_rewrite && ! set_hwaddr) printf("*** Emergency EEPROM rewrite is only valid when you also " "specify a new\n*** station address with -H \n"); if (set_hwaddr) { u16 backup_ee_contents[] = { 0x8129, 0x10ec, 0x8139, 0x10ec, 0x8139, 0x4020, 0xe110, 0x2301, 0x6745, 0xab89, 0x4d10, 0xf7c2, 0x8001, 0xb388, 0x58fa, 0x0708, 0xd843, 0xa438, 0xd843, 0xa438, 0xd843, 0xa438, 0xd843, 0xa438, }; /* A rtl8139c table is * 0x00: 8129 10ec 8139 10ec 8139 4020 e112 5000 * 0x08: b122 6e2a 4d14 f7c2 8801 43b9 b0f2 071a * 0x10: df43 8a36 df43 8a36 43b9 b0f2 1111 1111 */ if (emergency_rewrite > 2) memcpy(new_ee_contents, backup_ee_contents, sizeof backup_ee_contents); else if (emergency_rewrite) fprintf(stderr, "Overwriting the configuration EEPROM is likely " "to do more harm than good.\n Pass -EEE if you are " "certain this is what you want to do."); for (i = 0; i < 3; i++) new_ee_contents[i + EEPROM_SA_OFFSET] = (new_hwaddr[i*2+1]<<8) + new_hwaddr[i*2]; } if (new_default_media >= 0) { int new_media = eeprom_contents[6] & ~0x0031; switch (new_default_media) { case 0x0000: new_media |= 0x0000; break; /* 10baseT */ case 0x0204: new_media |= 0x0001; break; /* 10baseT-FDX */ case 0x0003: new_media |= 0x0020; break; /* 100baseTx */ case 0x0205: new_media |= 0x0021; break; /* 100baseTx-FDX */ case 0x0800: new_media |= 0x0011; break; /* Autosense */ default: printf(" Unsupported new media type (%4.4x), leaving the setting" " unchanged.\n", new_default_media); new_media = eeprom_contents[6]; /* Unchanged */ } if (new_ee_contents[6] != new_media) { printf(" Changing the default media setting to %4.4x.\n", new_media); new_ee_contents[6] = new_media; } } /* To set another EEPROM value do new_ee_contents[xxx] = new_value; */ if (set_hwaddr || new_default_media >= 0) { int not_written_msg = 0; for (i = 0; i < eeprom_size; i++) if (new_ee_contents[i] != eeprom_contents[i]) { if (do_write_eeprom) write_eeprom(ioaddr, i, new_ee_contents[i], ee_addr_len); else { printf(" Would write %4.4x to replace 0x%4.4x at " "offset %d.\n", new_ee_contents[i], eeprom_contents[i], i); not_written_msg++; } } if (not_written_msg) printf(" To actually write these values pass the '-w' flag.\n" " Note that this is a permanent action!\n" " You should record the original EEPROM values in" " a safe place.\n"); } return 0; } /* Serial EEPROM section. */ /* The EEPROM commands always start with 01.. preamble bits. Commands are prepended to the variable-length address. */ enum EEPROM_Cmds { EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7, }; enum EEPROM_Ctrl_Bits { EE_ShiftClk=0x04, EE_ChipSelect=0x88, EE_DataOut=0x02, EE_DataIn=0x01, EE_Write0=0x88, EE_Write1=0x8A, }; /* EEPROM_Ctrl bits. */ #define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ #define EE_CS 0x08 /* EEPROM chip select. */ #define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */ #define EE_WRITE_0 (0x00 | EE_ENB) #define EE_WRITE_1 (0x02 | EE_ENB) #define EE_DATA_READ 0x01 /* EEPROM chip data out. */ #define EE_ENB (0x80 | EE_CS) /* Delay between EEPROM clock transitions. This forces out buffered PCI writes. */ #define eeprom_delay(ee_addr) inb(ee_addr) /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD (5) #define EE_READ_CMD (6) #define EE_ERASE_CMD (7) /* This executes a generic EEPROM command, typically a write or write enable. It returns the data output from the EEPROM, and thus may also be used for reads. */ static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len) { unsigned retval = 0; long ee_addr = ioaddr + Cfg9346; if (debug > 1) printf(" EEPROM op 0x%x: ", cmd); outb(EE_ChipSelect | EE_ShiftClk, ee_addr); /* Shift the command bits out. */ do { short dataval = (cmd & (1 << cmd_len)) ? EE_Write1 : EE_Write0; outb(dataval, ee_addr); eeprom_delay(ee_addr); if (debug > 2) printf("%X", inl(ee_addr) & 15); outb(dataval | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); retval = (retval << 1) | ((inb(ee_addr) & EE_DataIn) ? 1 : 0); } while (--cmd_len >= 0); outb(EE_ChipSelect, ee_addr); /* Terminate the EEPROM access. */ outb(0x80, ee_addr); outb(0, ee_addr); if (debug > 1) printf(" EEPROM result is 0x%5.5x.\n", retval); return retval; } /* Wait for the EEPROM to finish what it is doing. Note that we take the already computed ioaddr of the control register. */ static int eeprom_busy_poll(long ee_ioaddr) { int i; outb(EE_ChipSelect, ee_ioaddr); for (i = 0; i < 10000; i++) /* Typical 2000 ticks */ if (inb(ee_ioaddr) & EE_DataIn) break; return i; } /* The abstracted functions for EEPROM access. */ /* Return the number of address bits this EEPROM accepts. Note that we cannot count on a leading transition bit, and must look explicitly for the initial value. This approach might fail with a blank or corrupted EEPROM. */ static int eeprom_addr_len(long ioaddr) { int testval = do_eeprom_cmd(ioaddr, (((EE_READ_CMD<<8)|0) << 16) | 0xffff, 3 + 8 + 16); int addr_size = (read_eeprom(ioaddr, 0, 6) & 0xffff) == 0x8129 ? 6 : 8; if (debug) printf(" Testvalue %x address size %d, test read 0x%4.4x.\n", testval, addr_size, read_eeprom(ioaddr, 0, 6)); return addr_size; } static int read_eeprom(long ioaddr, int location, int addr_len) { return do_eeprom_cmd(ioaddr, ((EE_ReadCmd << addr_len) | location) << 16, 3 + addr_len + 16) & 0xffff; } static void write_eeprom(long ioaddr, int index, int value, int addr_len) { long ee_ioaddr = ioaddr + Cfg9346; int i; /* Poll for previous op finished. */ eeprom_busy_poll(ee_ioaddr); /* Enable programming modes. */ do_eeprom_cmd(ioaddr, (0x4f << (addr_len-4)), 3 + addr_len); /* Do the actual write. */ do_eeprom_cmd(ioaddr, (((EE_WriteCmd<= 0; i--) { outb(MDIO_WRITE1, mdio_addr); mdio_delay(); outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr); mdio_delay(); } return; } int mdio_read(long ioaddr, int phy_id, int location) { long mdio_addr = ioaddr + MII_SMI; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; int i; if (phy_id == 32) { /* Really a 8139. Use internal registers. */ return location < 8 && mii_2_8139_map[location] ? inw(ioaddr + mii_2_8139_map[location]) : 0; } mdio_sync(mdio_addr); /* Shift the read command bits out. */ for (i = 15; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0; if (verbose > 3) /* Debug: 5 */ printf("%d", (mii_cmd & (1 << i)) ? 1 : 0); outb(MDIO_DIR | dataval, mdio_addr); mdio_delay(); outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr); if (verbose > 4) printf(" %x ", (inb(mdio_addr) & 0x0f)); mdio_delay(); } if (verbose > 3) printf("-> %x", inb(mdio_addr) & 0x0f); /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { outb(0, mdio_addr); mdio_delay(); retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0); outb(MDIO_CLK, mdio_addr); mdio_delay(); if (verbose > 3) printf("%x", inb(mdio_addr) & 0x0f); } if (verbose > 2) printf(" MII read of %d:%d -> %4.4x.\n", phy_id, location, retval); return (retval>>1) & 0xffff; } void mdio_write(long ioaddr, int phy_id, int location, int value) { long mdio_addr = ioaddr + MII_SMI; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; int i; if (phy_id == 32) { /* Really a 8139. Use internal registers. */ if (location < 8 && mii_2_8139_map[location]) outw(value, ioaddr + mii_2_8139_map[location]); return; } mdio_sync(mdio_addr); /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; outb(dataval, mdio_addr); mdio_delay(); outb(dataval | MDIO_CLK, mdio_addr); if (verbose > 4) printf(" %x ", (inb(mdio_addr) & 0x0f)); mdio_delay(); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { outb(0, mdio_addr); mdio_delay(); outb(MDIO_CLK, mdio_addr); mdio_delay(); } return; } /* * Local variables: * compile-command: "cc -O -Wall -o rtl8139-diag rtl8139-diag.c `[ -f libmii.c ] && echo -DLIBMII libmii.c`" * simple-compile-command: "cc -O -Wall -o rtl8139-diag rtl8139-diag.c" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 * End: */ nictools-pci-1.3.8.orig/starfire-diag.c0000644000175000017500000004636307137502056016725 0ustar alainalain/* starfire-diag.c: Diagnostic and setup for the Adaptec Starfire DuraLAN. This is a diagnostic and EEPROM setup program for PCI adapters based on the following chips: Adaptec 6915 "Starfire" This file contains the complete diagnostic code. Copyright 1998-2000 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 410 Severn Ave., Suite 210 Annapolis MD 21403 Support and updates available at http://www.scyld.com/diag/index.html http://scyld.com/expert/mii-status.html http://scyld.com/expert/NWay.html Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. */ static char *version_msg = "starfire-diag.c:v2.01 7/26/2000 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: etherdiag [-aEefFmqrRtvVwW] [-p ] [-[AF] ]\n"; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif /* No libmii.h or libflash.h yet. */ extern int show_mii_details(long ioaddr, int phy_id); extern int monitor_mii(long ioaddr, int phy_id); extern int flash_show(long addr_ioaddr, long data_ioaddr); extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename); extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename); extern int (*flash_in_hook)(long addr, int offset); extern void (*flash_out_hook)(long addr, int offset, int val); /* We should use __u8 .. __u32, but they are not always defined. */ typedef unsigned int u32; typedef unsigned short u16; typedef unsigned char u8; struct option longopts[] = { /* { name has_arg *flag val } */ {"Advertise", 1, 0, 'A'}, {"base-address", 1, 0, 'p'}, {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Give help */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; extern int starfire_diag(int vend_id, int dev_id, long ioaddr, int part_idx); /* Chip-specific flags. Yes, it's grungy to have the enum here. */ /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name and a PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { char *proc_pci_name; char *part_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_num); } pcidev_tbl[] = { { "Adaptec Unknown device", "Adaptec Starfire 6915", 0x9004, 0x6915, 0xffff, 0, 256, starfire_diag}, { 0, 0, 0, 0}, }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int nway_advertise = 0, fixed_speed = -1; int new_default_media = -1; /* Valid with libflash only. */ static unsigned int opt_flash_show = 0; static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int scan_proc_pci(int card_num); static int parse_media_type(const char *capabilities); static int get_media_index(const char *name); int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int emergency_rewrite = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:mp:qrRst:vVwWH:BL:S:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'A': nway_advertise = parse_media_type(optarg); break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'G': opt_G++; opt_GPIO = strtol(optarg, NULL, 16); break; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtol(optarg, NULL, 16); break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case 'W': opt_watch++; break; case 'B': opt_flash_show++; break; case 'L': opt_flash_loadfile = optarg; break; case 'S': opt_flash_dumpfile = optarg; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("Network adapter diagnostic: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for parsed contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if (pci_devid != (pcidev_tbl[i].vendor << 16) + pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].proc_pci_name; i++) if (strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Convert a text media name to a NWay capability word. */ static int parse_media_type(const char *capabilities) { const char *mtypes[] = { "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD", "10baseT", "10baseT-FD", "10baseT-HD", 0, }; int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,}; int i; if (debug) fprintf(stderr, "Advertise string is '%s'.\n", capabilities); for (i = 0; mtypes[i]; i++) if (strcasecmp(mtypes[i], capabilities) == 0) return cap_map[i]; if ((i = strtol(capabilities, NULL, 16)) <= 0xffff) return i; fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities); return 0; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to indices. This matches the Digital Tulip SROM numbering, primarily because that is the most complete list. Other chips will have to map these number to their internal values. */ struct { char *name; int value; } mediamap[] = { { "10baseT", 0 }, { "10base2", 1 }, { "AUI", 2 }, { "100baseTx", 3 }, { "10baseT-FDX", 0x204 }, { "100baseTx-FDX", 0x205 }, { "100baseT4", 6 }, { "100baseFx", 7 }, { "100baseFx-FDX", 8 }, { "MII", 11 }, { "Autosense", 0x0800 }, { 0, 0 }, }; static int get_media_index(const char *name) { int i; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) return i; if (name && atoi(name) >= 00) return atoi(name); fprintf(stderr, "Invalid interface specified: it must be one of\n "); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %s", mediamap[i].name); fprintf(stderr, ".\n"); return -1; } /* Chip-specific section. */ /* The chip-specific section for the Adaptec Starfire diagnostic. */ static int read_eeprom(long ioaddr, int location); int mdio_read(long ioaddr, int phy_id, int location); void mdio_write(long ioaddr, int phy_id, int location, int value); /* Offsets to the various registers. All accesses need not be longword aligned. */ enum starfire_offsets { GenCtrl=0x50070, IntrClear=0x50084, IntrStatus=0x50084, IntrEnable=0x50088, MIICtrl=0x52000, StationAddr=0x50120, EEPROMCtrl=0x51000, TxRingPtr=0x50098, HiPriTxRingPtr=0x50094, /* Low and High priority. */ TxRingAddrHi=0x5009C, /* 64 bit address extension. */ TxProducerIdx=0x500A0, TxConsumerIdx=0x500A4, TxThreshold=0x500B0, TxMode=0x55000, }; /* Non-interrupting events. */ const char *event_names[16] = { "Tx Abort", "Rx frame complete", "Transmit done", }; struct config_name { int val, mask; const char*name;} static rcvr_mode[] = { {0x44, 0xff, "Normal unicast and perfect multicast filtering"}, {0x34, 0xff, "Normal unicast and hashed multicast"}, {0x03, 0x02, "Normal unicast and all multicast"}, {0x01, 0x01, "Promiscuous"}, {0x00, 0x00, "Unknown/invalid"}, }; /* Values read from the EEPROM, and the new image. */ #define EEPROM_SIZE 32 unsigned int eeprom_contents[EEPROM_SIZE]; unsigned int new_ee_contents[EEPROM_SIZE]; int starfire_diag(int vendor_id, int device_id, long ioaddr, int part_idx) { int i; if (verbose || show_regs) { int MAC_config, MAC_addr; int rx_mode = inl(ioaddr + 0xf4); int pci_stats = inl(ioaddr + 0x48); if (opt_a) { printf("%s chip registers at %#lx", pcidev_tbl[part_idx].part_name, ioaddr); for (i = 0; i < pcidev_tbl[part_idx].io_size; i += 4) { if ((i & 0x1f) == 0) printf("\n 0x%3.3X:", i); if (!opt_f && i == 0x80) printf(" **INTR**"); else printf(" %8.8x", inl(ioaddr + i)); } printf("\n"); } printf(" Queue states\n" " Tx producer index %d, consumer index %d.\n" " Rx consumer index %d, producer index %d.\n", inw(ioaddr + 0xa0), inw(ioaddr + 0xa4), inw(ioaddr + 0xea), inw(ioaddr + 0xe8)); printf(" PCI statistics\n"); printf(" PCI Bus maximum latency was %d nsec, peak interrupt latency " "%d usec.\n", (pci_stats>>24)*480, (pci_stats & 0xff) *30); printf(" PCI accesses: %d slave cycles, %d master bursts.\n", inl(ioaddr + 0x48) & 0xffff, inl(ioaddr + 0x4C) & 0xffff); printf(" Interrupts pending: %8.8x\n", inl(ioaddr + 0x84)); for (i = 0; rcvr_mode[i].mask; i++) if ((rx_mode & rcvr_mode[i].mask) == rcvr_mode[i].val) break; printf(" Receive mode is 0x%8.8x: %s.\n", rx_mode, rcvr_mode[i].name); outl(0x50120, ioaddr + 0x68); MAC_addr = inl(ioaddr + 0x6c); printf(" MAC address is --:--:%2.2x:%2.2x:%2.2x:%2.2x.\n", (MAC_addr >> 24) & 0xff, (MAC_addr >> 16) & 0xff, (MAC_addr >> 8) & 0xff, (MAC_addr >> 0) & 0xff); outl(0x55000, ioaddr + 0x68); MAC_config = inl(ioaddr + 0x6c); printf(" MAC Config 1 is %8.8x: %s-duplex.\n", MAC_config, MAC_config & 0x02 ? "full" : "half"); if (opt_a > 2) { printf(" Statistics registers: "); for (i = 0; i < 0x100; i+=4) { outl(0x57000+i, ioaddr + 0x68); printf(" %8.8x%s", inl(ioaddr + 0x6c), i%16 == 15 ? "\n " : ""); } printf("\n"); } } for (i = 0; i < EEPROM_SIZE; i++) eeprom_contents[i] = read_eeprom(ioaddr, i); if (show_eeprom) { u32 sum = 0; u8 *ee = (u8*)eeprom_contents; if (show_eeprom > 1) { printf("EEPROM contents:"); for (i = 0; i < EEPROM_SIZE; i++) { if ((i & 7) == 0) printf("\n0x%3.3x: ", i); printf(" %8.8x", eeprom_contents[i]); } printf("\n"); } printf("EEPROM Subsystem IDs, Vendor %2.2x%2.2x Device %2.2x%2.2x.\n", ee[7], ee[6], ee[9], ee[8]); printf("EEPROM Station address is "); for (i = 20; i > 15; i--) printf("%2.2x:", ee[i]); printf("%2.2x.\n", ee[i]); for (i = 0; i < EEPROM_SIZE-1; i++) sum ^= eeprom_contents[i]; printf("EEPROM Checksum is %8.8x.\n", sum); for (i = 0, sum=0; i < EEPROM_SIZE*4 - 2; i++) sum += ee[i]; printf("EEPROM Checksum is %8.8x.\n", sum); } if (show_mii) { int phys[4], phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(ioaddr, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { phys[phy_idx++] = phy; printf(" MII PHY found at address %d, status 0x%4.4x.\n", phy, mii_status); } } if (phy_idx == 0) printf(" ***WARNING***: No MII transceivers found!\n"); for (phy = 0; phy < phy_idx; phy++) { int mii_reg; printf(" MII PHY #%d transceiver registers:", phys[phy]); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mdio_read(ioaddr, phys[phy], mii_reg)); printf(".\n"); } #ifdef LIBMII show_mii_details(ioaddr, phys[0]); if (show_mii > 1) monitor_mii(ioaddr, phys[0]); #endif } return 0; } static int read_eeprom(long ioaddr, int location) { outl(EEPROMCtrl + location*4, ioaddr + 0x68); return inl(ioaddr + 0x6C); } #ifdef notused static void write_eeprom(long ioaddr, int location, int value) { outl(EEPROMCtrl + location*4, ioaddr + 0x68); outl(value, ioaddr + 0x6C); return; } #endif /* MII Managemen Data I/O accesses. These routines assume the MDIO controller is idle, and do not exit until the command is finished. */ int mdio_read(long ioaddr, int phy_id, int location) { int result, boguscnt=1000; outl(MIICtrl + (phy_id<<7) + location*4, ioaddr + 0x68); do result = inl(ioaddr + 0x6C); while ((result & 0xC0000000) != 0x80000000 && --boguscnt >= 0); return result & 0xffff; } void mdio_write(long ioaddr, int phy_id, int location, int value) { outl(MIICtrl + (phy_id<<7) + location*4, ioaddr + 0x68); outl(value, ioaddr + 0x6C); return; } /* * Local variables: * compile-command: "cc -O -Wall -o starfire-diag starfire-diag.c" * tab-width: 4 * c-indent-level: 4 * c-basic-offset: 4 * End: */ nictools-pci-1.3.8.orig/tulip-diag.c0000644000175000017500000017052210264222626016233 0ustar alainalain/* tulip-diag.c: Diagnostic and setup for Digital DC21x4*-based ethercards. This is a diagnostic and EEPROM setup program for PCI Ethernet adapters based on the following chips: Intel (nee Digital) "Tulip" series chips: 21040/041/140/142/143/145, Work-alikes from Lite-On, LinkSys, Macronix, ASIX, Compex, STmicro, ADMtek, Davicom and (ugh) Xircom. Copyright 1998-2003 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 Support and updates available at http://www.scyld.com/diag/index.html http://scyld.com/expert/mii-status.html http://scyld.com/expert/NWay.html Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. To use this code under other terms requires an explicit license from the copyright holder. */ static char *version_msg = "tulip-diag.c:v2.18 11/12/2003 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: tulip-diag [-aDEefFGhmqrRtvVwW] [-p ] [-[AF] ]\n" " For details and other options see http://www.scyld.com/diag/index.html\n"; static const char long_usage_msg[] = "Usage: %s [-aDfrRvVw] [-AF ] [-#]\n" "\n" " Show the internal state of a network adapter.\n" "\n" " The common usage is\n" " diag -aem\n" "\n" " Frequently used options are\n" " -a --show_all_registers Print all registers.\n" " -e --show-eeprom Dump EEPROM contents, \"-ee\" shows the details.\n" " -m --show_mii Print the MII transceiver state\n" " Using -mm monitors the link.\n" " -f --force Perform operation, even on a running NIC.\n" "\n" " To operate on a single NIC, or one that hasn't been automatically found:\n" " -# --card_num INDEX Operate on the specified card index.\n" " -p --port-base IOADDR Assume an adapter at the specified I/O address.\n" " -t --chip-type TYPE Specify adapter type (with '-p'), use '-1' to list.\n" "\n" " To change the persistent EEPROM settings\n" " -F, --new-interface N Set the default transceiver type.\n" " -G --parameters PARMS Set adapter-specific parameters.\n" " -H --new-hwaddr 01:23:45:67:89:ab\n" " Set a new hardware station address. Typically disabled for safety.\n" " -w --write-EEPROM Actually write the new settings into the EEPROM.\n" " To read and write the boot BIOS extension Flash ROM\n" " -B Show the first few bytes of the ROM\n" " -L FILE Load the Flash from FILE.\n" " -S FILE Store the Flash image to FILE.\n" "\n" " -D --debug\n" " -v --verbose Report each action taken.\n" " -V --version Emit version information.\n" "\n" " -A --advertise (See the mii-diag manual page.)\n" "\n"; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include #include #include #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif /* No libmii.h or libflash.h yet, thus the declarations here. */ extern int show_mii_details(long ioaddr, int phy_id); extern int monitor_mii(long ioaddr, int phy_id); extern int flash_show(long addr_ioaddr, long data_ioaddr); extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename); extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename); extern int (*flash_in_hook)(long addr, int offset); extern void (*flash_out_hook)(long addr, int offset, int val); /* We should use __u8 .. __u32, but they are not always defined. */ typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; struct option longopts[] = { /* { name has_arg *flag val } */ {"card-num", 1, 0, '#'}, /* Operate on the specified card index. */ {"Advertise", 1, 0, 'A'}, {"base-address", 1, 0, 'p'}, {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Print a long usage message. */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"restart", 0, 0, 'r'}, /* Restart autonegotiation. */ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; extern int tulip_diag(int vend_id, int dev_id, long ioaddr, int part_idx); enum tulip_flags { DC21041_EEPROM=1, DC21040_EEPROM=2, DC21140_EEPROM=4, PNIC_EEPROM=8, CSR12_IS_GPIO=0x10, PNIC_MTABLE=0x20, DC21143_MII=0x100, PNIC_MII=0x200, COMET_MII=0x400, HAS_NWAY=0x800, ASIX_MACADDR=0x1000, COMET_MACADDR=0x2000, PNIC2_MACADDR=0x4000, IS_CONEXANT=0x8000, COMET_HPNA=0x10000, IS_DAVICOM=0x20000, }; /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name from the kernel, a common name and the PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { const char *part_name; const char *proc_pci_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx); } pcidev_tbl[] = { { "Digital Tulip series", "Digital Tulip, unknown type", 0x1011, 0x0000, 0xffff, 0, 128, tulip_diag }, { "Digital DC21040 Tulip", "DEC DC21040", 0x1011, 0x0002, 0xffff, DC21040_EEPROM, 128, tulip_diag }, { "Digital DC21041 Tulip", "DEC DC21041", 0x1011, 0x0014, 0xffff, DC21041_EEPROM | HAS_NWAY, 128, tulip_diag }, { "Digital DS21140 Tulip", "DEC DC21140", 0x1011, 0x0009, 0xffff, CSR12_IS_GPIO, 128, tulip_diag }, { "Digital DS21143 Tulip", "DEC DC21142", 0x1011, 0x0019, 0xffff, DC21143_MII | HAS_NWAY, 128, tulip_diag }, { "Intel 21145 Tulip", 0, 0x8086, 0x0039, 0xffff, DC21143_MII | HAS_NWAY, 128, tulip_diag }, { "Lite-On 82c168 PNIC", "Lite-on LNE100TX", 0x11AD, 0x0002, 0xffff, CSR12_IS_GPIO|PNIC_EEPROM|PNIC_MII, 256, tulip_diag }, { "Lite-On PNIC-II", 0, 0x11AD, 0xc115, 0xffff, PNIC_MTABLE | HAS_NWAY | PNIC2_MACADDR, 256, tulip_diag }, { "Macronix 98713 PMAC", "Macronix MX98713", 0x10d9, 0x0512, 0xffff, CSR12_IS_GPIO, 256, tulip_diag }, { "Macronix 98715 PMAC", "Macronix MX98715 / MX98725", 0x10d9, 0x0531, 0xffff, 0, 256, tulip_diag }, { "Macronix MX98715 / MX98725", "Macronix 98725 PMAC", 0x10d9, 0x0531, 0xffff, 0, 256, tulip_diag }, { "ASIX AX88140", 0, 0x125B, 0x1400, 0xffff, CSR12_IS_GPIO | ASIX_MACADDR, 128, tulip_diag }, { "Compex TX9881", "Compex TX9881", 0x11F6, 0x9881, 0xffff, 0, 128, tulip_diag }, { "ADMtek AL981 Comet", 0, 0x1317, 0x0981, 0xffff, COMET_MII | COMET_MACADDR, 256, tulip_diag }, { "ADMtek AL985 Centaur-P", 0, 0x1317, 0x0985, 0xffff, COMET_MACADDR, 256, tulip_diag }, { "ADMtek AL985 Centaur-C", 0, 0x1317, 0x1985, 0xffff, COMET_MACADDR, 256, tulip_diag }, { "ADMtek Comet-II", 0, 0x1317, 0x9511, 0xffff, COMET_MACADDR | COMET_HPNA, 256, tulip_diag }, { "ADMtek AL985 Centaur (Linksys CardBus v2)", 0, 0x13d1, 0xab02, 0xffff, COMET_MACADDR, 256, tulip_diag }, { "ADMtek AL985 Centaur (Linksys CardBus)", 0, 0x13d1, 0xab03, 0xffff, COMET_MACADDR, 256, tulip_diag }, { "ADMtek AL985 Centaur (OEM CardBus)", 0, 0x13d1, 0xab08, 0xffff, COMET_MACADDR, 256, tulip_diag }, { "ADMtek AL985 Centaur (Vendor 0x13d1 Unknown version)", 0, 0x13d1, 0xab00, 0xfff0, COMET_MACADDR, 256, tulip_diag }, { "Linksys PCM200 v4 CardBus (ADMtek AL985 Centaur)", 0, 0x1737, 0xab08, 0xffff, COMET_MACADDR, 256, tulip_diag }, { "Linksys PCM200 v3 CardBus (ADMtek AL985 Centaur)", 0, 0x1737, 0xab09, 0xffff, COMET_MACADDR, 256, tulip_diag }, { "STMicro STE10/100 Comet", 0, 0x104a, 0x0981, 0xffff, COMET_MACADDR, 256, tulip_diag }, { "STMicro STE10/100A Comet", 0, 0x104a, 0x2774, 0xffff, COMET_MACADDR, 256, tulip_diag }, { "Accton EN1217/EN2242 (ADMtek Comet)", 0, 0x1113, 0x1216, 0xffff, COMET_MACADDR, 256, tulip_diag }, { "Davicom DM9102", 0, 0x1282, 0x9102, 0xffff, CSR12_IS_GPIO, 128, tulip_diag }, { "Davicom DM9100", 0, 0x1282, 0x9100, 0xffff, CSR12_IS_GPIO, 128, tulip_diag }, { "Davicom DM9100 series (unknown model)", 0, 0x1282, 0x9100, 0xfff0, CSR12_IS_GPIO | IS_DAVICOM, 128, tulip_diag }, { "Conexant LANfinity", 0, 0x14f1, 0x1803, 0xffff, IS_CONEXANT, 256, tulip_diag }, { "3Com 3cSOHO100B-TX (ADMtek Centaur)", 0, 0x10b7, 0x9300, 0xffff, COMET_MACADDR, 256, tulip_diag }, { "3Com 3cSOHO100B-TX (ADMtek Centaur ID 8c00)", 0, 0x10b7, 0x8c00, 0xffff, COMET_MACADDR, 256, tulip_diag }, { 0, 0, 0, 0}, }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int nway_advertise = 0, fixed_speed = -1; int new_default_media = -1; /* Valid with libflash only. */ static unsigned int opt_flash_show = 0; static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int emergency_rewrite = 0; static int scan_proc_pci(int card_num); static int parse_media_type(const char *capabilities); static int get_media_index(const char *name); int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:hH:mp:qrRt:vVwWBL:S:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'A': nway_advertise = parse_media_type(optarg); break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 16); break; case 'h': fprintf(stderr, long_usage_msg, argv[0]); return 0; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtoul(optarg, NULL, 16); break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case 'W': opt_watch++; break; case 'B': opt_flash_show++; break; case 'L': opt_flash_loadfile = optarg; break; case 'S': opt_flash_dumpfile = optarg; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("Network adapter diagnostic: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for parsed contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n" " See http://www.scyld.com/expert/irq-conflict.html for more information.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if ((pci_devid >> 16) != pcidev_tbl[i].vendor || (pci_devid & pcidev_tbl[i].device_mask) != pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].part_name; i++) if (pcidev_tbl[i].proc_pci_name && strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Convert a text media name to a NWay capability word. */ static int parse_media_type(const char *capabilities) { const char *mtypes[] = { "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD", "10baseT", "10baseT-FD", "10baseT-HD", 0, }; char *endptr; int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,}; int i; if (debug) fprintf(stderr, "Advertise string is '%s'.\n", capabilities); for (i = 0; mtypes[i]; i++) if (strcasecmp(mtypes[i], capabilities) == 0) return cap_map[i]; i = strtoul(capabilities, &endptr, 16); if (*endptr == 0 && 0 < i && i <= 0xffff) return i; fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities); return 0; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to indices. This matches the Digital Tulip SROM numbering, primarily because that is the most complete list. Other chips will have to map these number to their internal values. */ struct { char *name; int value; } mediamap[] = { { "10baseT", 0 }, { "10base2", 1 }, { "AUI", 2 }, { "100baseTx", 3 }, { "10baseT-FDX", 0x204 }, { "100baseTx-FDX", 0x205 }, { "100baseT4", 6 }, { "100baseFx", 7 }, { "100baseFx-FDX", 8 }, { "MII", 11 }, { "HomePNA", 18 }, { "Autosense", 0x0800 }, { 0, 0 }, }; static int get_media_index(const char *name) { char *endptr; int i; if (! name) return -1; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) { if (debug) fprintf(stderr, "Using media index %d for '%s'.\n", i, name); return i; } i = strtol(name, &endptr, 0); if (*endptr == 0) return i; fprintf(stderr, "Invalid interface specified. It must be one of\n"); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %d %s\n", mediamap[i].value, mediamap[i].name); return -1; } /* Chip-specific section. */ int tulip_diag(int vendor_id, int device_id, long ioaddr, int part_idx); int mdio_read(long ioaddr, int phy_id, int location); void mdio_write(long ioaddr, int phy_id, int location, int value); static void mdio_sync(long ioaddr); static void setup_nway_xcvr(long ioaddr); static void tulip_eeprom(long ioaddr, int flags); static int read_eeprom(long ioaddr, int location, int addr_len); static void parse_eeprom(long ioaddr, unsigned char *ee_data, int part_idx); static void liteon_eeprom(unsigned char *ee_data, int part_idx); static void admtek_eeprom(unsigned char *ee_data, int part_idx); static void conexant_eeprom(unsigned char *ee_data, int part_idx); static void davicom_eeprom(unsigned char *ee_data, int part_idx); static unsigned int calculate_checksum1(u16 *eeprom_contents, int len); static unsigned int ether_crc_le(void *ptr, int length); int do_update(long ioaddr, u_int16_t *ee_values, int index, char *field_name, int new_value); static void check_for_intel_cb(long ioaddr, u_int16_t *eeprom_contents); /* Offsets to the Command and Status Registers, "CSRs". All accesses must be longword instructions and quadword aligned. I know these are not descriptive, but they are the commonly used names for the Tulip design. */ enum tulip_offsets { CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 }; static const char *tx_state[8] = { "Stopped", "Reading a Tx descriptor", "Waiting for Tx to finish", "Loading Tx FIFO", "", "Processing setup information", "Idle", "Closing Tx descriptor" }; static const char *rx_state[8] = { "Stopped", "Reading a Rx descriptor", "Waiting for Rx to finish", "Waiting for packets", "Suspended -- no Rx buffers", "Closing Rx descriptor", "Unavailable Rx buffer -- Flushing Rx frame", "Transferring Rx frame into memory", }; static const char *bus_error[8] = { "Parity Error", "Master Abort", "Target abort", "Unknown 3", "Unknown 4", "Unknown 5", "Unknown 6", "Unknown 7"}; const char *intr_names[16] ={ "Tx done", "Tx complete", "Tx out of buffers", "Transmit Jabber", "Link passed", "Tx FIFO Underflow", "Rx Done", "Receiver out of buffers", "Receiver stopped", "Receiver jabber", "Link changed", "Timer expired", "Link failed", "PCI bus error", "Early Rx", "Abnormal summary", }; #define EEPROM_SIZE 256 /* Size may be 256x16 for CardBus. */ static int has_mii = 0; static int current_part_idx = 0; /* Global, for mdio_{read,write,sync}() */ static int default_media_offset = -1; /* Values read from the EEPROM, and the new image to write. */ static u_int16_t eeprom_contents[EEPROM_SIZE]; static u_int16_t new_ee_contents[EEPROM_SIZE]; /* Support for Flash operations. */ static int tulip_flash_in(long ioaddr, int offset) { outl(offset, ioaddr + CSR10); outl(0x5000, ioaddr + CSR9); return inl(ioaddr + CSR9) & 0xff; } #ifdef LIBFLASH static void tulip_flash_out(long ioaddr, int offset, int val) { outl(offset, ioaddr + CSR10); outl(0x3000 | val, ioaddr + CSR9); } #endif int tulip_diag(int vendor_id, int device_id, long ioaddr, int part_idx) { int flags = pcidev_tbl[part_idx].flags; /* Capabilities. */ int if_active = 0; int i; /* It's mostly safe to use the Tulip EEPROM and MDIO register during operation. But warn the user, and make then pass '-f'. */ if (opt_a && !opt_f && (inl(ioaddr + CSR6) & 0x2002) != 0) { printf(" * A potential Tulip chip has been found, but it appears to " "be active.\n * Either shutdown the network, or use the" " '-f' flag to see all values.\n"); if_active = 1; } /* We always have registers up to CSR15. We may always safely read up to CSR7. We must be stopped or have '-f' to show CSR8-CSR15, since we might clear the missed packet count and other status. Chips with registers above CSR15 usually space them on 4 byte boundaries instead of 8 byte boundaries. */ if (show_regs) { printf("%s chip registers at %#lx:\n 0x00:", pcidev_tbl[part_idx].part_name, ioaddr); for (i = 0; i < 64; i += 8) printf(" %8.8x", inl(ioaddr + i)); printf("\n"); if (!if_active || opt_f) { int num_regs = pcidev_tbl[part_idx].io_size; printf(" 0x40:"); for (; i < 128; i += 8) printf(" %8.8x", inl(ioaddr + i)); if (i < num_regs) { /* Extended registers are _not_ quadword aligned. */ printf("\n Extended registers:"); for (; i < num_regs; i += 4) { if (i % 32 == 0) printf("\n 0x%2.2x:", i); printf(" %8.8x", inl(ioaddr + i)); } } printf("\n"); } } if (!opt_f && inl(ioaddr + CSR5) == 0xffffffff) { printf(" * A recognized chip has been found, but it does not appear" " to exist in\n * I/O space. Use the" " '-f' flag to see the register values anyway.\n"); return 1; } else { int csr5 = inl(ioaddr + CSR5); int csr6 = inl(ioaddr + CSR6); if (flags & (DC21040_EEPROM | DC21041_EEPROM)) printf(" Port selection is %s-duplex.\n", csr6 & 0x0200 ? "full" : "half"); else if (flags & COMET_MACADDR) { /* ADMtek chips. */ printf(" Comet duplex is reported in the MII status registers.\n"); } else if (flags & PNIC2_MACADDR) { /* The PNIC-II chip. */ int csr14 = inl(ioaddr + CSR14); printf(" Port selection is %s, %s-duplex.\n", csr14 & 0x80 ? "N-Way autonegotiation" : csr6 & 0x00040000 ? "100baseTx" : "10mpbs-serial", csr6 & 0x0200 ? "full" : "half"); } else printf(" Port selection is %s%s, %s-duplex.\n", ! (csr6 & 0x00040000) ? "10mpbs-serial" : (csr6 & 0x00800000 ? "100mbps-SYM/PCS" : "MII"), (csr6 & 0x01800000)==0x01800000 ? " 100baseTx scrambler":"", csr6 & 0x0200 ? "full" : "half"); printf(" Transmit %s, Receive %s.\n", csr6 & 0x2000 ? "started" : "stopped", csr6 & 0x0002 ? "started" : "stopped"); printf(" The Rx process state is '%s'.\n", rx_state[(csr5 >> 17) & 7]); printf(" The Tx process state is '%s'.\n", tx_state[(csr5 >> 20) & 7]); if (csr5 & 0x2000) printf(" PCI bus error!: %s.\n", bus_error[(csr5 >> 23) & 7]); if (csr6 & 0x00200000) printf(" The transmit unit is set to store-and-forward.\n"); else { const short tx_threshold[2][4] = {{ 72, 96, 128, 160 }, {128,256, 512, 1024}}; printf(" The transmit threshold is %d.\n", tx_threshold[(csr6&0x00440000) == 0x00040000][(csr6>>14) & 3]); } if (csr5 & 0x18000) { printf(" Interrupt sources are pending! CSR5 is %8.8x.\n", csr5); for (i = 0; i < 15; i++) if (csr5 & (1<>16); if ((csr12 & 0x0002) == 0) printf(" 100baseTx link good.\n"); if ((csr12 & 0x0003) == 0) printf(" 10baseT link good.\n"); } if (flags & COMET_MACADDR) { printf(" Comet MAC address registers %8.8x %8.8x\n" " Comet multicast filter %8.8x%8.8x.\n", inl(ioaddr + 0xA4), inl(ioaddr + 0xA8), inl(ioaddr + 0xAC), inl(ioaddr + 0xB0)); } else if (flags & PNIC2_MACADDR) { /* Grrr, damn Lite-On cannot use a consistent byte order. */ printf(" The current PNIC-II MAC address is " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x (%8.8x %8.8x).\n", inb(ioaddr + 0xB8), inb(ioaddr + 0xB9), inb(ioaddr + 0xB2), inb(ioaddr + 0xB3), inb(ioaddr + 0xB0), inb(ioaddr + 0xB1), inl(ioaddr + 0xB8), inl(ioaddr + 0xB0)); printf(" The current PNIC-II WOL address is " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", inb(ioaddr + 0xBA), inb(ioaddr + 0xBB), inb(ioaddr + 0xC2), inb(ioaddr + 0xC3), inb(ioaddr + 0xC0), inb(ioaddr + 0xC1)); } /* Below this point might be unsafe while the interface is active. */ if (if_active && ! opt_f) return 1; if (flags & ASIX_MACADDR) { printf(" The MAC/filter registers are "); for (i = 0; i < 4; i++) { outl(i, ioaddr + CSR13); printf(" %8.8x", inl(ioaddr + CSR14)); } printf(".\n"); } tulip_eeprom(ioaddr, flags); if (opt_GPIO) { printf("Setting the GPIO register %8.8x.\n", opt_GPIO); outl(opt_GPIO, ioaddr + CSR15); printf("The GPIO register is now %8.8x.\n", inl(ioaddr + CSR15)); return 0; } /* Show up to four (not just the on-board) PHYs. */ if ((has_mii && verbose) || show_mii) { int phys[4], phy, phy_idx = 0; current_part_idx = part_idx; /* Hack, set a global */ mdio_sync(ioaddr); for (phy = 1; phy <= 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(ioaddr, phy & 0x1f, 1); if (mii_status != 0xffff && mii_status != 0x0000) { phys[phy_idx++] = phy & 0x1f; printf(" MII PHY found at address %d, status 0x%4.4x.\n", phy & 0x1f, mii_status); } } if (phy_idx) { if (nway_advertise > 0) { printf(" Setting the media capability advertisement register" " of PHY #%d to 0x%4.4x.\n", phys[0], nway_advertise | 1); mdio_write(ioaddr, phys[0], 4, nway_advertise | 1); } if (opt_restart) { printf("Restarting negotiation...\n"); mdio_write(ioaddr, phys[0], 0, 0x0000); mdio_write(ioaddr, phys[0], 0, 0x1200); } /* Force 100baseTx-HD by mdio_write(ioaddr,phys[0], 0, 0x2000); */ if (fixed_speed >= 0) { int reg0_val = 0; reg0_val |= (fixed_speed & 0x0180) ? 0x2000 : 0; reg0_val |= (fixed_speed & 0x0140) ? 0x0100 : 0; printf("Setting the speed to \"fixed\", %4.4x.\n", reg0_val); mdio_write(ioaddr, phys[0], 0, reg0_val); } } if (phy_idx == 0) printf(" No MII transceivers found!\n"); #ifdef LIBMII else { if (show_mii > 1) show_mii_details(ioaddr, phys[0]); if (opt_watch || show_mii > 2) monitor_mii(ioaddr, phys[0]); } #else else for (phy = 0; phy < phy_idx; phy++) { int mii_reg; printf(" MII PHY #%d transceiver registers:", phys[phy]); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mdio_read(ioaddr, phys[phy], mii_reg)); printf(".\n"); } #endif } if (flags & HAS_NWAY) setup_nway_xcvr(ioaddr); #ifdef LIBFLASH flash_in_hook = tulip_flash_in; flash_out_hook = tulip_flash_out; if (opt_flash_show) flash_show(ioaddr, 0); if (opt_flash_dumpfile) if (flash_dump(ioaddr, 0, opt_flash_dumpfile) < 0) { fprintf(stderr, "Failed to save the old Flash BootROM image into" " file '%s'.\n", opt_flash_dumpfile); return 3; } if (opt_flash_loadfile) { outl(0x3000, ioaddr + CSR9); if (flash_program(ioaddr, 0, opt_flash_loadfile) < 0) { fprintf(stderr, "Failed to load the new Flash BootROM image from" " file '%s'.\n", opt_flash_loadfile); return 4; } } #else if (opt_flash_loadfile || opt_flash_dumpfile || opt_flash_show) printf("Flash operations not configured into this program.\n"); if (opt_flash_show) { printf("The first few boot ROM bytes are:"); for (i = 0; i < 8; i++) printf(" %2.2x", tulip_flash_in(ioaddr, i)); printf(".\n"); } #endif return 0; } static void tulip_eeprom(long ioaddr, int flags) { int eeprom_words = 64; int eeprom_change = 0; int i; /* Read the EEPROM. */ memset(eeprom_contents, 0, sizeof(eeprom_contents)); if (flags & DC21040_EEPROM) { outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ for (i = 0; i < 128; i++) { int value, boguscnt = 100000, sum = 0; do value = inl(ioaddr + CSR9); while (value < 0 && --boguscnt > 0); ((unsigned char *)eeprom_contents)[i] = value; if (i < 6) sum += value & 0xff; } } else if (flags & PNIC_EEPROM) { for (i = 0; i < eeprom_words; i++) { int value, boguscnt = 100000; u_int16_t sum; outl(0x600 | i, ioaddr + 0x98); do value = inl(ioaddr + CSR9); while (value < 0 && --boguscnt > 0); ((u_int16_t *)eeprom_contents)[i] = value; sum += value & 0xffff; } } else { u16 *eew = (u16 *)eeprom_contents; u16 andsum = 0xffff; int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6; eeprom_words = ee_addr_size == 8 ? 256 : 64; if (show_eeprom) printf("EEPROM %d words, %d address bits.\n", eeprom_words, ee_addr_size); for (i = 0; i < eeprom_words; i++) andsum &= (eew[i] = read_eeprom(ioaddr, i, ee_addr_size)); if (andsum == 0xffff) printf("WARNING: The EEPROM is missing or erased!\n"); } /* The user will usually want to see the interpreted EEPROM contents. */ if (show_eeprom || verbose > 1) { if (flags & DC21040_EEPROM) ; else if (flags & PNIC_MTABLE) liteon_eeprom((unsigned char *)eeprom_contents, flags); else if (flags & COMET_MACADDR) /* All ADMtek chips. */ admtek_eeprom((unsigned char *)eeprom_contents, flags); else if (flags & IS_CONEXANT) conexant_eeprom((unsigned char *)eeprom_contents, flags); else if (flags & IS_DAVICOM) davicom_eeprom((unsigned char *)eeprom_contents, flags); else parse_eeprom(ioaddr, (unsigned char *)eeprom_contents, flags); } if (show_eeprom > 1) { int block_crc = (calculate_checksum1(eeprom_contents, 8)>>8) & 0xff; int full_crc = (ether_crc_le((void*)eeprom_contents, 126) ^ 0xffff) & 0xffff; printf("EEPROM contents (%d words):", eeprom_words); for (i = 0; i < eeprom_words; i += 8) { int j; printf("\n0x%2.2x: ", i); for (j = 0; j < 8; j++) printf(" %4.4x", eeprom_contents[i + j]); printf(" "); for (j = 0; j < 8; j++) { int ew = eeprom_contents[i + j]; printf("%c%c", isprint(ew & 0xff) ? ew & 0xff : '_', isprint(ew >> 8) ? ew >> 8 : '_' ); } } printf("\n ID block CRC %#2.2x (vs. %#2.2x).\n" " Full contents CRC 0x%4.4x (read as 0x%4.4x).\n", block_crc, eeprom_contents[8] & 0xff, full_crc, eeprom_contents[63]); } /* Check for a bogus Intel CardBus card. */ if (eeprom_contents[0] == 0x8086 && eeprom_contents[1] == 0x0001 && eeprom_contents[2] == 0x0087) check_for_intel_cb(ioaddr, eeprom_contents); #if 0 if (emergency_rewrite) fprintf(stderr, "Configuration EEPROM overwrite is not available in " "this version of the diagnostic.\n"); #else if (emergency_rewrite && ! set_hwaddr) printf("*** Emergency EEPROM rewrite is only valid when you also " "specify a new\n*** station address with -H \n"); #endif if (set_hwaddr) { if (flags & PNIC_MTABLE) { /* int eeprom_sa_offset = 10; */ ; } else if (flags & COMET_MACADDR) { /* All ADMtek chips. */ u16 backup_ee_contents[] = { 0x0985, 0x0002, 0x0000, 0x0000, 0x0001, 0xd618, 0x126f, 0x0000, 0x0000, 0x0400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0985, 0x1317, 0x1216, 0x1113, 0x00e8, 0x0202, 0x0000, 0x80cc, }; int eeprom_sa_offset = 4; if (emergency_rewrite) memcpy(new_ee_contents, backup_ee_contents, sizeof backup_ee_contents); for (i = 0; i < 3; i++) new_ee_contents[i + eeprom_sa_offset] = (new_hwaddr[i*2]<<8) + new_hwaddr[i*2+1]; eeprom_change++; } else { fprintf(stderr, "Configuration EEPROM writing is not supported " "for this chip type.\n"); } } if (eeprom_change) { /* Enable EEPROM write, if the chip requires anything special. */ if (do_write_eeprom) { for (i = 0; i < eeprom_words; i++) if (new_ee_contents[i] != eeprom_contents[i]) { do_update(ioaddr, eeprom_contents, i, "configuration update", new_ee_contents[i]); } } else { printf("Would write %4.4x to replace %4.4x at %d.\n", new_ee_contents[i], eeprom_contents[i], i); } } if (new_default_media >= 0) { if (default_media_offset > 0) do_update(ioaddr, eeprom_contents, default_media_offset/2, "Default Media", mediamap[new_default_media].value); } } /* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ /* * This is not precisely a "delay" between EEPROM clock transitions, but * rather avoiding buffered PCI writes. */ #define eeprom_delay() inl(ee_addr) /* EEPROM_Ctrl bits. */ #define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ #define EE_CS 0x01 /* EEPROM chip select. */ #define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ #define EE_WRITE_0 0x4801 #define EE_WRITE_1 0x4805 #define EE_DATA_READ 0x08 /* EEPROM chip data out. */ #define EE_ENB (0x4800 | EE_CS) /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD (5) #define EE_READ_CMD (6) #define EE_ERASE_CMD (7) /* Note: this routine returns extra data bits for size detection. */ static int read_eeprom(long ioaddr, int location, int addr_len) { int i; unsigned retval = 0; long ee_addr = ioaddr + CSR9; int read_cmd = location | (EE_READ_CMD << addr_len); outl(EE_ENB & ~EE_CS, ee_addr); outl(EE_ENB, ee_addr); if (debug > 2) printf(" EEPROM read at %d ", location); /* Shift the read command bits out. */ for (i = 4 + addr_len; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; outl(EE_ENB | dataval, ee_addr); eeprom_delay(); outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(); if (debug > 2) printf("%X", inl(ee_addr) & 15); retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); } outl(EE_ENB, ee_addr); eeprom_delay(); if (debug > 2) printf(" :%X:", inl(ee_addr) & 15); for (i = 16; i > 0; i--) { outl(EE_ENB | EE_SHIFT_CLK, ee_addr); eeprom_delay(); if (debug > 2) printf("%X", inl(ee_addr) & 15); retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); outl(EE_ENB, ee_addr); eeprom_delay(); } /* Terminate the EEPROM access. */ outl(EE_ENB & ~EE_CS, ee_addr); if (debug > 2) printf(" EEPROM value at %d is %5.5x.\n", location, retval); return retval; } /* This executes a generic EEPROM command, typically a write or write enable. It returns the data output from the EEPROM, and thus may also be used for reads. */ static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len) { unsigned retval = 0; long ee_addr = ioaddr + CSR9; if (debug > 1) printf(" EEPROM op 0x%x: ", cmd); outl(EE_ENB | EE_SHIFT_CLK, ee_addr); /* Shift the command bits out. */ do { short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0; outl(dataval, ee_addr); eeprom_delay(); if (debug > 2) printf("%X", inl(ee_addr) & 15); outl(dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); } while (--cmd_len >= 0); outl(EE_ENB, ee_addr); /* Terminate the EEPROM access. */ outl(EE_ENB & ~EE_CS, ee_addr); if (debug > 1) printf(" EEPROM result is 0x%5.5x.\n", retval); return retval; } /* Read and write the MII registers using software-generated serial MDIO protocol. It is just different enough from the EEPROM protocol to not share code. The maxium data clock rate is 2.5 Mhz. */ /* Use a bus turn-around to avoid PCI write buffers pairing writes. */ #define mdio_delay() inl(mdio_addr) #define MDIO_SHIFT_CLK 0x10000 #define MDIO_DATA_WRITE0 0x00000 #define MDIO_DATA_WRITE1 0x20000 #define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ #define MDIO_ENB_IN 0x40000 #define MDIO_DATA_READ 0x80000 /* Syncronize the MII management interface by shifting 32 one bits out. */ static void mdio_sync(long ioaddr) { long mdio_addr = ioaddr + CSR9; int i; if (pcidev_tbl[current_part_idx].flags & (PNIC_MII|COMET_MII)) return; for (i = 32; i >= 0; i--) { outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); mdio_delay(); outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } return; } int mdio_read(long ioaddr, int phy_id, int location) { int i; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0, saved_0xfc = 0; long mdio_addr = ioaddr + CSR9; if (verbose > 2) /* Debug: 5 */ printf(" mdio_read(%#lx, %d, %d)..", ioaddr, phy_id, location); if (pcidev_tbl[current_part_idx].flags & PNIC_MII) { int i = 1000; outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); inl(ioaddr + 0xA0); inl(ioaddr + 0xA0); while (--i > 0) if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) break; if (debug) printf("Register at %#lx is %#x (%#x).\n", ioaddr, inl(ioaddr + 0xA0), retval & 0xffff); return retval & 0xffff; } if (pcidev_tbl[current_part_idx].flags & COMET_MII) { if (phy_id == 1) { if (location < 7) return inl(ioaddr + 0xB4 + (location<<2)); else if (location == 17) return inl(ioaddr + 0xD0); else if (location >= 29 && location <= 31) return inl(ioaddr + 0xD4 + ((location-29)<<2)); } return 0xffff; } if (pcidev_tbl[current_part_idx].flags & COMET_HPNA) { saved_0xfc = inl(ioaddr + 0xfc); if (phy_id == 1) outl(0x00, ioaddr + 0xfc); else if (phy_id == 2) outl(0x24, ioaddr + 0xfc); } /* Establish sync by sending at least 32 logic ones. */ for (i = 32; i >= 0; i--) { outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); mdio_delay(); outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Shift the read command bits out. */ for (i = 17; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; if (verbose > 3) /* Debug: 5 */ printf("%d", (read_cmd & (1 << i)) ? 1 : 0); outl(MDIO_ENB | dataval, mdio_addr); mdio_delay(); outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); if (verbose > 3) printf(" %x", (inl(mdio_addr) >> 16) & 0x0f); mdio_delay(); } if (verbose > 3) printf("-> %x", (inl(mdio_addr) >> 16) & 0x0f); /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { outl(MDIO_ENB_IN, mdio_addr); mdio_delay(); retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); if (verbose > 3) printf(" %x", (inl(mdio_addr) >> 16) & 0x0f); outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } if (verbose > 3) printf(" == %4.4x.\n", retval); if (pcidev_tbl[current_part_idx].flags & COMET_HPNA) outl(saved_0xfc, ioaddr + 0xfc); return (retval>>1) & 0xffff; } void mdio_write(long ioaddr, int phy_id, int location, int value) { int i; int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; long mdio_addr = ioaddr + CSR9; if (pcidev_tbl[current_part_idx].flags & COMET_MII) { if (phy_id == 1) { if (location < 7) outl(value, ioaddr + 0xB4 + (location<<2)); else if (location == 17) outl(value, ioaddr + 0xD0); else if (location >= 29 && location <= 31) outl(value, ioaddr + 0xD4 + ((location-29)<<2)); } return; } /* Establish sync by sending 32 logic ones. */ for (i = 32; i >= 0; i--) { outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); mdio_delay(); outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; outl(MDIO_ENB | dataval, mdio_addr); mdio_delay(); outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { outl(MDIO_ENB_IN, mdio_addr); mdio_delay(); outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } return; } #include const char *nway_state[8] = { "Autonegotiation disabled", "Transmit disabled", "Ability detect", "Acknowledge detect", "Complete acknowledge", "Negotiation complete", "Link check", "Invalid state" }; static void setup_nway_xcvr(long ioaddr) { int csr12 = inl(ioaddr + CSR12); int i; printf(" Internal autonegotiation state is '%s'.\n", nway_state[(csr12 >> 12) & 7]); if (opt_restart) { /* Restart NWay. */ int csr6 = inl(ioaddr + CSR6) & 0xFDFF; if (nway_advertise > 0) { int csr_setting = ((nway_advertise & 0x0380) << 9) | ((nway_advertise & 0x0020) << 1); if (verbose) printf("Setting 21142 N-Way advertisement to %4.4x " "(%x).\n", nway_advertise, csr_setting ); outl(0x000FFBF | csr_setting, ioaddr + CSR14); outl((nway_advertise & 0x0040 ? 0x82420200 : 0x82420000) | csr6, ioaddr + CSR6); } else { outl(0x0003FFFF, ioaddr + CSR14); outl(0x82420200 | csr6, ioaddr + CSR6); } #if 0 printf(" Writing the CSR15 direction bits.\n"); outl(0x08af0000, ioaddr + CSR15); outl(0x00050000, ioaddr + CSR15); #endif if (opt_reset) { printf(" Resetting the 21143 SIA registers.\n"); outl(0x0000, ioaddr + CSR13); outl(0x0001, ioaddr + CSR13); } outl(0x1000, ioaddr + CSR12); /* Start NWay. */ csr12 = inl(ioaddr + CSR12); printf(" Internal autonegotiation state is now '%s' CSR12 %x.\n" " CSR13 %x CSR14 %x CSR15 %x.\n", nway_state[(csr12 >> 12) & 7], csr12, inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); for (i = 0; i < 400; i++) { struct timeval sleepval; sleepval.tv_sec = 0; sleepval.tv_usec = 10000; select(0, 0, 0, 0, &sleepval); /* Or just sleep(1); */ if (csr12 != inl(ioaddr + CSR12)) { csr12 = inl(ioaddr + CSR12); printf(" Internal autonegotiation state is now '%s', " "CSR12 %x.\n" " CSR5 %x CSR13 %x CSR14 %x CSR15 %x.\n", nway_state[(csr12 >> 12) & 7], csr12, inl(ioaddr + CSR5), inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); } } printf(" Final autonegotiation state is '%s', CSR12 %x.\n" " CSR5 %x CSR13 %x CSR14 %x CSR15 %x.\n", nway_state[(inl(ioaddr + CSR12) >> 12) & 7], inl(ioaddr + CSR12), inl(ioaddr + CSR5), inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); /* We must explicitly switch to 100mbps mode. */ if (((nway_advertise > 0 ? nway_advertise : 0x01e1) & inl(ioaddr + CSR12) >> 16) & 0x0180) outl(0x83860200, ioaddr + CSR6); } } /* Calculate the EEPROM checksums. */ #define CRC1_POLYNOMIAL 0x07 /* x^8 + x^2 + x^1 + 1 */ static unsigned int calculate_checksum1(u_int16_t *eeprom, int len) { u16 crc = 0xffff; int i, bit; for (i = 0; i <= len; i++) /* Note: loc. 18 is the sum. */ for (bit = 15; bit >= 0; bit--) { /* Note: bits ordered as read from EEPROM */ crc <<= 1; if (((eeprom[i]>>bit) ^ (crc >> 8)) & 1) crc ^= CRC1_POLYNOMIAL; } return crc; } static unsigned const ethernet_polynomial_le = 0xedb88320U; static unsigned int ether_crc_le(void *ptr, int length) { unsigned char *data = ptr; unsigned int crc = 0xffffffff; /* Initial value. */ while(--length >= 0) { unsigned char current_octet = *data++; int bit; for (bit = 8; --bit >= 0; current_octet >>= 1) { if ((crc ^ current_octet) & 1) { crc >>= 1; crc ^= ethernet_polynomial_le; } else crc >>= 1; } } return crc; } int do_update(long ioaddr, u_int16_t *ee_values, int index, char *field_name, int new_value) { if (ee_values[index] == new_value) return 0; if (do_write_eeprom) { int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6; int i; u16 newval; printf("Writing new %s entry 0x%4.4x to offset %d.\n", field_name, new_value, index); /* Enable programming modes. */ do_eeprom_cmd(ioaddr, (0x4f << (ee_addr_size-4)), 3+ee_addr_size); /* Do the actual write. */ do_eeprom_cmd(ioaddr, (((EE_WRITE_CMD< 8 ? "" : blockname[blk_type] ? blockname[blk_type] : medianame[p[2] & 31], blk_type, p[0] & 0x7f); switch (blk_type) { case 0: printf(" AUI or SYM transceiver for %s (media type %d).\n" " CSR12 control port setting %#2.2x," " command 0x%2.2x 0x%2.2x.\n", medianame[p[2] & 31], p[2], p[3], p[5], p[4]); if (p[5] & 0x80) { printf(" No media-active status available.\n"); break; } printf(" Media detection by looking for a %d on bit %d of" " the CSR12 control port.\n", (p[4] & 0x80) ? 0 : 1, (p[4] >> 1) & 7); break; case 1: /* 21140 MII PHY*/ case 3: { /* 21142 MII PHY */ int init_length = p[3]; u16 *misc_info; printf(" MII interface PHY %d (media type 11).\n", p[2]); if (blk_type == 3) { /* 21142 */ u16 *init_sequence = (u16*)(p+4); u16 *reset_sequence = &((u16*)(p+5))[init_length]; int reset_length = p[4 + init_length*2]; misc_info = reset_sequence + reset_length; printf(" 21143 MII initialization sequence is %d " "words:", init_length); for (i = 0; i < init_length; i++) printf(" %4.4x", get_unaligned(init_sequence + i)); printf(".\n 21143 MII reset sequence is %d words:", reset_length); for (i = 0; i < reset_length; i++) printf(" %4.4x", get_unaligned(reset_sequence + i)); printf(".\n"); } else { u8 *init_sequence = p + 4; u8 *reset_sequence = p + 5 + init_length; int reset_length = p[4 + init_length]; misc_info = (u16*)(reset_sequence + reset_length); if (reset_length) { printf(" 21140 MII Reset sequence is %d words:", reset_length); for (i = 0; i < reset_length; i++) printf(" %2.2x", reset_sequence[i]); } else printf(" No MII reset sequence."); if (init_length) { printf(".\n 21140 MII initialization sequence is " "%d words:", init_length); for (i = 0; i < init_length; i++) printf(" %2.2x", init_sequence[i]); printf(".\n"); } else printf(" No MII initialization sequence.\n"); } printf(" Media capabilities are %4.4x, advertising %4.4x.\n" " Full-duplex map %4.4x, Threshold map %4.4x.\n", get_unaligned(misc_info + 0), get_unaligned(misc_info + 1) | 1, get_unaligned(misc_info + 2), get_unaligned(misc_info + 3)); if (blk_type == 3) { /* 21142 */ if ((*(u8 *)(misc_info+4)) > 0) printf(" MII interrupt on GPIO pin %d.\n", (*(u8 *)(misc_info+3)) - 1); else printf(" No MII interrupt.\n"); } has_mii++; break; } case 2: /* 21142 SYM or AUI */ case 4: printf(" %s transceiver for %s (media type %d).\n", blk_type == 2 ? "Serial" : "SYM", medianame[p[2] & 31], p[2]); if ( ! show_eeprom) break; if (p[2] & 0x40) printf(" CSR13 %2.2x%2.2x CSR14 %2.2x%2.2x" " CSR15 %2.2x%2.2x.\n GP pin direction " "%2.2x%2.2x GP pin data %2.2x%2.2x.\n", p[4], p[3], p[6], p[5], p[8], p[7], p[10], p[9], p[12], p[11]); else printf(" GP pin direction %2.2x%2.2x " "GP pin data %2.2x%2.2x.\n", p[4], p[3], p[6], p[5]); if (blk_type == 4) { if (p[8] & 0x80) printf(" No media detection indication (command " "%2.2x %2.2x).\n", p[8], p[7]); else printf(" Media detection by looking for a %d on " "general purpose pin %d.\n", (p[7] & 0x80) ? 0 : 1, (p[7] >> 1) & 7); } break; case 5: printf(" Transceiver Reset, sequence length %d:", p[2]); for( i = 0; i < p[2]; i++) printf(" %2.2x%2.2x", p[i*2 + 4], p[i*2 + 3]); printf(".\n"); if (opt_reset) { printf(" Performing a transceiver reset.\n"); for (i = 0; i < p[2]; i++) outw(((p[i*2 + 4]<<8) + p[i*2 + 3]) << 16, ioaddr + CSR15); printf(" New CSR15 value is %8.8x.\n", inl(ioaddr + CSR15)); } break; case 6: printf(" Disconnect reset for%s%s%s%s sequence length %d:", p[2] & 1 ? "Link fail, " : "", p[2] & 2 ? "D1 sleep, " : "", p[2] & 4 ? "D2 sleep, " : "", p[2] & 8 ? "D3 sleep, " : "", p[3]); for( i = 0; i < p[3]; i++) printf(" %2.2x%2.2x", p[i*2 + 5], p[i*2 + 4]); printf(".\n"); break; default: printf(" UNKNOW MEDIA DESCRIPTION BLOCK TYPE!\n "); for(i = 1; i <= (p[0] & 0x1f); i++) printf(" %2.2x", p[i]); printf(".\n"); break; } p += (p[0] & 0x3f) + 1; } else { /* "Compact" blocks (aka design screw-up). */ printf(" 21140 Non-MII transceiver for media %d (%s).\n" " CSR12 control port setting %#2.2x," " command %#2.2x %#2.2x.\n", p[0], medianame[p[0] & 31], p[1], p[3], p[2]); if (p[3] & 0x80) { printf(" No media-active status available.\n"); } else printf(" Media detection by looking for a %d on bit %d of" " the CSR12 control port.\n", (p[2] & 0x80) ? 0 : 1, (p[2] >> 1) & 7); p += 4; } } if (ee_data[19] >= 4) { /* Show the Magic Packet block. */ int b = 128 - 32; /* Magic Packet block offset */ int magic_cmd = ee_data[b + 12]; printf(" The Magic Packet address is " "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X.\n", ee_data[b + 6], ee_data[b + 7], ee_data[b + 8], ee_data[b + 9], ee_data[b + 10], ee_data[b + 11]); if (magic_cmd & 2) printf(" The Magic Packet password is " "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X.\n", ee_data[b + 0], ee_data[b + 1], ee_data[b + 2], ee_data[b + 3], ee_data[b + 4], ee_data[b + 5]); } } static void liteon_eeprom(unsigned char *ee_data, int part_idx) { printf(" Ethernet MAC Station Address " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", ee_data[20], ee_data[21], ee_data[22], ee_data[23], ee_data[24], ee_data[25]); /* Note: This code matches the documentation, but I suspect that it is the documentation that is byte-reversed. */ printf(" Wake-On-LAN ID bytes " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", ee_data[27], ee_data[26], ee_data[29], ee_data[28], ee_data[59], ee_data[58]); printf(" PCI Subsystem IDs Vendor %2.2x%2.2x Device %2.2x%2.2x\n", ee_data[93], ee_data[92], ee_data[90], ee_data[91]); } static struct alist { int num; const char *name; } admtek_media[] = { {0x0000, "10baseT"}, {0x0001, "BNC"}, {0x0002, "AUI"}, {0x0003, "100baseTx"}, {0x0004, "100baseT4"}, {0x0005, "100baseFx"}, {0x0010, "10baseT-FDX"}, {0x0013, "100baseTx-FDX"}, {0x0015, "100baseFx-FDX"}, {0x0100, "Autonegotiation"},{0x0200, "Power-on autosense"}, {0x0400, "Autosense"}, {0xFFFF, "Default"}, {0, ""}, }; static void admtek_eeprom(unsigned char *ee_data, int part_idx) { u_int16_t *eew = (void *)ee_data; int i; printf(" Ethernet MAC Station Address " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", ee_data[8], ee_data[9], ee_data[10], ee_data[11], ee_data[12], ee_data[13]); for (i = 0; admtek_media[i].name; i++) if (admtek_media[i].num == eew[0x09]) { printf(" Default connection type '%s'.\n", admtek_media[i].name); break; } if (admtek_media[i].name == NULL) printf(" Unknown default connection type '%#x'.\n", eew[0x09]); printf(" PCI IDs Vendor %4.4x Device %4.4x " " Subsystem %4.4x %4.4x\n", eew[0x11], eew[0x10], eew[0x13], eew[0x12]); printf(" PCI min_grant %d max_latency %d.\n", ee_data[0x28], ee_data[0x29]); printf(" CSR18 power-up setting 0x%4.4x****.\n", eew[0x17]); } static void conexant_eeprom(unsigned char *ee_data, int part_idx) { printf("Conexant EEPROM format is undocumented.\n"); } static void davicom_eeprom(unsigned char *ee_data, int part_idx) { printf("PCI Subsystem IDs, vendor %2.2x%2.2x, device %2.2x%2.2x.\n" "CardBus Information Structure at offset %2.2x%2.2x%2.2x%2.2x.\n", ee_data[1], ee_data[0], ee_data[3], ee_data[2], ee_data[7], ee_data[6], ee_data[5], ee_data[4]); printf(" Checksum: calculated %4.4x vs %4.4x from EEPROM.\n", ~ether_crc_le(ee_data, 126) & 0xffff, ee_data[63]); } static const char msg_no_station_addr[] = " However this card's station address could not be located in Card\n" " Information Structure, therefore no corrected EEPROM table information can\n" " be written.\n"; static const char msg_bogus_intel_eeprom[] = "You have an Intel CardBus card with an incomplete EEPROM!\n"; static void check_for_intel_cb(long ioaddr, u_int16_t *eeprom_contents) { unsigned const char cis_addr_prefix[4] = {0x22, 0x08, 0x04, 0x06}; unsigned const short media_ctrl_tbl[] = { 0x0103, 0x1100, 0x3322, 0x5544, 0x1e00, 0x0000, 0x0800, 0x8604, 0x0002, 0x08af, 0x00a5, 0x0286, 0xaf04, 0xa508, 0x8800, 0x0304, 0x08af, 0x00a5, 0x8061, 0x0488, 0xaf05, 0xa508, 0x6100, }; unsigned char cis_addr_tuple[10]; int i; if (eeprom_contents[9] == 0x0103) return; printf(msg_bogus_intel_eeprom); for (i = 0; i < 10; i++) cis_addr_tuple[i] = tulip_flash_in(ioaddr, 0xeb + i); if (memcmp(cis_addr_tuple, cis_addr_prefix, 4)) { printf(msg_no_station_addr); return; } printf("The station address is "); for (i = 0; i < 5; i++) printf("%2.2x:", cis_addr_tuple[4 + i]); printf("%2.2x\n", cis_addr_tuple[4 + i]); memcpy(new_ee_contents, eeprom_contents, 18); memcpy(new_ee_contents + 9, media_ctrl_tbl, sizeof(media_ctrl_tbl)); memcpy(new_ee_contents + 10, cis_addr_tuple + 4, 6); new_ee_contents[63] = (ether_crc_le(eeprom_contents, 126) ^ 0xffff) & 0xffff; printf("New EEPROM contents would be:"); for (i = 0; i < 64; i++) printf("%s %4.4x", (i & 7) == 0 ? "\n ":"", new_ee_contents[i]); printf("\n ID CRC %#2.2x (vs. %#2.2x), complete CRC %4.4x.\n", (calculate_checksum1(new_ee_contents, 8) >> 8) & 0xff, new_ee_contents[8] & 0xff, new_ee_contents[63]); if (do_write_eeprom) { for (i = 0; i < 64; i++) do_update(ioaddr, eeprom_contents, i, "Intel media table update", new_ee_contents[i]); } } /* * Local variables: * compile-command: "cc -O -Wall -Wstrict-prototypes -o tulip-diag tulip-diag.c `[ -f libmii.c ] && echo -DLIBMII libmii.c` `[ -f libflash.c ] && echo -DLIBFLASH libflash.c`" * simple-compile-command: "cc -O -o tulip-diag tulip-diag.c" * tab-width: 4 * c-indent-level: 4 * c-basic-offset: 4 * End: */ nictools-pci-1.3.8.orig/via-diag.c0000644000175000017500000007753210264222626015664 0ustar alainalain/* via-diag.c: Linux Diagnostic and setup code for the VIA Rhine chips. This is a diagnostic and EEPROM setup program for PCI adapters based on the following chips: VIA Rhine vt86c100, vt3043, vt6102, and vt6105 Ethernet controllers. Copyright 1998-2004 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 Updates and additional information available at http://www.scyld.com/diag/index.html http://scyld.com/expert/mii-status.html http://scyld.com/expert/NWay.html References http://www.via.com.tw/ Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. To use this code under other terms requires an explicit license from the copyright holder. */ static char *version_msg = "via-diag.c:v2.10 2/28/2005 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: via-diag [-aDEefFGhmqrRtvVwW] [-p ] [-[AF] ]\n" " For details and other options see http://www.scyld.com/diag/index.html\n"; static const char long_usage_msg[] = "Usage: %s [-aDfrRvVw] [-AF ] [-#]\n" "\n" " Show the internal state of a network adapter.\n" "\n" " The common usage is\n" " diag -aem\n" "\n" " Frequently used options are\n" " -a --show_all_registers Print all registers.\n" " -e --show-eeprom Dump EEPROM contents, \"-ee\" shows the details.\n" " -m --show_mii Print the MII transceiver state\n" " Using -mm monitors the link.\n" " -f --force Perform operation, even on a running NIC.\n" "\n" " To operate on a single NIC, or one that hasn't been automatically found:\n" " -# --card_num INDEX Operate on the specified card index.\n" " -p --port-base IOADDR Assume an adapter at the specified I/O address.\n" " -t --chip-type TYPE Specify adapter type (with '-p'), use '-1' to list.\n" "\n" " To change the persistent configuration EEPROM settings\n" " -G --parameters PARMS Set adapter-specific parameters.\n" " -H --new-hwaddr 01:23:45:67:89:ab\n" " Set a new hardware station address. Typically disabled for safety.\n" " -w --write-EEPROM Actually write the new settings into the EEPROM.\n" " To read and write the boot BIOS extension Flash ROM\n" " -B Show the first few bytes of the ROM\n" " -L FILE Load the Flash from FILE.\n" " -S FILE Store the Flash image to FILE.\n" "\n" " -D --debug\n" " -v --verbose Report each action taken.\n" " -V --version Emit version information.\n" "\n" " -A --advertise (See the mii-diag manual page.)\n" "\n"; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include #include #include /* The following are required only with unaligned field accesses. */ #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif /* No libmii.h or libflash.h yet, thus the declarations here. */ extern int show_mii_details(long ioaddr, int phy_id); extern int monitor_mii(long ioaddr, int phy_id); extern int flash_show(long addr_ioaddr, long data_ioaddr); extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename); extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename); extern int (*flash_in_hook)(long addr, int offset); extern void (*flash_out_hook)(long addr, int offset, int val); /* We should use __u8 .. __u32, but they are not always defined. */ typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; struct option longopts[] = { /* { name has_arg *flag val } */ {"card-num", 1, 0, '#'}, /* Operate on the specified card index. */ {"Advertise", 1, 0, 'A'}, {"base-address", 1, 0, 'p'}, {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Print a long usage message. */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"restart", 0, 0, 'r'}, /* Restart autonegotiation. */ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; extern int rhine_diag(int vend_id, int dev_id, long ioaddr, int part_idx); /* Chip-specific flags. Yes, it's grungy to have the enum here. */ enum rhine_flags { CanFlash=1, }; /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name from the kernel, a common name and the PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { const char *part_name; const char *proc_pci_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx); } pcidev_tbl[] = { {"VIA VT86C100A Rhine", " Ethernet controller: VIA Technologies Unknown device", 0x1106, 0x6100, 0xffff, 0, 128, rhine_diag}, {"VIA VT3043 Rhine", " Ethernet controller: VIA Technologies Unknown device", 0x1106, 0x3043, 0xffff, 0, 128, rhine_diag}, {"VIA VT6102 Rhine-II (type 3065)", 0, 0x1106, 0x3065, 0xffff, CanFlash, 256, rhine_diag}, {"VIA VT6105 Rhine-III (type 3053 prototype)", 0, 0x1106, 0x3053, 0xffff, CanFlash, 256, rhine_diag}, {"VIA VT6105 Rhine-III (type 3106)", 0, 0x1106, 0x3106, 0xffff, CanFlash, 256, rhine_diag}, { 0, 0, 0, 0}, }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int nway_advertise = 0, fixed_speed = -1; int new_default_media = -1; /* Valid with libflash only. */ static unsigned int opt_flash_show = 0; static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int emergency_rewrite = 0; static int scan_proc_pci(int card_num); static int parse_media_type(const char *capabilities); static int get_media_index(const char *name); /* Chip-specific options, if any, go here. */ int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:hH:mp:qrRt:vVwWBL:S:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'A': nway_advertise = parse_media_type(optarg); break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 16); break; case 'h': fprintf(stderr, long_usage_msg, argv[0]); return 0; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtoul(optarg, NULL, 16); break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case 'W': opt_watch++; break; case 'B': opt_flash_show++; break; case 'L': opt_flash_loadfile = optarg; break; case 'S': opt_flash_dumpfile = optarg; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("Network adapter diagnostic: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for parsed contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n" " See http://www.scyld.com/expert/irq-conflict.html for more information.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if ((pci_devid >> 16) != pcidev_tbl[i].vendor || (pci_devid & pcidev_tbl[i].device_mask) != pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].part_name; i++) if (pcidev_tbl[i].proc_pci_name && strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Convert a text media name to a NWay capability word. */ static int parse_media_type(const char *capabilities) { const char *mtypes[] = { "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD", "10baseT", "10baseT-FD", "10baseT-HD", 0, }; char *endptr; int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,}; int i; if (debug) fprintf(stderr, "Advertise string is '%s'.\n", capabilities); for (i = 0; mtypes[i]; i++) if (strcasecmp(mtypes[i], capabilities) == 0) return cap_map[i]; i = strtoul(capabilities, &endptr, 16); if (*endptr == 0 && 0 < i && i <= 0xffff) return i; fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities); return 0; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to indices. This matches the Digital Tulip SROM numbering, primarily because that is the most complete list. Other chips will have to map these number to their internal values. */ struct { char *name; int value; } mediamap[] = { { "10baseT", 0 }, { "10base2", 1 }, { "AUI", 2 }, { "100baseTx", 3 }, { "10baseT-FDX", 0x204 }, { "100baseTx-FDX", 0x205 }, { "100baseT4", 6 }, { "100baseFx", 7 }, { "100baseFx-FDX", 8 }, { "MII", 11 }, { "Autosense", 0x0800 }, { 0, 0 }, }; static int get_media_index(const char *name) { char *endptr; int i; if (! name) return -1; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) return i; i = strtol(name, &endptr, 0); if (*endptr == 0) return i; fprintf(stderr, "Invalid interface specified. It must be one of\n"); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %d %s\n", mediamap[i].value, mediamap[i].name); return -1; } /* Chip-specific section. */ /* The chip-specific section for the VIA Rhine. */ static int eeprom_addr_len(long ioaddr); static int read_eeprom(long ioaddr, int location, int addr_len); static void write_eeprom(long ioaddr, int index, int value, int addr_len); static void rhine_eeprom(unsigned short *ee_data); int mdio_read(long ioaddr, int phy_id, int location); void mdio_write(long ioaddr, int phy_id, int location, int value); /* Offsets to the various registers. Note if accesses must be longword aligned. */ enum register_offsets { StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08, IntrStatus=0x0C, IntrEnable=0x0E, MulticastFilter0=0x10, MulticastFilter1=0x14, RxRingPtr=0x18, TxRingPtr=0x1C, MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, EECtrl=0x74, Config=0x78, ConfigA=0x7A, RxMissed=0x7C, RxCRCErrs=0x7E, StickyHW=0x83, FlashAddr=0x8C, FlashWrite=0x8f, FlashStatus=0x90, FlashRead=0x91, WOLcrClr=0xA4, WOLcgClr=0xA4, PwrcsrClr=0xAC, }; /* Bits in the interrupt status/mask registers. */ enum intr_status_bits { IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020, IntrTxDone=0x0002, IntrTxAbort=0x0008, IntrTxUnderrun=0x0010, IntrPCIErr=0x0040, IntrStatsMax=0x0080, IntrRxEarly=0x0100, IntrMIIChange=0x0200, IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000, IntrTxAborted=0x2000, IntrLinkChange=0x4000, IntrRxWakeUp=0x8000, IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260, }; /* The textual names of the interrupt indications. */ static const char *intr_names[16] ={ "Rx Done event", "Tx Done event", "Rx error", "Tx abort", "Tx underrun", "Out of Rx buffers", "PCI bus fault", "Statistics counters full", "Rx partially done", "MII status changed", "Rx overflow", "Rx packet dropped", "No Rx buffers", "Tx aborted", "Link changed", "Rx Wakeup packet", }; /* Values read from the EEPROM, and a new image to write. */ #define MAX_EEPROM_SIZE 256 unsigned short eeprom_contents[MAX_EEPROM_SIZE]; unsigned short new_ee_contents[MAX_EEPROM_SIZE]; #define EEPROM_SA_OFFSET 0x00 #define EEPROM_CSUM_OFFSET 0 /* 0 means none. */ #ifdef LIBFLASH /* Support for Flash operations. */ static int rhine_flash_in(long ioaddr, int offset) { outw(offset, ioaddr + FlashAddr); outb(1, ioaddr + FlashStatus); return inb(ioaddr + FlashRead); } static void rhine_flash_out(long ioaddr, int offset, int val) { outw(offset, ioaddr + FlashAddr); outb(val, ioaddr + FlashWrite); outb(2, ioaddr + FlashStatus); return; } #endif /* A table for emitting the configuration of a register. */ struct config_name { int val, mask; const char*name;}; static struct config_name rcvr_mode[] = { {0x08, 0x1f, "Normal unicast"}, {0x0C, 0x1f, "Normal unicast and hashed multicast"}, {0x1C, 0x08, "Promiscuous"}, {0x00, 0x00, "Unknown/invalid"}, }; static struct config_name txmr_mode[] = { {0x00, 0xE6, "Normal transmit, 128 byte threshold"}, {0x20, 0xE6, "Normal transmit, 256 byte threshold"}, {0x40, 0xE6, "Normal transmit, Tx threshold increased to 512 bytes"}, {0x60, 0xE6, "Normal transmit, Tx threshold increased to 1024 bytes"}, {0x80, 0x86, "Normal transmit, transmitter set to store-and-forward"}, {0x02, 0x06, "Transmitter set to INTERNAL LOOPBACK!"}, {0x04, 0x06, "Transmitter set to ENDEC/MII LOOPBACK!"}, {0x06, 0x06, "Transmitter set to EXTERNAL LOOPBACK!"}, {0x00, 0x00, "Unknown/invalid"}, }; int rhine_diag(int vendor_id, int device_id, long ioaddr, int part_idx) { int flags = pcidev_tbl[part_idx].flags; /* Capabilities. */ int chip_active = 0; int rx_mode = inb(ioaddr + RxConfig); int tx_mode = inb(ioaddr + TxConfig); int chip_cmd = inw(ioaddr + ChipCmd); int ee_addr_len = 6, eeprom_size = 32; int i; if (! opt_f && inl(ioaddr) == 0xffffffff) { printf("This device does not appear to exist in I/O space.\n" "Perhaps it is set to ACPI power-off mode.\n" "To examine this device anyway use the '-f' flag.\n"); return 1; } /* Always show the basic status. */ printf(" Station address "); for (i = 0; i < 5; i++) printf("%2.2x:", inb(ioaddr + StationAddr + i)); printf("%2.2x.\n", inb(ioaddr + StationAddr + i)); printf(" Tx %sabled, Rx %sabled, %s-duplex (0x%4.4x).\n", chip_cmd & 0x10 ? "en" : "dis", chip_cmd & 0x08 ? "en" : "dis", chip_cmd & 0x0400 ? "full" : "half", chip_cmd); for (i = 0; rcvr_mode[i].mask; i++) if ((rx_mode & rcvr_mode[i].mask) == rcvr_mode[i].val) break; printf(" Receive mode is 0x%2.2x: %s.\n", rx_mode, rcvr_mode[i].name); for (i = 0; txmr_mode[i].mask; i++) if ((tx_mode & txmr_mode[i].mask) == txmr_mode[i].val) break; printf(" Transmit mode is 0x%2.2x: %s.\n", tx_mode, txmr_mode[i].name); if (verbose || show_regs) { unsigned intr_status; if (chip_active && !opt_f) { printf(" This device appears to be active, so some registers" " will not be read.\n" " To see all register values use the '-f' flag.\n"); } else chip_active = 0; /* Ignore the chip status with -f */ if (opt_a) { /* Reading some registers disrupts chip operation. */ char dont_read[8] = {0x00,0x00,0x00,0xce,0xfd,0xed,0x7d,0xff}; printf("%s chip registers at %#lx", pcidev_tbl[part_idx].part_name, ioaddr); for (i = 0; i < pcidev_tbl[part_idx].io_size; i += 4) { if ((i & 0x1f) == 0) printf("\n 0x%3.3X:", i); if (chip_active && (dont_read[i>>5]) & (1<<((i>>2) & 7))) printf(" ********"); else printf(" %8.8x", inl(ioaddr + i)); } printf("\n"); } intr_status = inw(ioaddr + IntrStatus); printf(" %snterrupt sources are pending (%4.4x).\n", (intr_status & 0x03ff) ? "I": "No i", inw(ioaddr + IntrStatus)); if (intr_status) { for (i = 0; i < 16; i++) if (intr_status & (1<= 0) { /* The Rhine has the questionable ability to 'lock' EEPROM access. EEPROM sizing cannot be done unless the EEPROM is unlocked. */ if (inb(ioaddr + EECtrl) & 0x80) { printf(" Access to the EEPROM has been disabled (0x%2.2x).\n" " Direct reading or writing is not possible.\n", inb(ioaddr + EECtrl)); eeprom_size = 32; for (i = 0; i < 6; i++) eeprom_contents[i] = inb(ioaddr + StationAddr + i); for (i = 0; i < 4; i++) eeprom_contents[i + 0x1a] = inb(ioaddr + Config + i); eeprom_contents[0x18] = inb(ioaddr + PCIBusConfig); eeprom_contents[0x19] = inb(ioaddr + PCIBusConfig + 1); eeprom_contents[0x1e] = eeprom_contents[0x1f] = 0x73; outb(0x00, ioaddr + EECtrl); } else { ee_addr_len = eeprom_addr_len(ioaddr); eeprom_size = 1 << ee_addr_len; for (i = 0; i < eeprom_size; i++) eeprom_contents[i] = read_eeprom(ioaddr, i, ee_addr_len); } } #if defined(HAS_EEPROM_RECOVERY) if (emergency_rewrite) fprintf(stderr, "Full EEPROM overwrite is not available in this" "version of the diagnostic.\n"); #else if (emergency_rewrite && ! set_hwaddr) printf("*** Emergency EEPROM rewrite is only valid when you also " "specify a new\n*** station address with -H \n"); #endif if (set_hwaddr) { memcpy(new_ee_contents, eeprom_contents, eeprom_size << 1); for (i = 0; i < 3; i++) new_ee_contents[i + EEPROM_SA_OFFSET] = (new_hwaddr[i*2]<<8) + new_hwaddr[i*2+1]; for (i = EEPROM_SA_OFFSET; i < EEPROM_SA_OFFSET + 3; i++) if (new_ee_contents[i] != eeprom_contents[i]) write_eeprom(ioaddr, i, new_ee_contents[i], ee_addr_len); #if defined(EEPROM_CSUM_OFFSET) && EEPROM_CSUM_OFFSET > 0 { /* Recalculate the checksum. */ unsigned short sum = 0; for (i = 0; i < EEPROM_CSUM_OFFSET; i++) sum ^= new_ee_contents[i]; new_ee_contents[EEPROM_CSUM_OFFSET] = (sum ^ (sum>>8)) & 0xff; write_eeprom(ioaddr, EEPROM_CSUM_OFFSET, sum, ee_addr_len); } #endif for (i = 0; i < eeprom_size; i++) eeprom_contents[i] = read_eeprom(ioaddr, i, ee_addr_len); } if (show_eeprom > 1) { printf("EEPROM contents%s:", inb(ioaddr + EECtrl) & 0x80 ? " (Assumed from chip registers)" : ""); for (i = 0; i < eeprom_size; i += 8) { int j; printf("\n0x%2.2x: ", i); for (j = 0; j < 8; j++) printf(" %4.4x", eeprom_contents[i + j]); if (show_eeprom > 2) { printf(" "); for (j = 0; j < 8; j++) { int ew = eeprom_contents[i + j]; printf("%c%c", isprint(ew & 0xff) ? ew & 0xff : '_', isprint(ew >> 8) ? ew >> 8 : '_' ); } } } printf("\n"); } if (show_eeprom) rhine_eeprom(eeprom_contents); if (show_mii) { int phys[4], phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(ioaddr, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { phys[phy_idx++] = phy; printf(" MII PHY found at address %d, status 0x%4.4x.\n", phy, mii_status); } } if (phy_idx == 0) printf(" ***WARNING***: No MII transceivers found!\n"); for (phy = 0; phy < phy_idx; phy++) { int mii_reg; printf(" MII PHY #%d transceiver registers:", phys[phy]); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mdio_read(ioaddr, phys[phy], mii_reg)); printf(".\n"); } #ifdef LIBMII show_mii_details(ioaddr, phys[0]); if (show_mii > 1) monitor_mii(ioaddr, phys[0]); #endif } if ((opt_flash_loadfile || opt_flash_dumpfile || opt_flash_show) && (CanFlash & flags) == 0) printf("This chip type does not support Flash access or " "programming.\n"); #ifndef LIBFLASH if (opt_flash_loadfile || opt_flash_dumpfile || opt_flash_show) printf("Flash operations not configured into this program.\n"); #else if (opt_flash_loadfile || opt_flash_dumpfile || opt_flash_show) { flash_in_hook = rhine_flash_in; flash_out_hook = rhine_flash_out; if (opt_flash_show) flash_show(ioaddr, 0); if (opt_flash_dumpfile) if (flash_dump(ioaddr, 0, opt_flash_dumpfile) < 0) { fprintf(stderr, "Failed to save the old Flash BootROM image " "into file '%s'.\n", opt_flash_dumpfile); return 3; } if (opt_flash_loadfile) if (flash_program(ioaddr, 0, opt_flash_loadfile) < 0) { fprintf(stderr, "Failed to load the new Flash BootROM image " "from file '%s'.\n", opt_flash_loadfile); return 4; } } #endif /* LIBFLASH support. */ return 0; } /* Serial EEPROM section. A "bit" grungy, but we work our way through bit-by-bit :->. */ /* The EEPROM commands always start with 01.. preamble bits. Commands are prepended to the variable-length address. */ enum EEPROM_Cmds { EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7, }; /* EEPROM_Ctrl bits. Some implementations have a data pin direction bit instead of separate data in and out bits. */ #define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ #define EE_CS 0x08 /* EEPROM chip select. */ #define EE_DATA_WRITE 0x02 /* Data into EEPROM chip. */ #define EE_DATA_READ 0x01 /* Data out of EEPROM chip. */ /* These are generally derived from the bits above. */ #define EE_ENB (EE_CS) #define EE_WRITE_0 (EE_CS) #define EE_WRITE_1 (EE_CS | EE_DATA_WRITE) #define EE_OFFSET EECtrl /* Register offset in I/O space. */ enum EEPROM_Ctrl_Bits { EE_ShiftClk=0x04, EE_ChipSelect=0x08, EE_DataOut=0x02, EE_DataIn=0x01, EE_Write0=0x08, EE_Write1=0x0A, }; /* Delay between EEPROM clock transitions. This forces out buffered PCI writes. */ #define eeprom_delay(ee_addr) inb(ee_addr) /* Execute a generic EEPROM command. Return all data output from the EEPROM, and thus may be used for EEPROM sizing, read, erase or write. */ static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len) { unsigned retval = 0; long ee_addr = ioaddr + EE_OFFSET; if (debug > 1) printf(" EEPROM op 0x%x: ", cmd); outb(EE_ChipSelect | EE_ShiftClk, ee_addr); /* Shift the command bits out. */ do { short dataval = (cmd & (1 << cmd_len)) ? EE_Write1 : EE_Write0; outb(dataval, ee_addr); eeprom_delay(ee_addr); if (debug > 2) printf("%X", inb(ee_addr) & 15); outb(dataval | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); retval = (retval << 1) | ((inb(ee_addr) & EE_DataIn) ? 1 : 0); } while (--cmd_len >= 0); outb(EE_ChipSelect, ee_addr); /* Terminate the EEPROM access. */ outb(EE_ENB & ~EE_CS, ee_addr); if (debug > 1) printf(" EEPROM result is 0x%5.5x.\n", retval); return retval; } /* Wait for the EEPROM to finish what it is doing. */ static int eeprom_busy_poll(long ee_ioaddr) { int i; outb(EE_ChipSelect, ee_ioaddr); for (i = 0; i < 10000; i++) /* Typical 2000 ticks */ if (inb(ee_ioaddr) & EE_DataIn) break; return i; } /* The abstracted functions for EEPROM access. */ /* Return the number of address bits this EEPROM accepts. */ static int eeprom_addr_len(long ioaddr) { return do_eeprom_cmd(ioaddr, EE_ReadCmd << (6+16), 3 + 6 + 16) & 0x10000 ? 8 : 6; } static int read_eeprom(long ioaddr, int location, int addr_len) { return do_eeprom_cmd(ioaddr, ((EE_ReadCmd << addr_len) | location) << 16, 3 + addr_len + 16) & 0xffff; } static void write_eeprom(long ioaddr, int index, int value, int addr_len) { long ee_ioaddr = ioaddr + EE_OFFSET; int i; /* Poll for previous op finished. */ eeprom_busy_poll(ee_ioaddr); /* Enable programming modes. */ do_eeprom_cmd(ioaddr, (0x4f << (addr_len-4)), 3 + addr_len); /* Do the actual write. */ do_eeprom_cmd(ioaddr, (((EE_WriteCmd<>8, ee_data[1] & 0xff, ee_data[1]>>8, ee_data[2] & 0xff, ee_data[2]>>8, ee_data[3] & 0xff, /* PHY */ ee_data[5], ee_data[4], /* Subsystem */ ee_data[7], ee_data[6], /* Subsystem */ ee_data[11] & 0xff, ee_data[11]>>8, /* PCI bus config */ checksum & 0xff, ee_data[15] >> 8); return; } /* MII - MDIO (Media Independent Interface - Management Data I/O) accesses. */ int mdio_read(long ioaddr, int phy_id, int regnum) { int boguscnt = 1024; if (verbose > 2) /* Debug: 5 */ printf(" mdio_read(%#lx, %d, %d)..", ioaddr, phy_id, regnum); /* Wait for a previous command to complete. */ while ((inb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) ; outb(0x00, ioaddr + MIICmd); outb(phy_id, ioaddr + MIIPhyAddr); outb(regnum, ioaddr + MIIRegAddr); outb(0x40, ioaddr + MIICmd); /* Trigger read */ boguscnt = 1024; while ((inb(ioaddr + MIICmd) & 0x40) && --boguscnt > 0) ; return inw(ioaddr + MIIData); } void mdio_write(long ioaddr, int phy_id, int regnum, int value) { int boguscnt = 1024; /* Wait for a previous command to complete. */ while ((inb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) ; outb(0x00, ioaddr + MIICmd); outb(phy_id, ioaddr + MIIPhyAddr); outb(regnum, ioaddr + MIIRegAddr); outw(value, ioaddr + MIIData); outb(0x20, ioaddr + MIICmd); /* Trigger write. */ return; } /* * Local variables: * compile-command: "cc -O -Wall -o via-diag via-diag.c" * tab-width: 4 * c-indent-level: 4 * c-basic-offset: 4 * End: */ nictools-pci-1.3.8.orig/vortex-diag.c0000644000175000017500000013031010264222626016414 0ustar alainalain/* vortex-diag.c: Diagnostics/EEPROM setup for the 3Com Vortex series. This is a diagnostic and EEPROM setup program for Ethernet adapters based on the 3Com Vortex, Boomerang and Cyclone chips, as used on the 3Com 3c590/595/900/905/920 PCI EtherLink XL adapters. Copyright 1997-2004 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 Updates and additional information available at http://www.scyld.com/diag/index.html http://scyld.com/expert/mii-status.html http://scyld.com/expert/NWay.html Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. To use this code under other terms requires an explicit license from the copyright holder. References 3Com Vortex Engineering Release Specification 3Com Boomerang modifications (unreleased) http://www.national.com/pf/DP/DP83840.html */ static char *version_msg = "vortex-diag.c:v2.16 1/12/2004 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: vortex-diag [-aDEefFgGhmPqrRtvVwW] [-p ] [-[AF] ]\n" " For details and other options see http://www.scyld.com/diag/index.html\n"; static const char long_usage_msg[] = "Usage: %s [-aDfrRvVw] [-AF ] [-#]\n" "\n" " Show the internal state of a network adapter.\n" "\n" " The common usage is\n" " vortex-diag -aem\n" "\n" " Frequently used options are\n" " -a --show_all_registers Print all registers.\n" " -e --show-eeprom Dump EEPROM contents, \"-ee\" shows the details.\n" " -m --show_mii Print the MII transceiver state\n" " Using -mm monitors the link.\n" " -f --force Perform operation, even on a running NIC.\n" "\n" " To operate on a single NIC, or one that hasn't been automatically found:\n" " -# --card_num INDEX Operate on the specified card index.\n" " -p --port-base IOADDR Assume an adapter at the specified I/O address.\n" " -t --chip-type TYPE Specify adapter type (with '-p'), use '-1' to list.\n" "\n" " To change the persistent EEPROM settings\n" " -G --parameters PARMS Set adapter-specific parameters.\n" " -H --new-hwaddr 01:23:45:67:89:ab\n" " Set a new hardware station address. Read the documentation first!\n" " -w --write-EEPROM Actually write the new settings into the EEPROM.\n" " To read and write the boot BIOS extension Flash ROM\n" " -B Show the first few bytes of the ROM\n" " -L FILE Load the Flash from FILE.\n" " -S FILE Store the Flash image to FILE.\n" "\n" " -D --debug\n" " -v --verbose Report each action taken.\n" " -V --version Emit version information.\n" "\n" " -A --advertise (See the mii-diag manual page.)\n" "\n"; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif /* No libmii.h or libflash.h yet, thus the declarations here. */ extern int show_mii_details(long ioaddr, int phy_id); extern int monitor_mii(long ioaddr, int phy_id); extern int flash_show(long addr_ioaddr, long data_ioaddr); extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename); extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename); extern int (*flash_in_hook)(long addr, int offset); extern void (*flash_out_hook)(long addr, int offset, int val); /* We should use __u8 .. __u32, but they are not always defined. */ typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; struct option longopts[] = { /* { name has_arg *flag val } */ {"card-num", 1, 0, '#'}, /* Operate on the specified card index. */ {"Advertise", 1, 0, 'A'}, {"base-address", 1, 0, 'p'}, {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Print a long usage message. */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"restart", 0, 0, 'r'}, /* Restart autonegotiation. */ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; extern int vortex_diag(int vend_id, int dev_id, long ioaddr, int part_idx); /* Chip-specific flags. Yes, it's grungy to have the enum here. */ enum { HAS_FLASH_BUG=1, ROADRUNNER=2, IS_CYCLONE=4 }; /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name from the kernel, a common name and the PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { const char *part_name; const char *proc_pci_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx); } pcidev_tbl[] = { {"3Com Generic Vortex/Boomerag/Cyclone", 0, 0x10B7, 0x9999, 0xffff, 0, 256, vortex_diag}, {"3Com 3c590 Vortex 10Mbps", "3Com Vortex (rev ", 0x10B7, 0x5900, 0xffff, 0, 32, vortex_diag}, {"3c592 EISA 10mbps Demon/Vortex", 0, 0x10B7, 0x5920, 0xffff, 0, 32, vortex_diag}, {"3Com 3c595 Vortex 10/100baseTx", "3Com Vortex (rev ", 0x10B7, 0x5950, 0xffff, 0, 32, vortex_diag}, {"3Com 3c595 Vortex 10/100baseT4", 0, 0x10B7, 0x5951, 0xffff, 0, 32, vortex_diag}, {"3Com 3c595 Vortex 10/100baseT-MII", 0, 0x10B7, 0x5952, 0xffff, 0, 32, vortex_diag}, {"3c597 EISA Fast Demon/Vortex", 0, 0x10B7, 0x5970, 0xffff, 0, 32, vortex_diag}, {"3c900 Boomerang 10baseT", "3Com 3C900", 0x10B7, 0x9000, 0xffff, 0, 64, vortex_diag}, {"3c900 Boomerang 10Mbps Combo", 0, 0x10B7, 0x9001, 0xffff, 0, 64, vortex_diag}, {"3c900 Cyclone 10Mbps TPO", 0, 0x10B7, 0x9004, 0xffff, IS_CYCLONE, 256, vortex_diag}, {"3c900 Cyclone 10Mbps Combo", 0, 0x10B7, 0x9005, 0xffff, IS_CYCLONE, 256, vortex_diag}, {"3c900 Cyclone 10Mbps TPC", 0, 0x10B7, 0x9006, 0xffff, IS_CYCLONE, 256, vortex_diag}, {"3c905 Boomerang 100baseTx", "3Com 3C905", 0x10B7, 0x9050, 0xffff, 0, 64, vortex_diag}, {"3c905 Boomerang 100baseT4", 0, 0x10B7, 0x9051, 0xffff, 0, 64, vortex_diag}, {"3c905B Cyclone 100baseTx", 0, 0x10B7, 0x9055, 0xffff, HAS_FLASH_BUG | IS_CYCLONE, 256, vortex_diag}, {"3c905B Cyclone 10/100/BNC", "3Com 3C905BNC", 0x10B7, 0x9058, 0xffff, HAS_FLASH_BUG | IS_CYCLONE, 256, vortex_diag}, {"3c905B Cyclone 100baseFx", "3Com 3C905B-FX", 0x10B7, 0x905A, 0xffff, HAS_FLASH_BUG | IS_CYCLONE, 256, vortex_diag}, {"3c920 (Type 920-2) Cyclone", 0, 0x10B7, 0x9202, 0xffff, HAS_FLASH_BUG | IS_CYCLONE, 256, vortex_diag}, {"3c920 Series NIC", 0, 0x10B7, 0x9200, 0xff00, HAS_FLASH_BUG | IS_CYCLONE, 256, vortex_diag}, {"3c980 Cyclone, server edition", 0, 0x10B7, 0x9800, 0xffff, HAS_FLASH_BUG | IS_CYCLONE, 256, vortex_diag}, {"3c982 Dual Port server NIC", 0, 0x10B7, 0x9805, 0xffff, HAS_FLASH_BUG | IS_CYCLONE, 256, vortex_diag}, {"3c980 series, server edition", 0, 0x10B7, 0x9800, 0xfff0, HAS_FLASH_BUG | IS_CYCLONE, 256, vortex_diag}, {"3Com 3cSOHO100-TX", 0, 0x10B7, 0x7646, 0xff00, HAS_FLASH_BUG | IS_CYCLONE, 256, vortex_diag}, {"3c450 HomePNA Cyclone", 0, 0x10B7, 0x4500, 0xffff, IS_CYCLONE, 256, vortex_diag}, {"3c555 Laptop Hurricane", 0, 0x10B7, 0x5055, 0xffff, HAS_FLASH_BUG, 256, vortex_diag}, {"3c556 Laptop Hurricane", 0, 0x10B7, 0x6055, 0xffff, 0, 256, vortex_diag}, {"3c566 Laptop Tornado", 0, 0x10B7, 0x6056, 0xffff, 0, 256, vortex_diag}, {"3Com 3CCFE556", "3ccfe556 Roadrunner PCMCIA", 0x10B7, 0x0556, 0xffff, ROADRUNNER, 32, vortex_diag}, {"3c575 CardBus", 0, 0x10B7, 0x5057, 0xffff, HAS_FLASH_BUG | IS_CYCLONE, 32, vortex_diag}, {"3CCFE575BT CardBus", 0, 0x10B7, 0x5157, 0xffff, HAS_FLASH_BUG | IS_CYCLONE, 128, vortex_diag}, {"3CCFE575CT CardBus", 0, 0x10B7, 0x5257, 0xffff, HAS_FLASH_BUG | IS_CYCLONE, 128, vortex_diag}, {"3C575 CardBus (unknown version)", 0, 0x10B7, 0x5057, 0x0fff, HAS_FLASH_BUG, 32, vortex_diag}, {"3ccfe656 Cyclone CardBus", 0, 0x10B7, 0x6560, 0xffff, HAS_FLASH_BUG | IS_CYCLONE, 256, vortex_diag}, {"3Com 3CCFE656B Cyclone+WinModem CardBus", 0, 0x10B7, 0x6562, 0xffff, HAS_FLASH_BUG | IS_CYCLONE, 256, vortex_diag}, {"3Com 3CCFE656C Tornado CardBus", 0, 0x10B7, 0x6564, 0xffff, HAS_FLASH_BUG | IS_CYCLONE, 256, vortex_diag}, {"3Com 3CCFE656 Series", 0, 0x10B7, 0x6560, 0xfff0, HAS_FLASH_BUG | IS_CYCLONE, 256, vortex_diag}, /* Added most new/unverified entries here. */ { 0, 0, 0, 0}, }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int nway_advertise = 0, fixed_speed = -1; int new_default_media = -1; static unsigned int opt_flash_show = 0; static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int emergency_rewrite = 0; static unsigned set_ee_rom = 0; static int opt_dma_diag = 0; static int scan_proc_pci(int card_num); static int parse_media_type(const char *capabilities); static int get_media_index(const char *name); int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:gG:hH:mp:PqrRt:vVwWBL:S:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'A': nway_advertise = parse_media_type(optarg); break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'g': opt_dma_diag++; break; case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 0); break; case 'h': fprintf(stderr, long_usage_msg, argv[0]); return 0; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtoul(optarg, NULL, 16); break; case 'P': set_ee_rom++; break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case 'W': opt_watch++; break; case 'B': opt_flash_show++; break; case 'L': opt_flash_loadfile = optarg; break; case 'S': opt_flash_dumpfile = optarg; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("Network adapter diagnostic: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for parsed contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n" " See http://www.scyld.com/expert/irq-conflict.html for more information.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if ((pci_devid >> 16) != pcidev_tbl[i].vendor || (pci_devid & pcidev_tbl[i].device_mask) != pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].part_name; i++) if (pcidev_tbl[i].proc_pci_name && strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Convert a text media name to a NWay capability word. */ static int parse_media_type(const char *capabilities) { const char *mtypes[] = { "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD", "10baseT", "10baseT-FD", "10baseT-HD", 0, }; char *endptr; int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,}; int i; if (debug) fprintf(stderr, "Advertise string is '%s'.\n", capabilities); for (i = 0; mtypes[i]; i++) if (strcasecmp(mtypes[i], capabilities) == 0) return cap_map[i]; i = strtoul(capabilities, &endptr, 16); if (*endptr == 0 && 0 < i && i <= 0xffff) return i; fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities); return 0; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to EEPROM setting. These match the 3Com internal values. */ struct { int value; char *name; } mediamap[] = { { 0, "10baseT-serial"}, { 1, "10Mbps-AUI"}, { 3, "10base2"}, { 5, "100baseFx"}, { 6, "MII/100baseT4"}, { 8, "Autonegotiation"}, { 0, 0 }, }; static int get_media_index(const char *name) { char *endptr; int i; if (! name) return -1; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) return i; i = strtol(name, &endptr, 0); if (*endptr == 0) return i; fprintf(stderr, "Invalid interface specified. It must be one of\n"); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %d %s\n", mediamap[i].value, mediamap[i].name); return -1; } /* Chip-specific section. */ /* The 3Com Vortex/Boomerang/Cyclone designs. */ static void interpret_eeprom(long ioaddr); static void mdio_sync(long ioaddr); int mdio_read(long ioaddr, int phy_id, int location); void mdio_write(long ioaddr, int phy_id, int location, int value); static void show_dma_state(long ioaddr); int vortex_flash_in(long addr, int offset); void vortex_flash_out(long addr, int offset, int val); #define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) #define EL3_CMD 0x0e enum vortex_cmd { TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11, RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, UpStall = 6<<11, UpUnstall = (6<<11)+1, DownStall = (6<<11)+2, DownUnstall = (6<<11)+3, RxDiscard = 8<<11, TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11, FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11, SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11, SetTxThreshold = 18<<11, SetTxStart = 19<<11, StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11, StatsDisable = 22<<11, StopCoax = 23<<11, SetFilterBit = 25<<11, }; /* Bits in the general status register. */ enum vortex_status { IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004, TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020, IntReq = 0x0040, StatsFull = 0x0080, DMADone = 1<<8, DownComplete = 1<<9, UpComplete = 1<<10, DMAInProgress = 1<<11, /* DMA controller is still busy.*/ CmdInProgress = 1<<12, /* EL3_CMD is still busy.*/ }; const char *intr_names[13] ={ "Interrupt latch", "Adapter Failure", "Tx Complete", "Tx Available", "Rx Complete", "Rx Early Notice", "Driver Intr Request", "Statistics Full", "DMA Done", "Download Complete", "Upload Complete", "DMA in Progress", "Command in Progress", }; enum Window0 { Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */ Wn0EepromData = 12, /* Window 0: EEPROM results register. */ IntrStatus=0x0E, /* Valid in all windows. */ }; #define MAX_EEPROM_SIZE 256 /* In undocumented bogusness, these value depend on the EEPROM size. */ enum Win0_EEPROM_cmds { EEPROM_Read = 2, EEPROM_WRITE = 1, EEPROM_ERASE = 3, EEPROM_EWENB = 0xC, /* Enable erasing/writing for 10 msec. */ EEPROM_EWDIS = 0x0, /* Disable EWENB before 10 msec timeout. */ }; enum Window2 { Wn2_ResetOptions=12, }; enum Window3 { /* Window 3: MAC/config bits. */ Wn3_Config=0, Wn3_MaxPktSz=4, Wn3_MAC_Ctrl=6, Wn3_Options=8, }; enum Window4 { /* Window 4: Xcvr/media bits. */ Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10, }; enum Window5 { Wn5_TxThreshold = 0, Wn5_RxFilter = 8, }; /* Media names in Wn3_Config bits 24:20. */ const char *el_medianames[16] ={ "10baseT", "10Mbs AUI", "undefined", "10base2", "100baseTX", "100baseFX", "MII", "undefined", "Autonegotiate", "MII-External", "undefined-10", "undefined-11", "undefined-12", "undefined-13", "undefined-14", "undefined-15", }; /* Media available in Wn3_Options and EEPROM. */ const char *medias[] = { "100baseT4", "100baseTx", "100baseFx", "10baseT", "10base2", "AUI", "MII", "", "10baseFL" }; struct config_name { int val, mask; const char*name;} /* Bits in Wn5_RxFilter. */ static rcvr_mode[] = { {0x05, 0x1f, "Normal unicast"}, {0x15, 0x1f, "Normal unicast and hashed multicast"}, {0x07, 0x0f, "Normal unicast and all multicast"}, {0x08, 0x08, "Promiscuous"}, {0x00, 0x00, "Unknown/invalid"}, }; /* Values read from the EEPROM, and the new image. */ unsigned short eeprom_contents[MAX_EEPROM_SIZE]; unsigned short new_ee_contents[MAX_EEPROM_SIZE]; int vortex_diag(int vendor_id, int dev_id, long ioaddr, int part_idx) { int chip_active = 0; int saved_window = inw(ioaddr + EL3_CMD) >> 13; int flags = pcidev_tbl[part_idx].flags; int internal_config, rx_mode; int i; /* It's mostly safe to examine the registers and EEPROM during operation. But warn the user, and make then pass '-f'. */ #ifdef notdef if ((inl(ioaddr + EL3_CMD) & 0xE000) == 0xE000) chip_active = 1; #endif EL3WINDOW(2); printf(" Station address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", inb(ioaddr + 0), inb(ioaddr + 1), inb(ioaddr + 2), inb(ioaddr + 3), inb(ioaddr + 4), inb(ioaddr + 5)); EL3WINDOW(5); rx_mode = inb(ioaddr + Wn5_RxFilter); for (i = 0; rcvr_mode[i].mask; i++) if ((rx_mode & rcvr_mode[i].mask) == rcvr_mode[i].val) break; printf(" Receive mode is 0x%2.2x: %s.\n", rx_mode, rcvr_mode[i].name); if (opt_a) { int io_size = pcidev_tbl[part_idx].io_size; int j; if (!opt_f) { printf("The Vortex chip may be active, so FIFO registers" " will not be read.\n" "To see all register values use the '-f' flag.\n"); } else chip_active = 0; /* Ignore the chip status with -f */ printf("Initial window %d, registers values by window:\n", saved_window); for (j = 0; j < 8; j++) { printf(" Window %d:", j); outw(SelectWindow + j, ioaddr + EL3_CMD); for (i = 0; i < 16; i+=2) { if (j == 1 && i < 4 && ! opt_f) printf(" FIFO"); else printf(" %4.4x", inw(ioaddr + i)); } printf(".\n"); } printf("Vortex chip registers at %#lx", ioaddr); if (io_size > 0x80) io_size = 0x80; for (i = 0x10; i < io_size; i += 4) { if ((i & 0x0f) == 0) printf("\n 0x%3.3lX:", ioaddr + i); if (! opt_f) { if (i == 0x10) printf(" **FIFO**"); else if (i == 0x1c) printf(" *STATUS*"); else printf(" %8.8x", (int)inl(ioaddr + i)); } else printf(" %8.8x", (int)inl(ioaddr + i)); } printf("\n"); if (opt_dma_diag || (flags & IS_CYCLONE)) show_dma_state(ioaddr); } if (opt_G) { #if defined(OPTG_MULTICAST) printf("Setting filter bit, %4.4x.\n", SetFilterBit|0x0400|opt_GPIO); outw(SetRxFilter | 0x15, ioaddr + EL3_CMD); for (i = 0; i < 255; i++) outw(SetFilterBit|0x0000|i, ioaddr + EL3_CMD); outw(SetFilterBit|0x0400|opt_GPIO, ioaddr + EL3_CMD); #elif defined(OPTG_RXTHRESH) printf("Setting the Rx Priority Thrshold to %d bytes.\n", opt_GPIO); outb((opt_GPIO + 0x1f)>>5, ioaddr + 0x3C); printf("Setting the Rx Priority Thrshold to %d bytes.\n", inb(ioaddr + 0x3C)<<5); #else EL3WINDOW(2); outw(opt_GPIO, ioaddr + Wn2_ResetOptions); #endif } EL3WINDOW(3); internal_config = inl(ioaddr + Wn3_Config); if (verbose > 1 || opt_a) { unsigned intr_status = inw(ioaddr + IntrStatus); EL3WINDOW(5); printf(" Indication enable is %4.4x, interrupt enable is %4.4x.\n", inw(ioaddr + 12), inw(ioaddr + 10)); printf(" %snterrupt sources are pending.\n", (intr_status & 0x03ff) ? "I": "No i"); if (intr_status) { for (i = 0; i < 13; i++) if (intr_status & (1<> 20) & 15]); MacCtrl = inw(ioaddr + Wn3_MAC_Ctrl); printf(" MAC settings: %s-duplex%s%s%s.\n", MacCtrl & 0x020 ? "full":"half", MacCtrl & 0x040 ? ", Large packets permitted":"", MacCtrl & 0x100 ? ", 802.1Q flow control":"", MacCtrl & 0x200 ? ", VLT VLAN enabled":""); if (inw(ioaddr + Wn3_MaxPktSz) != 1514) printf("Maximum packet size is %d.\n", inw(ioaddr + Wn3_MaxPktSz)); } EL3WINDOW(2); printf(" Station address set to %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", inb(ioaddr + 0), inb(ioaddr + 1), inb(ioaddr + 2), inb(ioaddr + 3), inb(ioaddr + 4), inb(ioaddr + 5)); /* This register only exists on certain Cyclone chips. */ printf(" Configuration options %4.4x.\n", inw(ioaddr + Wn2_ResetOptions)); } interpret_eeprom(ioaddr); /* Show up to four (not just the on-board) PHYs. */ if (verbose > 1 || show_mii) { int phys[4], phy, phy_idx = 0; int mii_reg; int saved_media_options; phys[0] = 24; /* Default for most 3Com products. */ EL3WINDOW(3); /* Turn on the MII transceiver for some cards. */ saved_media_options = inw(ioaddr + Wn3_Options); outw((saved_media_options & 0x1ff) | 0x8000, ioaddr + Wn3_Options); EL3WINDOW(4); mdio_sync(ioaddr); for (phy = 1; phy <= 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(ioaddr, phy & 0x1f, 1); if (mii_status != 0xffff && mii_status != 0) { phys[phy_idx++] = phy&0x1f; printf(" MII PHY found at address %d, status %4.4x.\n", phy & 0x1f, mii_status); } } if (phy_idx == 0) printf(" ***WARNING***: No MII transceivers found!\n"); for (phy = 0; phy < phy_idx; phy++) { printf(" MII PHY %d at #%d transceiver registers:", phy, phys[phy]); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mdio_read(ioaddr, phys[phy], mii_reg)); printf(".\n"); } if (opt_reset) { printf("Resetting the transceiver...\n"); mdio_write(ioaddr, phys[phy], 0, 0x8000); } if (phy_idx && nway_advertise > 0) { printf(" Setting the media capability advertisement register of " "PHY #%d to 0x%4.4x.\n", phys[0], nway_advertise | 1); mdio_write(ioaddr, phys[0], 4, nway_advertise | 1); } if (opt_restart) { printf("Restarting negotiation...\n"); mdio_write(ioaddr, phys[0], 0, 0x0000); mdio_write(ioaddr, phys[0], 0, 0x1200); } /* To force 100baseTx-HD do mdio_write(ioaddr, phys[0], 0, 0x2000); */ if (fixed_speed >= 0) { int reg0_val = 0; reg0_val |= (fixed_speed & 0x0180) ? 0x2000 : 0; reg0_val |= (fixed_speed & 0x0140) ? 0x0100 : 0; printf("Setting the speed to \"fixed\", %4.4x.\n", reg0_val); mdio_write(ioaddr, phys[0], 0, reg0_val); } #ifdef LIBMII if (show_mii > 1) show_mii_details(ioaddr, phys[0]); if (opt_watch || show_mii > 2) monitor_mii(ioaddr, phys[0]); #endif EL3WINDOW(3); outw(saved_media_options, ioaddr + Wn3_Options); } #ifdef LIBFLASH /* First, work around a chip buglet: the media must be set to EXT MII to read the flash on one Hurricane rev. */ /* Turn on the MII transceiver for some cards. */ { if (flags & HAS_FLASH_BUG) { EL3WINDOW(3); outl((internal_config & ~0x00f00000)|0x00600000, ioaddr + Wn3_Config); } EL3WINDOW(0); flash_in_hook = vortex_flash_in; flash_out_hook = vortex_flash_out; if (opt_flash_show) flash_show(ioaddr, 0); if (opt_flash_dumpfile) if (flash_dump(ioaddr, 0, opt_flash_dumpfile) < 0) { fprintf(stderr, "Failed to save the old Flash BootROM image " "into file '%s'.\n", opt_flash_dumpfile); EL3WINDOW(3); outl(internal_config, ioaddr + Wn3_Config); EL3WINDOW(saved_window); return 3; } if (opt_flash_loadfile) if (flash_program(ioaddr, 0, opt_flash_loadfile) < 0) { fprintf(stderr, "Failed to load the new Flash BootROM image " "from file '%s'.\n", opt_flash_loadfile); EL3WINDOW(3); outl(internal_config, ioaddr + Wn3_Config); EL3WINDOW(saved_window); return 4; } if (flags & HAS_FLASH_BUG) { EL3WINDOW(3); outl(internal_config, ioaddr + Wn3_Config); } } #else if (opt_flash_loadfile || opt_flash_dumpfile || opt_flash_show) printf("Flash operations not configured into this program.\n"); if (opt_flash_show) { printf("The first few boot ROM bytes are:"); for (i = 0; i < 8; i++) printf(" %2.2x", vortex_flash_in(ioaddr, i)); printf(".\n"); } #endif if (do_test) { int bogus_cnt = 10000; /* Run the built-in-self-test of the SRAM buffer. This is valid only on the boomerang, but we run it unconditionally. */ EL3WINDOW(4); outw(0x0004, ioaddr + Wn4_FIFODiag); while ((inw(ioaddr + Wn4_FIFODiag) & 0x0020) == 0 && --bogus_cnt > 0) inw(ioaddr + Wn4_FIFODiag); if (inw(ioaddr + Wn4_FIFODiag) & 0x0020) printf("SRAM buffer test %s\n", inw(ioaddr + Wn4_FIFODiag) & 0x0010 ? "failed!" : "passed"); else printf("INTERNAL FAILURE -- SRAM buffer test did not complete!\n"); } EL3WINDOW(saved_window); return 0; } /* Serial EEPROM section. */ static int read_eeprom(long ioaddr, int addrlen, int location) { int timer; if (addrlen == 6 && location > 0x3f) location = (location & 0x3f) + ((location<<2) & 0x0f00); outw((2 << addrlen) + location, ioaddr + Wn0EepromCmd); /* Wait for the read to take place, worst-case 162 us. */ for (timer = 1620; timer >= 0; timer--) { if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) break; } if (debug > 2) fprintf(stderr, " EEPROM read completed in %d ticks, %4.4x.\n", 1620-timer, inw(ioaddr + Wn0EepromData)); return inw(ioaddr + Wn0EepromData); } static void write_eeprom(long ioaddr, int addrlen, int index, int value) { int timer; /* Verify that the EEPROM is idle. */ for (timer = 1620; inw(ioaddr + Wn0EepromCmd) & 0x8000;) if (--timer < 0) goto error_return; /* Enable writing: EEPROM_EWENB | 110000.... */ outw(3 << (addrlen-2), ioaddr + Wn0EepromCmd); for (timer = 400; inw(ioaddr + Wn0EepromCmd) & 0x8000;) { if (--timer < 0) goto error_return; } if (debug) fprintf(stderr, "EEPROM write enable took %d ticks!\n", 400 - timer); outw((EEPROM_ERASE << addrlen) + index, ioaddr + Wn0EepromCmd); for (timer = 16000; inw(ioaddr + Wn0EepromCmd) & 0x8000;) if (--timer < 0) { fprintf(stderr, "EEPROM failed to erase index %d!\n", index); return; } if (debug) fprintf(stderr, "EEPROM erased index %d after %d ticks!\n", index, 16000-timer); outw(3 << (addrlen-2), ioaddr + Wn0EepromCmd); for (timer = 400; inw(ioaddr + Wn0EepromCmd) & 0x8000;) { if (--timer < 0) goto error_return; } if (debug) fprintf(stderr, "EEPROM write enable took %d ticks!\n", 400-timer); outw(value, ioaddr + Wn0EepromData); outw((EEPROM_WRITE << addrlen) + index, ioaddr + Wn0EepromCmd); for (timer = 16000; inw(ioaddr + Wn0EepromCmd) & 0x8000;) if (--timer < 0) goto error_return; if (debug) fprintf(stderr, "EEPROM wrote index %d with 0x%4.4x after %d ticks!\n", index, value, 16000-timer); return; error_return: fprintf(stderr, "Failed to write EEPROM location %d with 0x%4.4x!\n", index, value); } static int do_update(long ioaddr, int addrlen, unsigned short *ee_values, unsigned short *old_ee_values) { int i; EL3WINDOW(0); if (debug) printf("Comparing %d words (address length %d) in do_update().\n", 1< 0 && inw(ioaddr + Wn0EepromCmd) & 0x8000; i--) ; return 0; } static void parse_eeprom(unsigned short *eeprom) { unsigned char *p = (void *)eeprom; /* Assumes little-endian */ u16 *ee = eeprom; int i, sum = 0; printf("Saved EEPROM settings of a 3Com Vortex/Boomerang:\n"); if (eeprom[0x37] == 0x6d50) { printf(" The CardBus product ID is %4.4x %4.4x.\n", eeprom[0], eeprom[1]); p += 0x60; ee += 0x30; } printf(" 3Com Node Address "); for (i = 0; i < 5; i++) printf("%2.2X:", p[i^1]); printf("%2.2X (used as a unique ID only).\n", p[i^1]); printf(" OEM Station address %2.2X", p[1 + 20]); for (i = 1; i < 6; i++) printf(":%2.2X", p[(i^1) + 20]); printf(" (used as the ethernet address).\n"); /* The original 3Com layout did not consider post-Y2K production. */ printf(" Device ID %4.4x, Manufacturer ID %4.4x.\n", ee[3], ee[7]); printf(" Manufacture date (MM/DD/YYYY) %d/%d/%d, division %c," " product %c%c.\n", ((p[8]>>5) & 7) + ((p[9]<<3) & 8), p[8] & 31, (p[9]>>1) + ((p[9]>>1) < 95 ? 2000 : 1900), p[10], p[12], p[13]); if (ee[9] & 0x0800) printf(" A BIOS ROM of size %dKx8 is expected.\n", (ee[9]>>12)*64); else printf(" No BIOS ROM is present.\n"); printf(" Transceiver selection: %s.\n", el_medianames[(ee[19] >> 4) & 15]); printf(" Options: %s duplex, link beat %s.\n", ee[13] & 0x8000 ? "force full" : "negotiated", ee[13] & 0x4000 ? "check disabled" : "required"); printf(" PCI bus requested settings -- minimum grant %d, " "maximum latency %d (250ns units).\n", ((ee[8] & 0x03f0)>>6)*2, (ee[8] & 0xFC00) >> 10); if (ee[0x18]) { int MediaOptions = ee[0x19]; printf(" PCI Subsystem IDs: Vendor %4.4x Device %4.4x.\n", ee[0x17], ee[0x18]); for (i = 0; i < 8; i++) if (MediaOptions & 1<>8)) & 0xff) == ee[0x17] ? "" : "in", (sum ^ (sum>>8)) & 0xff, ee[0x17]); for ( ; i < 0x1A; i++) sum ^= ee[i]; sum ^= sum>>8; printf(" Cyclone format checksum is %scorrect (%#2.2x vs. %#2.2x).\n", (sum & 0xff) == (ee[0x20] & 0xff) ? "" : "in", sum & 0xff, ee[0x20] & 0xff); for (sum = 0, i = 0; i < 0x20*2; i++) sum ^= ((unsigned char *)ee)[i]; printf(" Hurricane format checksum is %scorrect (%#2.2x vs. %#2.2x).\n", sum == (ee[0x20] & 0xff) ? "" : "in", sum, ee[0x20] & 0xff); return; } static void interpret_eeprom(long ioaddr) { int eeaddrlen, eesize, ee_tbl_offset = 0; int e6, eeprom_update = 0; int i; /* Read the EEPROM. */ EL3WINDOW(0); outw(0x5555, ioaddr + Wn0EepromData); e6 = read_eeprom(ioaddr, 6, 0); if (e6 != 0x5555) { if (debug) printf(" EEPROM Address length is 6 bits (%4.4x).\n", read_eeprom(ioaddr, 6, 0)); eeaddrlen = 6; } else { int e8 = read_eeprom(ioaddr, 8, 0); if (debug) printf(" EEPROM address sizing read returned %4.4x/%4.4x.\n", e6, e8); eeaddrlen = (e8 != 0xffff) ? 8 : 6; } eesize = 1 << eeaddrlen; if (debug) printf(" EEPROM address size is %d bits.\n", eeaddrlen); for (i = 0; i < eesize; i++) eeprom_contents[i] = read_eeprom(ioaddr, eeaddrlen, i); if (eeprom_contents[0x37] == 0x6d50) { ee_tbl_offset = 0x30; } else if (eeprom_contents[0] == 0x10b7 || eeprom_contents[0] == 0x1570 || eeprom_contents[0] == 0x2978) { printf(" Questionable EEPROM offset for software information!\n"); ee_tbl_offset = 0x30; } memcpy(new_ee_contents, eeprom_contents, eesize << 1); if (set_hwaddr) { for (i = 0; i < 3; i++) new_ee_contents[ee_tbl_offset + 10 + i] = (new_hwaddr[i*2]<<8) + new_hwaddr[i*2+1]; eeprom_update++; } if (set_ee_rom) { new_ee_contents[ee_tbl_offset + 9] = 0x3001; eeprom_update++; } if (new_default_media >= 0) { new_ee_contents[ee_tbl_offset + 19] &= 0x00ff; new_ee_contents[ee_tbl_offset + 19] |= (new_default_media << 8); eeprom_update++; } if (eeprom_update) { u16 *ee = eeprom_contents + ee_tbl_offset; unsigned short sum = 0; int sum_range = 0x1A, sum_location = 0x20; /* Recalculate the checksum: First find the checksum range and location. */ for (i = 0; i < 0x16; i++) sum ^= ee[i]; if (((sum ^ (sum>>8)) & 0xff) == ee[0x17]) { sum_range = 0x16; sum_location = 0x17; } for ( ; i < 0x1A; i++) sum ^= ee[i]; if (((sum ^ (sum>>8)) & 0xff) == (ee[0x20] & 0xff)) { sum_range = 0x1A; sum_location = 0x20; } for ( ; i < 0x20; i++) sum ^= ee[i]; if (((sum ^ (sum>>8)) & 0xff) == (ee[0x20] & 0xff)) { sum_range = 0x20; sum_location = 0x20; } sum = 0; for (i = 0; i < sum_range; i++) sum ^= new_ee_contents[ee_tbl_offset + i]; new_ee_contents[ee_tbl_offset + sum_location] = (sum ^ (sum>>8)) & 0xff; do_update(ioaddr, eeaddrlen, new_ee_contents, eeprom_contents); for (i = 0; i < eesize; i++) eeprom_contents[i] = read_eeprom(ioaddr, eeaddrlen, i); } if (verbose > 2 || show_eeprom > 1) { unsigned short sum = 0; int previous_row_same = 0; printf("EEPROM format %dx16, configuration table at offset %#x:\n", eesize, ee_tbl_offset); for (i = 0; i < eesize; i += 8) { int j; if (i == 0 || /* Always show first row. */ (memcmp(eeprom_contents+i, eeprom_contents+i - 8, 16) != 0)) { previous_row_same = 0; printf(" %#4.2x:", i); for (j = 0; j < 8; j++) { printf(" %4.4x", eeprom_contents[i + j]); sum += eeprom_contents[i + j]; } if (show_eeprom > 2) { printf(" "); for (j = 0; j < 8; j++) { int ew = eeprom_contents[i + j]; printf("%c%c", isprint(ew & 0xff) ? ew & 0xff : '_', isprint(ew >> 8) ? ew >> 8 : '_' ); } } printf("\n"); } else if ( ! previous_row_same) { previous_row_same = 1; printf(" ...\n"); } } printf("\n The word-wide EEPROM checksum is %#4.4x.\n", sum); } /* The user will usually want to see the interpreted EEPROM contents. */ if (verbose > 1 || show_eeprom) { parse_eeprom(eeprom_contents); } return; } /* Read and write the MII registers using software-generated serial MDIO protocol. It is just different enough from the EEPROM protocol to not share code. The maxium data clock rate is 2.5 Mhz, which is met by the PCI I/O access timing. */ #define mdio_delay(mdio_addr) inw(mdio_addr) #define MDIO_SHIFT_CLK 0x01 #define MDIO_DIR_WRITE 0x04 #define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE) #define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE) #define MDIO_DATA_READ 0x02 #define MDIO_ENB_IN 0x00 static int mii_preamble_required = 1; static void mdio_sync(long ioaddr) { long mdio_addr = ioaddr + Wn4_PhysicalMgmt; int i; /* Establish sync by sending at least 32 logic ones. */ for (i = 32; i >= 0; i--) { outw(MDIO_DATA_WRITE1, mdio_addr); mdio_delay(mdio_addr); outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(mdio_addr); } } int mdio_read(long ioaddr, int phy_id, int location) { int i; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; unsigned int retval = 0; long mdio_addr = ioaddr + Wn4_PhysicalMgmt; if (verbose > 2) /* Debug: 5 */ printf(" mdio_read(%#lx, %d, %d)..", ioaddr, phy_id, location); if (mii_preamble_required) mdio_sync(ioaddr); /* Shift the read command bits out. */ for (i = 14; i >= 0; i--) { int dataval = (read_cmd&(1< 3) /* Debug: 5 */ printf("%d", (read_cmd & (1 << i)) ? 1 : 0); outw(dataval, mdio_addr); mdio_delay(mdio_addr); outw(dataval | MDIO_SHIFT_CLK, mdio_addr); if (verbose > 3) printf(" %x", (inw(mdio_addr) >> 16) & 0x0f); mdio_delay(mdio_addr); } if (verbose > 3) printf("-> %x", (inw(mdio_addr) >> 16) & 0x0f); if (verbose > 3) /* Debug: 5 */ printf(" \n"); /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { outw(MDIO_ENB_IN, mdio_addr); mdio_delay(mdio_addr); retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(mdio_addr); if (verbose > 3) printf(" %x", (inw(mdio_addr) >> 16) & 0x0f); } if (verbose > 2) /* Debug: 5 */ printf(" %4.4x.\n", retval); /* Avoid buggy 3c905B MDIO implementation. */ return (retval & 0x20000) == 0x00000 ? retval>>1 & 0x1ffff : 0; } void mdio_write(long ioaddr, int phy_id, int location, int value) { int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value; long mdio_addr = ioaddr + Wn4_PhysicalMgmt; int i; if (verbose > 2) /* Debug: 5 */ printf(" mdio_write(%#lx, %d, %d, %4.4x)..", ioaddr, phy_id, location, value); if (mii_preamble_required) mdio_sync(ioaddr); /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (write_cmd&(1<= 0; i--) { outw(MDIO_ENB_IN, mdio_addr); mdio_delay(mdio_addr); outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(mdio_addr); } return; } int vortex_flash_in(long addr, int offset) { outl(offset, addr + 4); return inb(addr + 8) & 0xff; } void vortex_flash_out(long addr, int offset, int val) { outl(offset, addr + 4); outb(val, addr + 8); } static void show_dma_state(long ioaddr) { int dma_ctrl = inl(ioaddr + 0x20); printf(" DMA control register is %8.8x.\n", dma_ctrl); if (dma_ctrl & 0x0080) { outw(DownStall, ioaddr + EL3_CMD); printf(" DMA control register is %8.8x (during Tx Stall).\n", (int)inl(ioaddr + 0x20)); outw(DownUnstall, ioaddr + EL3_CMD); } printf(" Tx list starts at %8.8x.\n", (int)inl(ioaddr + 0x24)); printf(" Tx FIFO thresholds: min. burst %d bytes, " "priority with %d bytes to empty.\n", inb(ioaddr + 0x2A)<<5, inb(ioaddr + 0x2C)<<5); printf(" Rx FIFO thresholds: min. burst %d bytes, " "priority with %d bytes to full.\n", inb(ioaddr + 0x3E)<<5, inb(ioaddr + 0x3C)<<5); printf(" Poll period Tx %d0 ns., Rx %d ns.\n", inb(ioaddr + 0x2D)<<5, inb(ioaddr + 0x3D)<<5); printf(" Maximum burst recorded Tx %d, Rx %d.\n", inw(ioaddr + 0x78), inw(ioaddr + 0x7A)); } /* * Local variables: * compile-command: "cc -O -Wall -o vortex-diag vortex-diag.c" * alt-compile-command: "cc -O -Wall -o vortex-diag vortex-diag.c -DLIBMII libmii.c -DLIBFLASH libflash.c" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 * End: */ nictools-pci-1.3.8.orig/winbond-diag.c0000644000175000017500000006707010264222626016541 0ustar alainalain/* winbond-diag.c: Diagnostic and setup core code for Linux ethercards. This is a diagnostic and EEPROM setup program for Ethernet adapters based on the following chips: Winbond w89c840 This file also contains the chip-independent diagnostic code. Copyright 1998-2002 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 Support and updates available at http://www.scyld.com/diag/index.html http://scyld.com/expert/mii-status.html http://scyld.com/expert/NWay.html Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. */ static char *version_msg = "winbond-diag.c:v2.02 2/28/2005 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: etherdiag [-aEefFGhmqrRtvVwW] [-p ] [-[AF] ]\n" " For details and other options see http://www.scyld.com/diag/index.html\n"; static const char long_usage_msg[] = "Usage: %s [-aDfrRvVw] [-AF ] [-#]\n\ \n\ Show the internal state of a network adapter.\n\ \n\ The common usage is\n\ winbond-diag -aem\n\ \n\ Frequently used options are\n\ -a --show_all_registers Print all registers.\n\ -e --show-eeprom Dump EEPROM contents, \"-ee\" shows the details.\n\ -m --show_mii Print the MII transceiver state\n\ Using -mm monitors the link.\n\ -f --force Perform operation, even on a running NIC.\n\ \n\ To operate on a single NIC, or one that hasn't been automatically found:\n\ -# --card_num INDEX Operate on the specified card index.\n\ -p --port-base IOADDR Assume an adapter at the specified I/O address.\n\ -t --chip-type TYPE Specify adapter type (with '-p'). Use '-1' to\n\ list available types indicies.\n\ \n\ To change the persistent EEPROM settings\n\ -G --parameters PARMS Set adapter-specific parameters.\n\ -H --new-hwaddr 01:23:45:67:89:ab\n\ Set a new hardware station address. Typically disabled for safety.\n\ -w --write-EEPROM Actually write the new settings into the EEPROM.\n\ \n\ To read and write the boot BIOS extension Flash ROM\n\ -B Show the first few bytes of the ROM\n\ -L FILE Load the Flash from FILE.\n\ -S FILE Store the Flash image to FILE.\n\ \n\ -D --debug\n\ -v --verbose Report each action taken.\n\ -V --version Emit version information.\n\ \n\ -A --advertise (See the mii-diag manual page.)\n\ "; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif /* No libmii.h or libflash.h yet, thus the declarations here. */ extern int show_mii_details(long ioaddr, int phy_id); extern int monitor_mii(long ioaddr, int phy_id); extern int flash_show(long addr_ioaddr, long data_ioaddr); extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename); extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename); extern int (*flash_in_hook)(long addr, int offset); extern void (*flash_out_hook)(long addr, int offset, int val); /* We should use __u8 .. __u32, but they are not always defined. */ typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; struct option longopts[] = { /* { name has_arg *flag val } */ {"card-num", 1, 0, '#'}, /* Operate on the specified card index. */ {"Advertise", 1, 0, 'A'}, {"base-address", 1, 0, 'p'}, {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Print a long usage message. */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; extern int winbond_diag(int vend_id, int dev_id, long ioaddr, int part_idx); /* Chip-specific flags. Yes, it's grungy to have the enum here. */ /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name from the kernel, a common name and the PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { const char *part_name; const char *proc_pci_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx); } pcidev_tbl[] = { { "Winbond W89c840", 0, 0x1050, 0x0840, 0xffff, 0, 128, winbond_diag }, { "Compex RL100-ATX", "Compex Unknown device", 0x11F6, 0x2011, 0xffff, 0, 128, winbond_diag }, { 0, 0, 0, 0}, }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int nway_advertise = 0, fixed_speed = -1; int new_default_media = -1; /* Valid with libflash only. */ static unsigned int opt_flash_show = 0; static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int emergency_rewrite = 0; static int scan_proc_pci(int card_num); static int parse_media_type(const char *capabilities); static int get_media_index(const char *name); /* Chip-specific options, if any, go here. */ int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:hH:mp:qrRt:vVwWBL:S:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'A': nway_advertise = parse_media_type(optarg); break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 16); break; case 'h': fprintf(stderr, long_usage_msg, argv[0]); return 0; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtoul(optarg, NULL, 16); break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case 'W': opt_watch++; break; case 'B': opt_flash_show++; break; case 'L': opt_flash_loadfile = optarg; break; case 'S': opt_flash_dumpfile = optarg; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("Network adapter diagnostic: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for parsed contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n" " See http://www.scyld.com/expert/irq-conflict.html for more information.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if ((pci_devid >> 16) != pcidev_tbl[i].vendor || (pci_devid & pcidev_tbl[i].device_mask) != pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].part_name; i++) if (pcidev_tbl[i].proc_pci_name && strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Convert a text media name to a NWay capability word. */ static int parse_media_type(const char *capabilities) { const char *mtypes[] = { "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD", "10baseT", "10baseT-FD", "10baseT-HD", 0, }; char *endptr; int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,}; int i; if (debug) fprintf(stderr, "Advertise string is '%s'.\n", capabilities); for (i = 0; mtypes[i]; i++) if (strcasecmp(mtypes[i], capabilities) == 0) return cap_map[i]; i = strtoul(capabilities, &endptr, 16); if (*endptr == 0 && 0 < i && i <= 0xffff) return i; fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities); return 0; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to indices. This matches the Digital Tulip SROM numbering, primarily because that is the most complete list. Other chips will have to map these number to their internal values. */ struct { char *name; int value; } mediamap[] = { { "10baseT", 0 }, { "10base2", 1 }, { "AUI", 2 }, { "100baseTx", 3 }, { "10baseT-FDX", 0x204 }, { "100baseTx-FDX", 0x205 }, { "100baseT4", 6 }, { "100baseFx", 7 }, { "100baseFx-FDX", 8 }, { "MII", 11 }, { "Autosense", 0x0800 }, { 0, 0 }, }; static int get_media_index(const char *name) { char *endptr; int i; if (! name) return -1; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) return i; i = strtol(name, &endptr, 0); if (*endptr == 0) return i; fprintf(stderr, "Invalid interface specified. It must be one of\n"); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %d %s\n", mediamap[i].value, mediamap[i].name); return -1; } /* Chip-specific section. */ /* Winbond w89c840 section. */ enum w840_offsets { PCIBusCfg=0x00, TxStartDemand=0x04, RxStartDemand=0x08, RxRingPtr=0x0C, TxRingPtr=0x10, IntrStatus=0x14, NetworkConfig=0x18, IntrEnable=0x1C, RxMissed=0x20, EECtrl=0x24, MIICtrl=0x24, BootRom=0x28, GPTimer=0x2C, CurRxDescAddr=0x30, CurRxBufAddr=0x34, /* Debug use */ MulticastFilter0=0x38, MulticastFilter1=0x3C, StationAddr=0x40, CurTxDescAddr=0x4C, CurTxBufAddr=0x50, }; enum mii_reg_bits { MDIO_ShiftClk=0x10000, MDIO_DataIn=0x80000, MDIO_DataOut=0x20000, MDIO_EnbOutput=0x40000, MDIO_EnbIn = 0x00000, MDIO_Write0=0x40000, MDIO_Write1=0x60000, }; #define mdio_delay(addr) inl(addr) /* Extra bus turn-around as a delay. */ enum EEPROM_Ctrl_Bits { EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805, EE_ChipSelect=0x801, EE_DataIn=0x08, }; #define EE_OFFSET EECtrl /* Register offset in I/O space. */ /* Values read from the EEPROM, and a new image to write. */ #define EEPROM_SIZE 64 unsigned short eeprom_contents[EEPROM_SIZE]; #define EEPROM_SA_OFFSET 0 #define EEPROM_CSUM_OFFSET 0 /* 0 means none. */ static const char *tx_state[8] = { "Stopped", "Reading a Tx descriptor", "Waiting for Tx to finish", "Loading Tx FIFO", "", "Processing setup information", "Idle", "Closing Tx descriptor" }; static const char *rx_state[8] = { "Stopped", "Reading a Rx descriptor", "Waiting for Rx to finish", "Waiting for packets", "Suspended -- no Rx buffers", "Closing Rx descriptor", "Unavailable Rx buffer -- Flushing Rx frame", "Transferring Rx frame into memory", }; static const char *bus_error[8] = { "Parity Error", "Master Abort", "Target abort", "Unknown 3", "Unknown 4", "Unknown 5", "Unknown 6", "Unknown 7"}; static const char *intr_names[16] ={ "Tx done", "Tx complete", "Tx out of buffers", "Transmit Jabber", "Rx Error", "Tx FIFO Underflow", "Rx Done", "Receiver out of buffers", "Receiver stopped", "Unknown-9", "Tx partially done", "Timer expired", "Unknown-12", "PCI bus error", "Unknown-14", "Abnormal summary", }; static void w840_mdio_sync(long ioaddr) { long mdio_addr = ioaddr + MIICtrl; int i; for (i = 32; i >= 0; i--) { outl(MDIO_Write1, mdio_addr); mdio_delay(mdio_addr); outl(MDIO_Write1 | MDIO_ShiftClk, mdio_addr); mdio_delay(mdio_addr); } return; } static int w840_mdio_read(long ioaddr, int phy_id, int location) { int i; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; long mdio_addr = ioaddr + MIICtrl; if (verbose > 2) /* Debug: 5 */ printf(" mdio_read(%#lx, %d, %d)..", ioaddr, phy_id, location); w840_mdio_sync(ioaddr); /* Shift the read command bits out. */ for (i = 17; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? MDIO_Write1 : MDIO_Write0; if (verbose > 3) /* Debug: 5 */ printf("%d", (read_cmd & (1 << i)) ? 1 : 0); outl(dataval, mdio_addr); mdio_delay(mdio_addr); outl(dataval | MDIO_ShiftClk, mdio_addr); if (verbose > 3) printf("-%x ", (inl(mdio_addr) >> 16) & 0x0f); mdio_delay(mdio_addr); } if (verbose > 3) printf("-> %x", (inl(mdio_addr) >> 16) & 0x0f); /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 20; i > 0; i--) { outl(MDIO_EnbIn, mdio_addr); mdio_delay(mdio_addr); retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DataIn) ? 1 : 0); if (verbose > 3) printf(" %x", (inl(mdio_addr) >> 16) & 0x0f); outl(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); mdio_delay(mdio_addr); } if (verbose > 3) printf(" == %4.4x.\n", retval); return (retval>>1) & 0xffff; } /* The external version. */ int mdio_read(long ioaddr, int phy_id, int location) { return w840_mdio_read(ioaddr, phy_id, location); } static void w840_mdio_write(long ioaddr, int phy_id, int location, int value) { int i; int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; long mdio_addr = ioaddr + MIICtrl; w840_mdio_sync(ioaddr); /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (cmd & (1 << i)) ? MDIO_Write1 : MDIO_Write0; outl(MDIO_EnbIn | dataval, mdio_addr); mdio_delay(mdio_addr); outl(MDIO_EnbIn | dataval | MDIO_ShiftClk, mdio_addr); mdio_delay(mdio_addr); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { outl(MDIO_EnbIn, mdio_addr); mdio_delay(mdio_addr); outl(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); mdio_delay(mdio_addr); } return; } /* The EEPROM commands include the always-set leading bit. */ enum EEPROM_Cmds { EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7, }; /* Delay between EEPROM clock transitions. */ #define eeprom_delay(ee_addr) inl(ee_addr) /* This executes a generic EEPROM command, typically a write or write enable. It returns the data output from the EEPROM, and thus may also be used for reads. */ static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len) { unsigned retval = 0; long ee_addr = ioaddr + EE_OFFSET; if (debug > 1) printf(" EEPROM op 0x%x: ", cmd); outl(EE_ChipSelect | EE_ShiftClk, ee_addr); /* Shift the command bits out. */ do { short dataval = (cmd & (1 << cmd_len)) ? EE_Write1 : EE_Write0; outl(dataval, ee_addr); eeprom_delay(ee_addr); if (debug > 2) printf("%X", inl(ee_addr) & 15); outl(dataval | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); retval = (retval << 1) | ((inl(ee_addr) & EE_DataIn) ? 1 : 0); } while (--cmd_len >= 0); outl(EE_ChipSelect, ee_addr); /* Terminate the EEPROM access. */ outl(0, ee_addr); if (debug > 1) printf(" EEPROM result is 0x%5.5x.\n", retval); return retval; } /* The abstracted functions for EEPROM access. */ static int read_eeprom(long ioaddr, int location, int addr_len) { return do_eeprom_cmd(ioaddr, ((EE_ReadCmd << addr_len) | location) << 16, 3 + addr_len + 16) & 0xffff; } #ifdef LIBFLASH /* Support for Flash operations. */ static int w840_flash_in(long ioaddr, int offset) { outl(offset, ioaddr + BootRom); outl(0x5000, ioaddr + MIICtrl); return inl(ioaddr + MIICtrl) & 0xff; } static void w840_flash_out(long ioaddr, int offset, int val) { outl(offset, ioaddr + BootRom); outl(0x3000 | val, ioaddr + MIICtrl); } #endif int winbond_diag(int vendor_id, int device_id, long ioaddr, int part_idx) { int chip_active = 0; int i; /* It's mostly safe to use the EEPROM and MDIO register during operation. But warn the user, and make then pass '-f'. */ if (inl(ioaddr + NetworkConfig) & 0x2002) { chip_active = 1; } if (chip_active && !opt_f) { printf("This device appears to be active, so some registers" " will not be read.\n" "To see all register values use the '-f' flag.\n"); } else chip_active = 0; /* Ignore the chip status with -f */ if (show_regs && ! chip_active) { int num_regs = pcidev_tbl[part_idx].io_size; printf("%s chip registers at %#lx:", pcidev_tbl[part_idx].part_name, ioaddr); for (i = 0; i < num_regs; i += 4) printf("%s %8.8x", (i % 32) == 0 ? "\n " : "", inl(ioaddr + i)); printf("\n"); } { int csr5 = inl(ioaddr + IntrStatus); int net_cfg = inl(ioaddr + NetworkConfig); printf(" Port selection is %s%s, %s-duplex.\n", ! (net_cfg & 0x00040000) ? "10mpbs-serial" : (net_cfg & 0x00800000 ? "100mbps-SYM/PCS" : "MII"), net_cfg & 0x01000000 ? " 100baseTx scrambler" : "", net_cfg & 0x0200 ? "full" : "half"); printf(" Transmit %s, Receive %s, %s-duplex.\n", net_cfg & 0x2000 ? "started" : "stopped", net_cfg & 0x0002 ? "started" : "stopped", net_cfg & 0x0200 ? "full" : "half"); printf(" The Rx process state is '%s'.\n", rx_state[(csr5 >> 17) & 7]); printf(" The Tx process state is '%s'.\n", tx_state[(csr5 >> 20) & 7]); if (csr5 & 0x2000) printf(" PCI bus error!: %s.\n", bus_error[(csr5 >> 23) & 7]); if (net_cfg & 0x00200000) printf(" The transmit unit is set to store-and-forward.\n"); else { const short tx_threshold[2][4] = {{ 72, 96, 128, 160 }, {128,256, 512, 1024}}; printf(" The transmit threshold is %d.\n", tx_threshold[(NetworkConfig&0x00440000) == 0x00040000] [(NetworkConfig>>14) & 3]); } if (csr5 & 0x18000) { printf(" Interrupt sources are pending! CSR5 is %8.8x.\n", csr5); for (i = 0; i < 16; i++) if (csr5 & (1< 1) { printf("EEPROM contents:"); for (i = 0; i < EEPROM_SIZE; i++) { if ((i & 7) == 0) printf("\n0x%3.3x: ", i); printf(" %4.4x", eeprom_contents[i]); } printf("\n"); } printf("EEPROM IDs: Primary Vendor %2.2x%2.2x Device %2.2x%2.2x " " Subsystem Vendor %2.2x%2.2x Device %2.2x%2.2x.\n", ee[15], ee[14], ee[13], ee[12], ee[11], ee[10], ee[9], ee[8]); printf(" EEPROM Station address is "); for (i = EEPROM_SA_OFFSET; i < EEPROM_SA_OFFSET + 5; i++) printf("%2.2x:", ee[i]); printf("%2.2x.\n", ee[i]); printf(" PCI maximum latency %d usec, minimum grant %d usec.\n", ee[7], ee[6]); printf(" PCI revision %d, Boot ROM setting 0x%2.2x.\n", ee[16], ee[17]); for (i = 0; i < EEPROM_SIZE-1; i++) sum ^= eeprom_contents[i]; } /* Show up to four (not just the on-board) PHYs. */ w840_mdio_read(ioaddr, 0, 1); if (show_mii) { int phys[4], phy, phy_idx = 0; w840_mdio_sync(ioaddr); for (phy = 0; phy < 32 && phy_idx < 4; phy++) { int mii_status = w840_mdio_read(ioaddr, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { phys[phy_idx++] = phy; printf(" MII PHY found at address %d, status 0x%4.4x.\n", phy, mii_status); } } if (phy_idx) { if (nway_advertise > 0) { printf(" Setting the media capability advertisement register" " of PHY #%d to 0x%4.4x.\n", phys[0], nway_advertise | 1); w840_mdio_write(ioaddr, phys[0], 4, nway_advertise | 1); } if (opt_restart) { printf("Restarting negotiation...\n"); w840_mdio_write(ioaddr, phys[0], 0, 0x0000); w840_mdio_write(ioaddr, phys[0], 0, 0x1200); } /* Force 100baseTx-HD by mdio_write(ioaddr,phys[0], 0, 0x2000); */ if (fixed_speed >= 0) { int reg0_val = 0; reg0_val |= (fixed_speed & 0x0180) ? 0x2000 : 0; reg0_val |= (fixed_speed & 0x0140) ? 0x0100 : 0; printf("Setting the speed to \"fixed\", %4.4x.\n", reg0_val); w840_mdio_write(ioaddr, phys[0], 0, reg0_val); } } if (phy_idx == 0) printf(" No MII transceivers found!\n"); #ifdef LIBMII else { if (show_mii > 1) show_mii_details(ioaddr, phys[0]); if (opt_watch || show_mii > 2) monitor_mii(ioaddr, phys[0]); } #else else for (phy = 0; phy < phy_idx; phy++) { int mii_reg; printf(" MII PHY #%d transceiver registers:", phys[phy]); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", w840_mdio_read(ioaddr, phys[phy], mii_reg)); printf(".\n"); } #endif } #ifdef LIBFLASH flash_in_hook = w840_flash_in; flash_out_hook = w840_flash_out; if (opt_flash_show) flash_show(ioaddr, 0); if (opt_flash_dumpfile) if (flash_dump(ioaddr, 0, opt_flash_dumpfile) < 0) { fprintf(stderr, "Failed to save the old Flash BootROM image into" " file '%s'.\n", opt_flash_dumpfile); return 3; } if (opt_flash_loadfile) { outl(0x3000, ioaddr + MIICtrl); if (flash_program(ioaddr, 0, opt_flash_loadfile) < 0) { fprintf(stderr, "Failed to load the new Flash BootROM image from" " file '%s'.\n", opt_flash_loadfile); return 4; } } #else if (opt_flash_loadfile || opt_flash_dumpfile || opt_flash_show) printf("Flash operations not configured into this program.\n"); #endif return 0; } /* * Local variables: * compile-command: "cc -O -Wall -Wstrict-prototypes -o winbond-diag winbond-diag.c `[ -f libmii.c ] && echo -DLIBMII libmii.c` `[ -f libmii.c ] && echo -DLIBFLASH libflash.c`" * simple-compile-command: "cc -O -o winbond-diag winbond-diag.c" * tab-width: 4 * c-indent-level: 4 * c-basic-offset: 4 * End: */ nictools-pci-1.3.8.orig/yellowfin-diag.c0000644000175000017500000006116210264222626017105 0ustar alainalain/* yellowfin-diag.c: Diagnostic/setup program for the Packet Engines Yellowfin. This is a diagnostic and EEPROM setup program for Ethernet adapters based on the following chips: Packet Engines "Yellowfin" G-NIC-I Symbios Ethernet chips such as the 53c885 used on DigitalScape's adapters. (Note: The EEPROM write code is not currently activated.) Copyright 1997-2000 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Contact the author for use under other terms. This program must be compiled with "-O"! See the bottom of this file for the suggested compile-command. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 Updates and additional information are available at http://www.scyld.com/diag/index.html http://scyld.com/expert/mii-status.html http://scyld.com/expert/NWay.html Common-sense licensing statement: Using any portion of this program in your own program means that you must give credit to the original author and release the resulting code under the GPL. To use this code under other terms requires an explicit license from the copyright holder. */ static char *version_msg = "yellowfin-diag.c:v2.01 2/28/2005 Donald Becker (becker@scyld.com)\n" " http://www.scyld.com/diag/index.html\n"; static char *usage_msg = "Usage: yellowfin-diag [-aDEefFGhmqrRtvVwW] [-p ] [-[AF] ]\n" " For details and other options see http://www.scyld.com/diag/index.html\n"; static const char long_usage_msg[] = "Usage: %s [-aDfrRvVw] [-AF ] [-#]\n\ \n\ Show the internal state of a network adapter.\n\ \n\ The common usage is\n\ diag -aem\n\ \n\ Frequently used options are\n\ -a --show_all_registers Print all registers.\n\ -e --show-eeprom Dump EEPROM contents, \"-ee\" shows the details.\n\ -m --show_mii Print the MII transceiver state\n\ Using -mm monitors the link.\n\ -f --force Perform operation, even on a running NIC.\n\ \n\ To operate on a single NIC, or one that hasn't been automatically found:\n\ -# --card_num INDEX Operate on the specified card index.\n\ -p --port-base IOADDR Assume an adapter at the specified I/O address.\n\ -t --chip-type TYPE Specify adapter type (with '-p'). Use '-1' to\n\ list available types indicies.\n\ \n\ To change the persistent EEPROM settings\n\ -F, --new-interface N Set the default transceiver type.\n\ -G --parameters PARMS Set adapter-specific parameters.\n\ -H --new-hwaddr 01:23:45:67:89:ab\n\ Set a new hardware station address. Typically disabled for safety.\n\ -w --write-EEPROM Actually write the new settings into the EEPROM.\n\ To read and write the boot BIOS extension Flash ROM\n\ -B Show the first few bytes of the ROM\n\ -L FILE Load the Flash from FILE.\n\ -S FILE Store the Flash image to FILE.\n\ \n\ -D --debug\n\ -v --verbose Report each action taken.\n\ -V --version Emit version information.\n\ \n\ -A --advertise (See the mii-diag manual page.)\n\ \n"; #if ! defined(__OPTIMIZE__) #warning You must compile this program with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif #include #include #include #include #include #include #include #if defined(__linux__) && __GNU_LIBRARY__ == 1 #include /* Newer libraries use instead. */ #else #include #endif /* No libmii.h or libflash.h yet, thus the declarations here. */ extern int show_mii_details(long ioaddr, int phy_id); extern int monitor_mii(long ioaddr, int phy_id); extern int flash_show(long addr_ioaddr, long data_ioaddr); extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename); extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename); extern int (*flash_in_hook)(long addr, int offset); extern void (*flash_out_hook)(long addr, int offset, int val); /* We should use __u8 .. __u32, but they are not always defined. */ typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; struct option longopts[] = { /* { name has_arg *flag val } */ {"card-num", 1, 0, '#'}, /* Operate on the specified card index. */ {"Advertise", 1, 0, 'A'}, {"base-address", 1, 0, 'p'}, {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */ {"help", 0, 0, 'h'}, /* Print a long usage message. */ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */ {"force-detection", 0, 0, 'f'}, {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */ {"verbose", 0, 0, 'v'}, /* Verbose mode */ {"version", 0, 0, 'V'}, /* Display version number */ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */ { 0, 0, 0, 0 } }; extern int symbios_diag(int vend_id, int dev_id, long ioaddr, int part_idx); /* The table of known chips. Because of the bogus /proc/pci interface we must have both the exact name from the kernel, a common name and the PCI vendor/device IDs. This table is searched in order: place specific entries followed by 'catch-all' general entries. */ struct pcidev_entry { const char *proc_pci_name; const char *part_name; int vendor, device, device_mask; int flags; int io_size; int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx); } pcidev_tbl[] = { {" Ethernet controller: NCR Unknown device", "Symbios 53885", 0x1000, 0x0701, 0xffff, 0, 256, symbios_diag}, { 0, 0, 0, 0}, }; int verbose = 1, opt_f = 0, debug = 0; int show_regs = 0, show_eeprom = 0, show_mii = 0; unsigned int opt_a = 0, /* Show-all-interfaces flag. */ opt_restart = 0, opt_reset = 0, opt_watch = 0, opt_G = 0; unsigned int opt_GPIO = 0; /* General purpose I/O setting. */ int do_write_eeprom = 0, do_test = 0; int nway_advertise = 0, fixed_speed = -1; int new_default_media = -1; /* Valid with libflash only. */ static unsigned int opt_flash_show = 0; static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL; static unsigned char new_hwaddr[6], set_hwaddr = 0; static int emergency_rewrite = 0; static int scan_proc_pci(int card_num); static int parse_media_type(const char *capabilities); static int get_media_index(const char *name); int main(int argc, char **argv) { int port_base = 0, chip_type = 0; int errflag = 0, show_version = 0; int c, longind; int card_num = 0; extern char *optarg; while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:hH:mp:qrRst:vVwWBL:S:", longopts, &longind)) != -1) switch (c) { case '#': card_num = atoi(optarg); break; case 'a': show_regs++; opt_a++; break; case 'A': nway_advertise = parse_media_type(optarg); break; case 'D': debug++; break; case 'e': show_eeprom++; break; case 'E': emergency_rewrite++; break; case 'f': opt_f++; break; case 'F': new_default_media = get_media_index(optarg); if (new_default_media < 0) errflag++; break; case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 16); break; case 'h': fprintf(stderr, long_usage_msg, argv[0]); return 0; case 'H': { int hwaddr[6], i; if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x", hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) { for (i = 0; i < 6; i++) new_hwaddr[i] = hwaddr[i]; set_hwaddr++; } else errflag++; break; } case 'm': show_mii++; break; case 'p': port_base = strtoul(optarg, NULL, 16); break; case 'q': if (verbose) verbose--; break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 't': chip_type = atoi(optarg); break; case 'v': verbose++; break; case 'V': show_version++; break; case 'w': do_write_eeprom++; break; case 'W': opt_watch++; break; case 'B': opt_flash_show++; break; case 'L': opt_flash_loadfile = optarg; break; case 'S': opt_flash_dumpfile = optarg; break; case '?': errflag++; } if (errflag) { fprintf(stderr, usage_msg); return 3; } if (verbose || show_version) printf(version_msg); if (chip_type < 0 || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) { int i; fprintf(stderr, "Valid numeric chip types are:\n"); for (i = 0; pcidev_tbl[i].part_name; i++) { fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name); } return 3; } /* Get access to all of I/O space. */ if (iopl(3) < 0) { perror("Network adapter diagnostic: iopl()"); fprintf(stderr, "This program must be run as root.\n"); return 2; } /* Try to read a likely port_base value from /proc/pci. */ if (port_base) { printf("Assuming a %s adapter at %#x.\n", pcidev_tbl[chip_type].part_name, port_base); pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type); } else if ( scan_proc_pci(card_num) == 0) { fprintf(stderr, "Unable to find a recognized card in /proc/pci.\nIf there is" " a card in the machine, explicitly set the I/O port" " address\n using '-p -t '\n" " Use '-t -1' to see the valid chip types.\n"); return ENODEV; } if (show_regs == 0 && show_eeprom == 0 && show_mii == 0) printf(" Use '-a' or '-aa' to show device registers,\n" " '-e' to show EEPROM contents, -ee for parsed contents,\n" " or '-m' or '-mm' to show MII management registers.\n"); return 0; } /* Generic (all PCI diags) code to find cards. */ static char bogus_iobase[] = "This chip has not been assigned a valid I/O address, and will not function.\n" " If you have warm-booted from another operating system, a complete \n" " shut-down and power cycle may restore the card to normal operation.\n"; static char bogus_irq[] = "This chip has not been assigned a valid IRQ, and will not function.\n" " This must be fixed in the PCI BIOS setup. The device driver has no way\n" " of changing the PCI IRQ settings.\n" " See http://www.scyld.com/expert/irq-conflict.html for more information.\n"; static int scan_proc_bus_pci(int card_num) { int card_cnt = 0, chip_idx = 0; int port_base; char buffer[514]; unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1; int i; FILE *fp = fopen("/proc/bus/pci/devices", "r"); if (fp == NULL) { if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n"); return -1; } while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parsing line -- %s", buffer); if (sscanf(buffer, "%x %x %x %x %x", &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0) break; for (i = 0; pcidev_tbl[i].vendor; i++) { if ((pci_devid >> 16) != pcidev_tbl[i].vendor || (pci_devid & pcidev_tbl[i].device_mask) != pcidev_tbl[i].device) continue; chip_idx = i; card_cnt++; /* Select the I/O address. */ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (irq == 0 || irq == 255) printf(bogus_irq); if (port_base) pcidev_tbl[chip_idx].diag_func(0,0,port_base, i); else printf(bogus_iobase); break; } } } fclose(fp); return card_cnt; } static int scan_proc_pci(int card_num) { int card_cnt = 0, chip_idx = 0; char chip_name[40]; FILE *fp; int port_base; if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0) return card_cnt; card_cnt = 0; fp = fopen("/proc/pci", "r"); if (fp == NULL) return 0; { char buffer[514]; int pci_bus, pci_device, pci_function, vendor_id, device_id; int state = 0; if (debug) printf("Done open of /proc/pci.\n"); while (fgets(buffer, sizeof(buffer), fp)) { if (debug > 1) fprintf(stderr, " Parse state %d line -- %s", state, buffer); if (sscanf(buffer, " Bus %d, device %d, function %d", &pci_bus, &pci_device, &pci_function) > 0) { chip_idx = 0; state = 1; continue; } if (state == 1) { if (sscanf(buffer, " Ethernet controller: %39[^\n]", chip_name) > 0) { int i; if (debug) printf("Named ethernet controller %s.\n", chip_name); for (i = 0; pcidev_tbl[i].part_name; i++) if (pcidev_tbl[i].proc_pci_name && strncmp(pcidev_tbl[i].proc_pci_name, chip_name, strlen(pcidev_tbl[i].proc_pci_name)) == 0) { state = 2; chip_idx = i; continue; } continue; } /* Handle a /proc/pci that does not recognize the card. */ if (sscanf(buffer, " Vendor id=%x. Device id=%x", &vendor_id, &device_id) > 0) { int i; if (debug) printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n", vendor_id, device_id); for (i = 0; pcidev_tbl[i].vendor; i++) if (vendor_id == pcidev_tbl[i].vendor && (device_id & pcidev_tbl[i].device_mask) == pcidev_tbl[i].device) break; if (pcidev_tbl[i].vendor == 0) continue; chip_idx = i; state = 2; } } if (state == 2) { if (sscanf(buffer, " I/O at %x", &port_base) > 0) { card_cnt++; state = 3; if (card_num == 0 || card_num == card_cnt) { printf("Index #%d: Found a %s adapter at %#x.\n", card_cnt, pcidev_tbl[chip_idx].part_name, port_base); if (port_base) pcidev_tbl[chip_idx].diag_func (vendor_id, device_id, port_base, chip_idx); else printf(bogus_iobase); } } } } } fclose(fp); return card_cnt; } /* Convert a text media name to a NWay capability word. */ static int parse_media_type(const char *capabilities) { const char *mtypes[] = { "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD", "10baseT", "10baseT-FD", "10baseT-HD", 0, }; char *endptr; int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,}; int i; if (debug) fprintf(stderr, "Advertise string is '%s'.\n", capabilities); for (i = 0; mtypes[i]; i++) if (strcasecmp(mtypes[i], capabilities) == 0) return cap_map[i]; i = strtoul(capabilities, &endptr, 16); if (*endptr == 0 && 0 < i && i <= 0xffff) return i; fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities); return 0; } /* Return the index of a valid media name. 0x0800 Power up autosense (check speed only once) 0x8000 Dynamic Autosense */ /* A table of media names to indices. This matches the Digital Tulip SROM numbering, primarily because that is the most complete list. Other chips will have to map these number to their internal values. */ struct { char *name; int value; } mediamap[] = { { "10baseT", 0 }, { "10base2", 1 }, { "AUI", 2 }, { "100baseTx", 3 }, { "10baseT-FDX", 0x204 }, { "100baseTx-FDX", 0x205 }, { "100baseT4", 6 }, { "100baseFx", 7 }, { "100baseFx-FDX", 8 }, { "MII", 11 }, { "Autosense", 0x0800 }, { 0, 0 }, }; static int get_media_index(const char *name) { char *endptr; int i; if (! name) return -1; for (i = 0; mediamap[i].name; i++) if (strcasecmp(name, mediamap[i].name) == 0) return i; i = strtol(name, &endptr, 0); if (*endptr == 0) return i; fprintf(stderr, "Invalid interface specified. It must be one of\n"); for (i = 0; mediamap[i].name; i++) fprintf(stderr, " %d %s\n", mediamap[i].value, mediamap[i].name); return -1; } /* The chip-specific section for the Symbios diagnostic. */ static int read_eeprom(long ioaddr, int location); static int read_eeprom_serial(long ioaddr, int location, int addr_len); #if 0 static void write_eeprom_serial(long ioaddr, int index, int value); static void write_eeprom(long ioaddr, int index, int value); #endif int mdio_read(long ioaddr, int phy_id, int location); void mdio_write(long ioaddr, int phy_id, int location, int value); static void parse_eeprom(unsigned char *eeprom); #define EEPROM_SIZE 256 /* Offsets to the various registers. All accesses need not be longword aligned. */ enum yellowfin_offsets { TxCtrl=0x00, TxStatus=0x04, TxPtr=0x0C, TxIntrSel=0x10, TxBranchSel=0x14, TxWaitSel=0x18, RxCtrl=0x40, RxStatus=0x44, RxPtr=0x4C, RxIntrSel=0x50, RxBranchSel=0x54, RxWaitSel=0x58, EventStatus=0x80, IntrEnb=0x82, IntrClear=0x84, IntrStatus=0x86, ChipRev=0x8C, DMACtrl=0x90, Cnfg=0xA0, RxDepth=0xB8, FlowCtrl=0xBC, MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC, MII_Status=0xAE, AddrMode=0xD0, StnAddr=0xD2, HashTbl=0xD8, EEStatus=0xF0, EECtrl=0xF1, EEAddr=0xF2, EERead=0xF3, EEWrite=0xF4, EEFeature=0xF5, }; /* The interrupt flags for a Yellowfin. */ static const char *intr_names[16] ={ "Rx DMA event", "Rx Illegal instruction", "PCI bus fault during receive", "PCI parity error during receive", "Tx DMA event", "Tx Illegal instruction", "PCI bus fault during transmit", "PCI parity error during transmit", "Early receive", "Carrier sense wakeup", }; /* Non-interrupting events. */ const char *event_names[16] = { "Tx Abort", "Rx frame complete", "Transmit done", }; /* Values read from the EEPROM, and the new image. */ static unsigned char eeprom_contents[EEPROM_SIZE]; int symbios_diag(int vendor_id, int device_id, long ioaddr, int part_idx) { int chip_active = 0; int i; /* It's mostly safe to examine the registers and EEPROM during operation. But warn the user, and make then pass '-f'. */ if (!opt_f && (inl(ioaddr + TxStatus) & 0x0400) != 0x0000) { printf("A potential Yellowfin chip has been found, but it appears to " "be active.\nEither shutdown the network, or use the" " '-f' flag.\n"); chip_active = 0; } if (verbose || show_regs) { unsigned intr_status, event_status; printf("Station address "); for (i = 0; i < 5; i++) printf("%2.2x:", inb(ioaddr + StnAddr + i)); printf("%2.2x.\n", inb(ioaddr + StnAddr + i)); printf("%s chip registers at %#lx", pcidev_tbl[part_idx].part_name, ioaddr); for (i = 0; i < pcidev_tbl[part_idx].io_size; i += 4) { if ((i & 0x1f) == 0) printf("\n 0x%3.3X:", i); printf(" %8.8x", inl(ioaddr + i)); } printf("\n"); intr_status = inw(ioaddr + IntrStatus); printf(" %snterrupt sources are pending (%4.4x).\n", (intr_status & 0x03ff) ? "I": "No i", intr_status); if (intr_status) { for (i = 0; i < 16; i++) if (intr_status & (1< 1) { printf("EEPROM byte zero is %2.2x/%2.2x.\n", read_eeprom(ioaddr, 0), read_eeprom_serial(ioaddr, 0, 6)); printf("EEPROM contents:"); for (i = 0; i < EEPROM_SIZE; i++) { if ((i&15) == 0) printf("\n0x%3.3x: ", i + 0x100); printf(" %2.2x", eeprom_contents[i]); } printf("\n"); } if (show_eeprom) parse_eeprom(eeprom_contents); if (show_mii) { int phys[4], phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(ioaddr, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { phys[phy_idx++] = phy; printf(" MII PHY found at address %d, status 0x%4.4x.\n", phy, mii_status); } } if (phy_idx == 0) printf(" ***WARNING***: No MII transceivers found!\n"); for (phy = 0; phy < phy_idx; phy++) { int mii_reg; printf(" MII PHY #%d transceiver registers:", phys[phy]); for (mii_reg = 0; mii_reg < 32; mii_reg++) printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "", mdio_read(ioaddr, phys[phy], mii_reg)); printf(".\n"); } #ifdef LIBMII show_mii_details(ioaddr, phys[0]); if (show_mii > 1) monitor_mii(ioaddr, phys[0]); #endif } return 0; } /* Serial EEPROM section. A "bit" grungy, but we work our way through bit-by-bit :->. */ /* The EEPROM commands include the always-set leading bit. They must be shifted by the number of address bits. */ enum EEPROM_Cmds { EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7, }; enum EEPROM_Ctrl_Bits { EE_ShiftClk=0x02, EE_ChipSelect=0x00, EE_DataOut=0x01, EE_DataIn=0x01, EE_Write0=0x00, EE_Write1=0x01, }; #define EE_OFFSET EECtrl /* Register offset in I/O space. */ /* Delay between EEPROM clock transitions. */ #define eeprom_delay(ee_addr) inb(ee_addr) /* This executes a generic EEPROM command, typically a write or write enable. It returns the data output from the EEPROM, and thus may also be used for reads. */ static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len) { unsigned retval = 0; long ee_addr = ioaddr + EE_OFFSET; if (debug > 1) printf(" EEPROM op 0x%x: ", cmd); outb(EE_ChipSelect | EE_ShiftClk, ee_addr); /* Shift the command bits out. */ do { short dataval = (cmd & (1 << cmd_len)) ? EE_Write1 : EE_Write0; outb(dataval, ee_addr); eeprom_delay(ee_addr); if (debug > 2) printf("%X", inb(ee_addr) & 15); outb(dataval | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); retval = (retval << 1) | ((inb(ee_addr) & EE_DataIn) ? 1 : 0); } while (--cmd_len >= 0); outb(EE_ChipSelect, ee_addr); /* Terminate the EEPROM access. */ outb(0, ee_addr); if (debug > 1) printf(" EEPROM result is 0x%5.5x.\n", retval); return retval; } /* The abstracted functions for EEPROM access. */ static int read_eeprom_serial(long ioaddr, int location, int addr_len) { return do_eeprom_cmd(ioaddr, ((EE_ReadCmd << addr_len) | location) << 16, 3 + addr_len + 16) & 0xffff; } #if 0 static void write_eeprom_serial(long ioaddr, int index, int value) { int i; long ee_addr = ioaddr + 0x9e; long ee_dir = ioaddr + 0x9f; int cmd = ((index | EE_WRITE_CMD)<< 16) | value; outb(0xfc, ee_dir); /* Shift the command bits out. */ for (i = 26; i >= 0; i--) { short dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0; outb(EE_ENB | dataval, ee_addr); eeprom_delay(); outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(); } outb(EE_ENB, ee_addr); /* Terminate the EEPROM access. */ outb(0xff, ee_dir); } #endif static int read_eeprom(long ioaddr, int location) { int bogus_cnt = 1000; outb(location, ioaddr + EEAddr); outb(0x30 | ((location >> 8) & 7), ioaddr + EECtrl); while ((inb(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0) ; if (inb(ioaddr + EEStatus) || debug) printf("EEStatus is %2.2x after %d ticks, %d is %x.\n", inb(ioaddr + EEStatus), 1000-bogus_cnt, location, inb(ioaddr + EERead)); return inb(ioaddr + EERead); } #if 0 static void write_eeprom(long ioaddr, int location, int value) { int bogus_cnt = 1000; outb(1, ioaddr + EEFeature); /* Enable writing. */ outb(value, ioaddr + EEWrite); outb(location, ioaddr + EEAddr); outb(0x20 | ((location >> 8) & 7), ioaddr + EECtrl); while ((inb(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0) ; outb(0, ioaddr + EEFeature); /* Disable writing. */ printf("EEStatus is %2.2x after %d ticks, %d is now %x.\n", inb(ioaddr + EEStatus), 999-bogus_cnt, location, read_eeprom(ioaddr, location)); return; } #endif /* MII Managemen Data I/O accesses. These routines assume the MDIO controller is idle, and do not exit until the command is finished. */ int mdio_read(long ioaddr, int phy_id, int location) { int i = 10000; if (verbose > 2) /* Debug: 5 */ printf(" mdio_read(%#lx, %d, %d)..", ioaddr, phy_id, location); outw((phy_id<<8) + location, ioaddr + MII_Addr); outw(1, ioaddr + MII_Cmd); while (--i > 0) if ((inw(ioaddr + MII_Status) & 1) == 0) break; return inw(ioaddr + MII_Rd_Data); } void mdio_write(long ioaddr, int phy_id, int location, int value) { int i = 10000; outw((phy_id<<8) + location, ioaddr + MII_Addr); outw(value, ioaddr + MII_Wr_Data); /* Wait for the command to finish. */ while (--i > 0) if ((inw(ioaddr + MII_Status) & 1) == 0) break; return; } static void parse_eeprom(unsigned char *eeprom) { int i; printf(" Yellowfin EEPROM contents.\n Station address "); for (i = 0; i < 5; i++) printf("%2.2X:", eeprom[i]); printf("%2.2X.\n", eeprom[i]); return; } /* * Local variables: * compile-command: "cc -O -Wall -Wstrict-prototypes -o yellowfin-diag yellowfin-diag.c `[ -f libmii.c ] && echo -DLIBMII libmii.c` `[ -f libmii.c ] && echo -DLIBFLASH libflash.c`" * simple-compile-command: "cc -O -o yellowfin-diag yellowfin-diag.c" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 * End: */