On 13.05.2009 04:10, Uwe Hermann wrote: > Add support for 3COM NICs as "external programmer" and Atmel AT49BV512. > > This allows flashrom to identify, read, write, erase and verify flash chips > on (some) 3COM network cards. The patch uses the external programmer > infrastructure, the network card is basically treated as an external > flash programmer. > > Usage: > > $ ./flashrom -p nic3com > flashrom v0.9.0-r498 > Found NIC "3COM 3C905C: EtherLink 10/100 PCI (TX)" (10b7:9200), addr = 0xa400 > Calibrating delay loop... OK. > Found chip "Atmel AT49BV512" (64 KB) at physical address 0xffff0000. > No operations were specified. > > $ ./flashrom -p nic3com -E > flashrom v0.9.0-r498 > Found NIC "3COM 3C905C: EtherLink 10/100 PCI (TX)" (10b7:9200), addr = 0xa400 > Calibrating delay loop... OK. > Found chip "Atmel AT49BV512" (64 KB) at physical address 0xffff0000. > Erasing flash chip... SUCCESS. > > $ ./flashrom -p nic3com -wv backup.bin > flashrom v0.9.0-r498 > Found NIC "3COM 3C905C: EtherLink 10/100 PCI (TX)" (10b7:9200), addr = 0xa400 > Calibrating delay loop... OK. > Found chip "Atmel AT49BV512" (64 KB) at physical address 0xffff0000. > Flash image seems to be a legacy BIOS. Disabling checks. > Programming page: 1023 at address: 0x0000ffc0 > Verifying flash... VERIFIED. > > $ ./flashrom -p nic3com -r backup.bin > flashrom v0.9.0-r498 > Found NIC "3COM 3C905C: EtherLink 10/100 PCI (TX)" (10b7:9200), addr = 0xa400 > Calibrating delay loop... OK. > Found chip "Atmel AT49BV512" (64 KB) at physical address 0xffff0000. > Reading flash... done. > > I have tested this on actual hardware (see PCI IDs above) and all > operations worked fine. > > Support for other 3COM cards will follow (I added some more which should > be supportable by this code, but they're untested so far), as well as > support for NICs from other vendors. > > The patch also adds support for the Atmel AT49BV512 which is soldered > onto the 3COM NIC I used for testing. > > Signed-off-by: Uwe Hermann <[email protected]> >
Awesome! Acked-by: Carl-Daniel Hailfinger <[email protected]> > Index: flashrom.8 > =================================================================== > --- flashrom.8 (Revision 498) > +++ flashrom.8 (Arbeitskopie) > @@ -127,7 +127,9 @@ > Specify the programmer device. Currently supported are: > .sp > .BR " internal" " (default, for in-system flashing in the mainboard)" > - > +.br > +.BR " nic3com" " (for flash ROMs on 3COM network cards)" > +.br > .BR " dummy" " (just prints all operations and accesses)" > .TP > .B "\-h, \-\-help" > Index: flash.h > =================================================================== > --- flash.h (Revision 498) > +++ flash.h (Arbeitskopie) > @@ -79,6 +79,7 @@ > extern int programmer; > #define PROGRAMMER_INTERNAL 0x00 > #define PROGRAMMER_DUMMY 0x01 > +#define PROGRAMMER_NIC3COM 0x02 > > struct programmer_entry { > const char *vendor; > @@ -281,6 +282,7 @@ > #define AT_45DB321D 0x2701 /* Buggy data sheet */ > #define AT_45DB642 /* No ID available */ > #define AT_45DB642D 0x2800 > +#define AT_49BV512 0x03 > #define AT_49F002N 0x07 /* for AT49F002(N) */ > #define AT_49F002NT 0x08 /* for AT49F002(N)T */ > > @@ -601,6 +603,18 @@ > uint16_t dummy_chip_readw(const volatile void *addr); > uint32_t dummy_chip_readl(const volatile void *addr); > > +/* nic3com.c */ > +int nic3com_init(void); > +int nic3com_shutdown(void); > +void *nic3com_map(const char *descr, unsigned long phys_addr, size_t len); > +void nic3com_unmap(void *virt_addr, size_t len); > +void nic3com_chip_writeb(uint8_t val, volatile void *addr); > +void nic3com_chip_writew(uint16_t val, volatile void *addr); > +void nic3com_chip_writel(uint32_t val, volatile void *addr); > +uint8_t nic3com_chip_readb(const volatile void *addr); > +uint16_t nic3com_chip_readw(const volatile void *addr); > +uint32_t nic3com_chip_readl(const volatile void *addr); > + > /* flashrom.c */ > extern int verbose; > #define printf_debug(x...) { if (verbose) printf(x); } > Index: flashchips.c > =================================================================== > --- flashchips.c (Revision 498) > +++ flashchips.c (Arbeitskopie) > @@ -530,6 +530,20 @@ > > { > .vendor = "Atmel", > + .name = "AT49BV512", > + .manufacture_id = ATMEL_ID, > + .model_id = AT_49BV512, > + .total_size = 64, > + .page_size = 64, > + .tested = TEST_OK_PREW, > + .probe = probe_jedec, > + .erase = erase_chip_jedec, > + .write = write_49f002, > + .read = read_memmapped, > + }, > + > + { > + .vendor = "Atmel", > .name = "AT49F002(N)", > .manufacture_id = ATMEL_ID, > .model_id = AT_49F002N, > Index: nic3com.c > =================================================================== > --- nic3com.c (Revision 0) > +++ nic3com.c (Revision 0) > @@ -0,0 +1,170 @@ > +/* > + * This file is part of the flashrom project. > + * > + * Copyright (C) 2009 Uwe Hermann <[email protected]> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#include <stdlib.h> > +#include <string.h> > +#include <errno.h> > +#include <sys/io.h> > +#include <pci/pci.h> > +#include "flash.h" > + > +#define BIOS_ROM_ADDR 0x04 > +#define BIOS_ROM_DATA 0x08 > +#define INT_STATUS 0x0e > +#define SELECT_REG_WINDOW 0x800 > + > +#define PCI_IO_BASE_ADDRESS 0x10 > + > +#define PCI_VENDOR_ID_3COM 0x10b7 > + > +uint32_t io_base_addr; > +struct pci_access *pacc; > + > +#define OK 0 > +#define NT 1 /* Not tested */ > + > +static struct nic_status { > + uint16_t device_id; > + int status; > + const char *device_name; > +} nics[] = { > + /* 3C90xB */ > + {0x9055, NT, "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-TX"}, > + {0x9001, NT, "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-T4" }, > + {0x9004, NT, "3C90xB: PCI 10BASE-T (TPO)" }, > + {0x9005, NT, "3C90xB: PCI 10BASE-T/10BASE2/AUI (COMBO)" }, > + {0x9006, NT, "3C90xB: PCI 10BASE-T/10BASE2 (TPC)" }, > + {0x900a, NT, "3C90xB: PCI 10BASE-FL" }, > + {0x905a, NT, "3C90xB: PCI 10BASE-FX" }, > + > + /* 3C905C */ > + {0x9200, OK, "3C905C: EtherLink 10/100 PCI (TX)" }, > + > + /* 3C980C */ > + {0x9805, NT, "3C980C: EtherLink Server 10/100 PCI (TX)" }, > + > + {}, > +}; > + > +int nic3com_init(void) > +{ > + int i, found = 0; > + struct pci_dev *dev; > + > +#if defined (__sun) && (defined(__i386) || defined(__amd64)) > + if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) { > +#elif defined(__FreeBSD__) || defined (__DragonFly__) > + if ((io_fd = open("/dev/io", O_RDWR)) < 0) { > +#else > + if (iopl(3) != 0) { > +#endif > + fprintf(stderr, "ERROR: Could not get IO privileges (%s).\n" > + "You need to be root.\n", strerror(errno)); > + exit(1); > + } > + > + pacc = pci_alloc(); /* Get the pci_access structure */ > + pci_init(pacc); /* Initialize the PCI library */ > + pci_scan_bus(pacc); /* We want to get the list of devices */ > + > + for (i = 0; nics[i].device_name != NULL; i++) { > + dev = pci_dev_find(PCI_VENDOR_ID_3COM, nics[i].device_id); > + if (!dev) > + continue; > + > + io_base_addr = pci_read_long(dev, PCI_IO_BASE_ADDRESS) & ~0x03; > + > + printf("Found NIC \"3COM %s\" (%04x:%04x), addr = 0x%x\n", > + nics[i].device_name, PCI_VENDOR_ID_3COM, > + nics[i].device_id, io_base_addr); > + > + if (nics[i].status == NT) { > + printf("===\nThis NIC is UNTESTED. Please email a " > + "report including the 'flashrom -p nic3com'\n" > + "output to [email protected] if it works " > + "for you. Thank you for your help!\n===\n"); > + } > + > + found = 1; > + break; > + } > + > + if (!found) { > + fprintf(stderr, "Error: No supported 3COM NIC found.\n"); > + exit(1); > + } > + > + /* > + * The lowest 16 bytes of the I/O mapped register space of (most) 3COM > + * cards form a 'register window' into one of multiple (usually 8) > + * register banks. For 3C90xB/3C90xC we need register window/bank 0. > + */ > + OUTW(SELECT_REG_WINDOW + 0, io_base_addr + INT_STATUS); > + > + return 0; > +} > + > +int nic3com_shutdown(void) > +{ > + return 0; > +} > + > +void *nic3com_map(const char *descr, unsigned long phys_addr, size_t len) > +{ > + return 0; > +} > + > +void nic3com_unmap(void *virt_addr, size_t len) > +{ > +} > + > +void nic3com_chip_writeb(uint8_t val, volatile void *addr) > +{ > + OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR); > + OUTB(val, io_base_addr + BIOS_ROM_DATA); > +} > + > +void nic3com_chip_writew(uint16_t val, volatile void *addr) > +{ > +} > + > +void nic3com_chip_writel(uint32_t val, volatile void *addr) > +{ > +} > Hmm. It would be cool if chip_{read,write}[wl] simply called chip_{read,write}b multiple times. Since nobody uses these functions right now, I'll probably create a separate patch to do this in the future. > + > +uint8_t nic3com_chip_readb(const volatile void *addr) > +{ > + uint8_t val; > + > + OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR); > + val = INB(io_base_addr + BIOS_ROM_DATA); > + > + return val; > +} > + > +uint16_t nic3com_chip_readw(const volatile void *addr) > +{ > + return 0xffff; > +} > + > +uint32_t nic3com_chip_readl(const volatile void *addr) > +{ > + return 0xffffffff; > +} > Index: Makefile > =================================================================== > --- Makefile (Revision 498) > +++ Makefile (Arbeitskopie) > @@ -35,7 +35,7 @@ > sst49lfxxxc.o sst_fwhub.o layout.o cbtable.o flashchips.o physmap.o \ > flashrom.o w39v080fa.o sharplhf00l04.o w29ee011.o spi.o it87spi.o \ > ichspi.o w39v040c.o sb600spi.o wbsio_spi.o m29f002.o internal.o \ > - dummyflasher.o > + dummyflasher.o nic3com.o > > all: pciutils dep $(PROGRAM) > > Index: flashrom.c > =================================================================== > --- flashrom.c (Revision 498) > +++ flashrom.c (Arbeitskopie) > @@ -63,6 +63,19 @@ > .chip_writel = dummy_chip_writel, > }, > > + { > + .init = nic3com_init, > + .shutdown = nic3com_shutdown, > + .map_flash_region = nic3com_map, > + .unmap_flash_region = nic3com_unmap, > + .chip_readb = nic3com_chip_readb, > + .chip_readw = nic3com_chip_readw, > + .chip_readl = nic3com_chip_readl, > + .chip_writeb = nic3com_chip_writeb, > + .chip_writew = nic3com_chip_writew, > + .chip_writel = nic3com_chip_writel, > + }, > + > {}, > }; > > @@ -439,6 +452,8 @@ > programmer = PROGRAMMER_INTERNAL; > } else if (strncmp(optarg, "dummy", 5) == 0) { > programmer = PROGRAMMER_DUMMY; > + } else if (strncmp(optarg, "nic3com", 7) == 0) { > + programmer = PROGRAMMER_NIC3COM; > } else { > printf("Error: Unknown programmer.\n"); > exit(1); > > > This is one of the best patches of this size and impact I ever saw. Please commit right away. (No need to address the chip_{read,write}[wl] comments, that's just cosmetics for later.) Regards, Carl-Daniel -- http://www.hailfinger.org/ -- coreboot mailing list: [email protected] http://www.coreboot.org/mailman/listinfo/coreboot

