From a2faddf7d38e4651ce6654c62b668ab02b909b58 Mon Sep 17 00:00:00 2001 From: Carl-Daniel Hailfinger Date: Sat, 5 Jan 2013 23:52:45 +0000 Subject: Decouple BAR reading from pci device init, handle errors gracefully MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pcidev_init() now returns struct pci_device * instead of a BAR stored in PCI config space. This allows for real error checking instead of having exit(1) everywhere in pcidev.c. Thanks to Niklas Söderlund for coming up with the original error handling patch which was slightly modified and folded into this patch. Move the declaration of struct pci_device in programmer.h before the first user. Corresponding to flashrom svn r1644. Signed-off-by: Carl-Daniel Hailfinger Acked-by: Stefan Tauner --- atahpt.c | 11 ++++++++--- drkaiser.c | 11 +++++++---- gfxnvidia.c | 11 +++++++---- nic3com.c | 11 ++++++++--- nicintel.c | 13 +++++++------ nicintel_spi.c | 7 +++++-- nicnatsemi.c | 15 ++++++--------- nicrealtek.c | 14 ++++++++++---- ogp_spi.c | 6 +++++- pcidev.c | 27 +++++++++++++++------------ programmer.h | 36 ++++++++++++++++++------------------ satamv.c | 12 ++++++------ satasii.c | 11 +++++++---- 13 files changed, 109 insertions(+), 76 deletions(-) diff --git a/atahpt.c b/atahpt.c index d19cb75..f8be8c4 100644 --- a/atahpt.c +++ b/atahpt.c @@ -58,17 +58,22 @@ static const struct par_programmer par_programmer_atahpt = { int atahpt_init(void) { + struct pci_dev *dev = NULL; uint32_t reg32; if (rget_io_perms()) return 1; - io_base_addr = pcidev_init(PCI_BASE_ADDRESS_4, ata_hpt); + dev = pcidev_init(ata_hpt, PCI_BASE_ADDRESS_4); + if (!dev) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_4); /* Enable flash access. */ - reg32 = pci_read_long(pcidev_dev, REG_FLASH_ACCESS); + reg32 = pci_read_long(dev, REG_FLASH_ACCESS); reg32 |= (1 << 24); - rpci_write_long(pcidev_dev, REG_FLASH_ACCESS, reg32); + rpci_write_long(dev, REG_FLASH_ACCESS, reg32); register_par_programmer(&par_programmer_atahpt, BUS_PARALLEL); diff --git a/drkaiser.c b/drkaiser.c index a6eca1c..b94d6dd 100644 --- a/drkaiser.c +++ b/drkaiser.c @@ -64,17 +64,20 @@ static int drkaiser_shutdown(void *data) int drkaiser_init(void) { + struct pci_dev *dev = NULL; uint32_t addr; if (rget_io_perms()) return 1; - /* No need to check for errors, pcidev_init() will not return in case of errors. */ - addr = pcidev_init(PCI_BASE_ADDRESS_2, drkaiser_pcidev); + dev = pcidev_init(drkaiser_pcidev, PCI_BASE_ADDRESS_2); + if (!dev) + return 1; + + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_2); /* Write magic register to enable flash write. */ - rpci_write_word(pcidev_dev, PCI_MAGIC_DRKAISER_ADDR, - PCI_MAGIC_DRKAISER_VALUE); + rpci_write_word(dev, PCI_MAGIC_DRKAISER_ADDR, PCI_MAGIC_DRKAISER_VALUE); /* Map 128kB flash memory window. */ drkaiser_bar = physmap("Dr. Kaiser PC-Waechter flash memory", diff --git a/gfxnvidia.c b/gfxnvidia.c index a994d68..d0a9feb 100644 --- a/gfxnvidia.c +++ b/gfxnvidia.c @@ -85,14 +85,17 @@ static int gfxnvidia_shutdown(void *data) int gfxnvidia_init(void) { + struct pci_dev *dev = NULL; uint32_t reg32; if (rget_io_perms()) return 1; - /* No need to check for errors, pcidev_init() will not return in case of errors. */ - io_base_addr = pcidev_init(PCI_BASE_ADDRESS_0, gfx_nvidia); + dev = pcidev_init(gfx_nvidia, PCI_BASE_ADDRESS_0); + if (!dev) + return 1; + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); io_base_addr += 0x300000; msg_pinfo("Detected NVIDIA I/O base address: 0x%x.\n", io_base_addr); @@ -102,9 +105,9 @@ int gfxnvidia_init(void) return 1; /* Allow access to flash interface (will disable screen). */ - reg32 = pci_read_long(pcidev_dev, 0x50); + reg32 = pci_read_long(dev, 0x50); reg32 &= ~(1 << 0); - rpci_write_long(pcidev_dev, 0x50, reg32); + rpci_write_long(dev, 0x50, reg32); /* Write/erase doesn't work. */ programmer_may_write = 0; diff --git a/nic3com.c b/nic3com.c index 4ec6193..8d67b54 100644 --- a/nic3com.c +++ b/nic3com.c @@ -86,13 +86,18 @@ static int nic3com_shutdown(void *data) int nic3com_init(void) { + struct pci_dev *dev = NULL; + if (rget_io_perms()) return 1; - /* No need to check for errors, pcidev_init() will not return in case of errors. */ - io_base_addr = pcidev_init(PCI_BASE_ADDRESS_0, nics_3com); + dev = pcidev_init(nics_3com, PCI_BASE_ADDRESS_0); + if (!dev) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); - id = pcidev_dev->device_id; + id = dev->device_id; /* 3COM 3C90xB cards need a special fixup. */ if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005 diff --git a/nicintel.c b/nicintel.c index 8481915..56678e7 100644 --- a/nicintel.c +++ b/nicintel.c @@ -68,6 +68,7 @@ static int nicintel_shutdown(void *data) int nicintel_init(void) { + struct pci_dev *dev = NULL; uintptr_t addr; /* Needed only for PCI accesses on some platforms. @@ -76,17 +77,17 @@ int nicintel_init(void) if (rget_io_perms()) return 1; - /* No need to check for errors, pcidev_init() will not return in case of errors. - * FIXME: BAR2 is not available if the device uses the CardBus function. - */ - addr = pcidev_init(PCI_BASE_ADDRESS_2, nics_intel); + /* FIXME: BAR2 is not available if the device uses the CardBus function. */ + dev = pcidev_init(nics_intel, PCI_BASE_ADDRESS_2); + if (!dev) + return 1; + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_2); nicintel_bar = physmap("Intel NIC flash", addr, NICINTEL_MEMMAP_SIZE); if (nicintel_bar == ERROR_PTR) goto error_out_unmap; - /* FIXME: Using pcidev_dev _will_ cause pretty explosions in the future. */ - addr = pcidev_readbar(pcidev_dev, PCI_BASE_ADDRESS_0); + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); /* FIXME: This is not an aligned mapping. Use 4k? */ nicintel_control_bar = physmap("Intel NIC control/status reg", addr, NICINTEL_CONTROL_MEMMAP_SIZE); diff --git a/nicintel_spi.c b/nicintel_spi.c index f61c2b1..0045c09 100644 --- a/nicintel_spi.c +++ b/nicintel_spi.c @@ -166,14 +166,17 @@ static int nicintel_spi_shutdown(void *data) int nicintel_spi_init(void) { + struct pci_dev *dev = NULL; uint32_t tmp; if (rget_io_perms()) return 1; - /* No need to check for errors, pcidev_init() will not return in case of errors. */ - io_base_addr = pcidev_init(PCI_BASE_ADDRESS_0, nics_intel_spi); + dev = pcidev_init(nics_intel_spi, PCI_BASE_ADDRESS_0); + if (!dev) + return 1; + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); nicintel_spibar = physmap("Intel Gigabit NIC w/ SPI flash", io_base_addr, MEMMAP_SIZE); /* Automatic restore of EECD on shutdown is not possible because EECD diff --git a/nicnatsemi.c b/nicnatsemi.c index 60d8f87..d62a73f 100644 --- a/nicnatsemi.c +++ b/nicnatsemi.c @@ -52,22 +52,19 @@ static const struct par_programmer par_programmer_nicnatsemi = { .chip_writen = fallback_chip_writen, }; -static int nicnatsemi_shutdown(void *data) -{ - pci_cleanup(pacc); - return 0; -} - int nicnatsemi_init(void) { + struct pci_dev *dev = NULL; + if (rget_io_perms()) return 1; - io_base_addr = pcidev_init(PCI_BASE_ADDRESS_0, nics_natsemi); - - if (register_shutdown(nicnatsemi_shutdown, NULL)) + dev = pcidev_init(nics_natsemi, PCI_BASE_ADDRESS_0); + if (!dev) return 1; + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); + /* The datasheet shows address lines MA0-MA16 in one place and MA0-MA15 * in another. My NIC has MA16 connected to A16 on the boot ROM socket * so I'm assuming it is accessible. If not then next line wants to be diff --git a/nicrealtek.c b/nicrealtek.c index 8349b42..fb8e9e1 100644 --- a/nicrealtek.c +++ b/nicrealtek.c @@ -59,16 +59,19 @@ static int nicrealtek_shutdown(void *data) int nicrealtek_init(void) { + struct pci_dev *dev = NULL; + if (rget_io_perms()) return 1; - /* No need to check for errors, pcidev_init() will not return in case of errors. */ - io_base_addr = pcidev_init(PCI_BASE_ADDRESS_0, nics_realtek); - if (register_shutdown(nicrealtek_shutdown, NULL)) + dev = pcidev_init(nics_realtek, PCI_BASE_ADDRESS_0); + if (!dev) return 1; + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); + /* Beware, this ignores the vendor ID! */ - switch (pcidev_dev->device_id) { + switch (dev->device_id) { case 0x8139: /* RTL8139 */ case 0x1211: /* SMC 1211TX */ default: @@ -81,6 +84,9 @@ int nicrealtek_init(void) break; } + if (register_shutdown(nicrealtek_shutdown, NULL)) + return 1; + register_par_programmer(&par_programmer_nicrealtek, BUS_PARALLEL); return 0; diff --git a/ogp_spi.c b/ogp_spi.c index 6fb1a77..0c09d6a 100644 --- a/ogp_spi.c +++ b/ogp_spi.c @@ -105,6 +105,7 @@ static int ogp_spi_shutdown(void *data) int ogp_spi_init(void) { + struct pci_dev *dev = NULL; char *type; type = extract_programmer_param("rom"); @@ -131,8 +132,11 @@ int ogp_spi_init(void) if (rget_io_perms()) return 1; - io_base_addr = pcidev_init(PCI_BASE_ADDRESS_0, ogp_spi); + dev = pcidev_init(ogp_spi, PCI_BASE_ADDRESS_0); + if (!dev) + return 1; + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); ogp_spibar = physmap("OGP registers", io_base_addr, 4096); if (register_shutdown(ogp_spi_shutdown, NULL)) diff --git a/pcidev.c b/pcidev.c index f2c8827..c7e9d78 100644 --- a/pcidev.c +++ b/pcidev.c @@ -27,7 +27,6 @@ uint32_t io_base_addr; struct pci_access *pacc; -struct pci_dev *pcidev_dev = NULL; enum pci_bartype { TYPE_MEMBAR, @@ -156,7 +155,6 @@ uintptr_t pcidev_readbar(struct pci_dev *dev, int bar) static int pcidev_shutdown(void *data) { - pcidev_dev = NULL; if (pacc == NULL) { msg_perr("%s: Tried to cleanup an invalid PCI context!\n" "Please report a bug at flashrom@flashrom.org\n", __func__); @@ -181,18 +179,24 @@ int pci_init_common(void) return 0; } -uintptr_t pcidev_init(int bar, const struct dev_entry *devs) +/* pcidev_init gets an array of allowed PCI device IDs and returns a pointer to struct pci_dev iff exactly one + * match was found. If the "pci=bb:dd.f" programmer parameter was specified, a match is only considered if it + * also matches the specified bus:device.function. + * For convenience, this function also registers its own undo handlers. + */ +struct pci_dev *pcidev_init(const struct dev_entry *devs, int bar) { struct pci_dev *dev; + struct pci_dev *found_dev = NULL; struct pci_filter filter; char *pcidev_bdf; char *msg = NULL; int found = 0; int i; - uintptr_t addr = 0, curaddr = 0; + uintptr_t addr = 0; - if(pci_init_common() != 0) - return 1; + if (pci_init_common() != 0) + return NULL; pci_filter_init(pacc, &filter); /* Filter by bb:dd.f (if supplied by the user). */ @@ -200,7 +204,7 @@ uintptr_t pcidev_init(int bar, const struct dev_entry *devs) if (pcidev_bdf != NULL) { if ((msg = pci_filter_parse_slot(&filter, pcidev_bdf))) { msg_perr("Error: %s\n", msg); - exit(1); + return NULL; } } free(pcidev_bdf); @@ -230,8 +234,7 @@ uintptr_t pcidev_init(int bar, const struct dev_entry *devs) * just those with a valid BAR. */ if ((addr = pcidev_readbar(dev, bar)) != 0) { - curaddr = addr; - pcidev_dev = dev; + found_dev = dev; found++; } } @@ -240,14 +243,14 @@ uintptr_t pcidev_init(int bar, const struct dev_entry *devs) /* Only continue if exactly one supported PCI dev has been found. */ if (found == 0) { msg_perr("Error: No supported PCI device found.\n"); - exit(1); + return NULL; } else if (found > 1) { msg_perr("Error: Multiple supported PCI devices found. Use 'flashrom -p xxxx:pci=bb:dd.f' \n" "to explicitly select the card with the given BDF (PCI bus, device, function).\n"); - exit(1); + return NULL; } - return curaddr; + return found_dev; } enum pci_write_type { diff --git a/programmer.h b/programmer.h index 4302809..51a8c80 100644 --- a/programmer.h +++ b/programmer.h @@ -160,8 +160,25 @@ struct bitbang_spi_master { unsigned int half_period; }; -#if CONFIG_INTERNAL == 1 +#if NEED_PCI == 1 struct pci_dev; + +/* pcidev.c */ +// FIXME: These need to be local, not global +extern uint32_t io_base_addr; +extern struct pci_access *pacc; +int pci_init_common(void); +uintptr_t pcidev_readbar(struct pci_dev *dev, int bar); +struct pci_dev *pcidev_init(const struct dev_entry *devs, int bar); +/* rpci_write_* are reversible writes. The original PCI config space register + * contents will be restored on shutdown. + */ +int rpci_write_byte(struct pci_dev *dev, int reg, uint8_t data); +int rpci_write_word(struct pci_dev *dev, int reg, uint16_t data); +int rpci_write_long(struct pci_dev *dev, int reg, uint32_t data); +#endif + +#if CONFIG_INTERNAL == 1 struct penable { uint16_t vendor_id; uint16_t device_id; @@ -232,23 +249,6 @@ void myusec_delay(int usecs); void myusec_calibrate_delay(void); void internal_delay(int usecs); -#if NEED_PCI == 1 -/* pcidev.c */ -// FIXME: These need to be local, not global -extern uint32_t io_base_addr; -extern struct pci_access *pacc; -extern struct pci_dev *pcidev_dev; -int pci_init_common(void); -uintptr_t pcidev_readbar(struct pci_dev *dev, int bar); -uintptr_t pcidev_init(int bar, const struct dev_entry *devs); -/* rpci_write_* are reversible writes. The original PCI config space register - * contents will be restored on shutdown. - */ -int rpci_write_byte(struct pci_dev *dev, int reg, uint8_t data); -int rpci_write_word(struct pci_dev *dev, int reg, uint16_t data); -int rpci_write_long(struct pci_dev *dev, int reg, uint32_t data); -#endif - #if CONFIG_INTERNAL == 1 /* board_enable.c */ int board_parse_parameter(const char *boardstring, const char **vendor, const char **model); diff --git a/satamv.c b/satamv.c index 46a0e2d..c3f27e7 100644 --- a/satamv.c +++ b/satamv.c @@ -81,6 +81,7 @@ static int satamv_shutdown(void *data) */ int satamv_init(void) { + struct pci_dev *dev = NULL; uintptr_t addr; uint32_t tmp; @@ -88,11 +89,11 @@ int satamv_init(void) return 1; /* BAR0 has all internal registers memory mapped. */ - /* No need to check for errors, pcidev_init() will not return in case - * of errors. - */ - addr = pcidev_init(PCI_BASE_ADDRESS_0, satas_mv); + dev = pcidev_init(satas_mv, PCI_BASE_ADDRESS_0); + if (!dev) + return 1; + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); mv_bar = physmap("Marvell 88SX7042 registers", addr, 0x20000); if (mv_bar == ERROR_PTR) return 1; @@ -143,8 +144,7 @@ int satamv_init(void) pci_rmmio_writel(tmp, mv_bar + GPIO_PORT_CONTROL); /* Get I/O BAR location. */ - tmp = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_2) & - PCI_BASE_ADDRESS_IO_MASK; + tmp = pcidev_readbar(dev, PCI_BASE_ADDRESS_2); /* Truncate to reachable range. * FIXME: Check if the I/O BAR is actually reachable. * This is an arch specific check. diff --git a/satasii.c b/satasii.c index ec65bd0..72e35e5 100644 --- a/satasii.c +++ b/satasii.c @@ -76,21 +76,24 @@ static uint32_t satasii_wait_done(void) int satasii_init(void) { + struct pci_dev *dev = NULL; uint32_t addr; uint16_t reg_offset; if (rget_io_perms()) return 1; - pcidev_init(PCI_BASE_ADDRESS_0, satas_sii); + dev = pcidev_init(satas_sii, PCI_BASE_ADDRESS_0); + if (!dev) + return 1; - id = pcidev_dev->device_id; + id = dev->device_id; if ((id == 0x3132) || (id == 0x3124)) { - addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_0) & ~0x07; + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); reg_offset = 0x70; } else { - addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_5) & ~0x07; + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_5); reg_offset = 0x50; } -- cgit v1.1