Add in kernel firmware loading support Signed-off-by: Mark Hounschell <markh@xxxxxxxxxx> Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> drivers/staging/dgap/dgap_driver.c | 635 ++++++++++++++++----------- drivers/staging/dgap/dgap_driver.h | 6 2 files changed, 381 insertions(+), 260 deletions(-) diff -urN linux-3.13.1-orig/drivers/staging/dgap/dgap_driver.c linux-3.13.1-new/drivers/staging/dgap/dgap_driver.c --- linux-3.13.1-orig/drivers/staging/dgap/dgap_driver.c 2014-02-03 13:34:50.489287314 -0500 +++ linux-3.13.1-new/drivers/staging/dgap/dgap_driver.c 2014-02-03 14:12:20.059076489 -0500 @@ -18,6 +18,33 @@ * */ +/* + * In the original out of kernel Digi dgap driver, firmware + * loading was done via user land to driver handshaking. + * + * For cards that support a concentrator (port expander), + * I believe the concentrator its self told the card which + * concentrator is actually attached and then that info + * was used to tell user land which concentrator firmware + * image was to be downloaded. I think even the BIOS or + * FEP images required would change with the connection + * of a particular concentrator. + * + * Since I have no access to any of these cards or + * concentrators, I cannot put the correct concentrator + * firmware file names into the firmware_info structure + * as is now done for the BIOS and FEP images. + * + * I think, but am not certain, that the cards supporting + * concentrators will function without them. So support + * of these cards has been left in this driver. + * + * In order to fully support those cards, they would + * either have to be acquired for dissection or maybe + * Digi International could provide some assistance. + */ +#undef DIGI_CONCENTRATORS_SUPPORTED + #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> @@ -26,6 +53,7 @@ #include <asm/uaccess.h> /* For copy_from_user/copy_to_user */ #include <linux/sched.h> #include <linux/sched.h> +#include <linux/firmware.h> #include <linux/version.h> #include <linux/tty.h> @@ -72,10 +100,25 @@ static void dgap_mbuf(struct board_t *brd, const char *fmt, ...); static int dgap_do_remap(struct board_t *brd); static irqreturn_t dgap_intr(int irq, void *voidbrd); - +static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds); +static int dgap_event(struct board_t *bd); +static int dgap_firmware_load(struct pci_dev *pdev, int card_type); +static void dgap_do_bios_load(struct board_t *brd, uchar *ubios, int len); +static void dgap_do_fep_load(struct board_t *brd, uchar *ufep, int len); +static void dgap_sysfs_create(struct board_t *brd); +static void dgap_get_vpd(struct board_t *brd); +static void dgap_do_reset_board(struct board_t *brd); +static void dgap_do_wait_for_bios(struct board_t *brd); +static void dgap_do_wait_for_fep(struct board_t *brd); +static int dgap_after_config_loaded(int brd); +static int dgap_finalize_board_init(struct board_t *brd); static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds); static int dgap_event(struct board_t *bd); +#ifdef DIGI_CONCENTRATORS_SUPPORTED +static void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len); +#endif + /* Driver load/unload functions */ int dgap_init_module(void); void dgap_cleanup_module(void); @@ -110,9 +153,7 @@ */ static int dgap_Major_Control_Registered = FALSE; static uint dgap_driver_start = FALSE; - static uint dgap_count = 500; - static struct class * dgap_class; /* @@ -123,6 +164,24 @@ static uint dgap_poll_stop; /* Used to tell poller to stop */ static struct timer_list dgap_poll_timer; +/* + SUPPORTED PRODUCTS + + Card Model Number of Ports Interface + ---------------------------------------------------------------- + Acceleport Xem 4 - 64 (EIA232 & EIA422) + Acceleport Xr 4 & 8 (EIA232) + Acceleport Xr 920 4 & 8 (EIA232) + Acceleport C/X 8 - 128 (EIA232) + Acceleport EPC/X 8 - 224 (EIA232) + Acceleport Xr/422 4 & 8 (EIA422) + Acceleport 2r/920 2 (EIA232) + Acceleport 4r/920 4 (EIA232) + Acceleport 8r/920 8 (EIA232) + + IBM 8-Port Asynchronous PCI Adapter (EIA232) + IBM 128-Port Asynchronous PCI Adapter (EIA232 & EIA422) +*/ static struct pci_device_id dgap_pci_tbl[] = { { DIGI_VID, PCI_DEVICE_XEM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, @@ -144,7 +203,6 @@ }; MODULE_DEVICE_TABLE(pci, dgap_pci_tbl); - /* * A generic list of Product names, PCI Vendor ID, and PCI Device ID. */ @@ -182,6 +240,36 @@ .remove = dgap_remove_one, }; +struct firmware_info { + uchar *conf_name; /* dgap.conf */ + uchar *bios_name; /* BIOS filename */ + uchar *fep_name; /* FEP filename */ + uchar *con_name; /* Concentrator filename FIXME*/ + int num; /* sequence number */ +}; + +/* + * Firmware - BIOS, FEP, and CONC filenames + */ +#define _CONFIG_ "dgap/dgap.conf" +static struct firmware_info fw_info[] = { + { _CONFIG_, "dgap/sxbios.bin", "dgap/sxfep.bin", 0, 0 }, /* XEM_DID */ + { _CONFIG_, "dgap/cxpbios.bin", "dgap/cxpfep.bin", 0, 1 }, /* CX_DID */ + { _CONFIG_, "dgap/cxpbios.bin", "dgap/cxpfep.bin", 0, 2 }, /* CX_IBM_DID */ + { _CONFIG_, "dgap/pcibios.bin", "dgap/pcifep.bin", 0, 3 }, /* EPCJ_DID */ + { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 4 }, /* 920_2_DID */ + { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 5 }, /* 920_4_DID */ + { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 6 }, /* 920_8_DID */ + { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 7 }, /* XR_DID */ + { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 8 }, /* XRJ_DID */ + { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 9 }, /* XR_422_DID */ + { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 10 }, /* XR_IBM_DID */ + { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 11 }, /* XR_SAIP_DID */ + { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 12 }, /* XR_BULL_DID */ + { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 13 }, /* 920_8_HP_DID */ + { _CONFIG_, "dgap/sxbios.bin", "dgap/sxfep.bin", 0, 14 }, /* XEM_HP_DID */ + {0,} +}; char *dgap_state_text[] = { "Board Failed", @@ -214,8 +302,6 @@ "Driver Ready." }; - - /************************************************************************ * * Driver load/unload functions @@ -233,14 +319,15 @@ APR(("%s, Digi International Part Number %s\n", DG_NAME, DG_PART)); + dgap_driver_state = DRIVER_NEED_CONFIG_LOAD; + /* * Initialize global stuff */ rc = dgap_start(); - if (rc < 0) { + if (rc < 0) return(rc); - } /* * Find and configure all the cards @@ -258,16 +345,15 @@ printk("WARNING: dgap driver load failed. No DGAP boards found.\n"); dgap_cleanup_module(); - } - else { + } else { dgap_create_driver_sysfiles(&dgap_driver); + dgap_driver_state = DRIVER_READY; } DPR_INIT(("Finished init_module. Returning %d\n", rc)); return (rc); } - /* * Start of driver. */ @@ -306,9 +392,6 @@ device_create(dgap_class, NULL, MKDEV(DIGI_DGAP_MAJOR, 0), NULL, "dgap_mgmt"); - device_create(dgap_class, NULL, - MKDEV(DIGI_DGAP_MAJOR, 1), - NULL, "dgap_downld"); dgap_Major_Control_Registered = TRUE; } @@ -339,7 +422,6 @@ return (rc); } - /* * Register pci driver, and return how many boards we have. */ @@ -348,7 +430,6 @@ return pci_register_driver(&dgap_driver); } - /* returns count (>= 0), or negative on error */ static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -364,24 +445,22 @@ if (rc == 0) { dgap_NumBoards++; DPR_INIT(("Incrementing numboards to %d\n", dgap_NumBoards)); + rc = dgap_firmware_load(pdev, ent->driver_data); } } return rc; } - static int dgap_probe1(struct pci_dev *pdev, int card_type) { return dgap_found_board(pdev, card_type); } - static void dgap_remove_one(struct pci_dev *dev) { /* Do Nothing */ } - /* * dgap_cleanup_module() * @@ -397,7 +476,7 @@ DGAP_UNLOCK(dgap_poll_lock, lock_flags); /* Turn off poller right away. */ - del_timer_sync( &dgap_poll_timer); + del_timer_sync(&dgap_poll_timer); dgap_remove_driver_sysfiles(&dgap_driver); @@ -427,7 +506,6 @@ pci_unregister_driver(&dgap_driver); } - /* * dgap_cleanup_board() * @@ -484,7 +562,6 @@ kfree(brd); } - /* * dgap_found_board() * @@ -538,9 +615,8 @@ brd->wait_for_bios = 0; brd->wait_for_fep = 0; - for (i = 0; i < MAXPORTS; i++) { + for (i = 0; i < MAXPORTS; i++) brd->channels[i] = NULL; - } /* store which card & revision we have */ pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor); @@ -552,13 +628,12 @@ /* get the PCI Base Address Registers */ - /* Xr Jupiter and EPC use BAR 2 */ if (brd->device == PCI_DEVICE_XRJ_DID || brd->device == PCI_DEVICE_EPCJ_DID) { + /* Xr Jupiter and EPC use BAR 2 */ brd->membase = pci_resource_start(pdev, 2); brd->membase_end = pci_resource_end(pdev, 2); - } - /* Everyone else uses BAR 0 */ - else { + } else { + /* Everyone else uses BAR 0 */ brd->membase = pci_resource_start(pdev, 0); brd->membase_end = pci_resource_end(pdev, 0); } @@ -582,7 +657,6 @@ brd->port = brd->membase + PCI_IO_OFFSET; brd->port_end = brd->port + PCI_IO_SIZE; - /* * Special initialization for non-PLX boards */ @@ -625,10 +699,9 @@ else brd->state = NEED_RESET; - return(0); + return 0; } - int dgap_finalize_board_init(struct board_t *brd) { int rc; @@ -653,16 +726,169 @@ dgap_mbuf(brd, DRVSTR": Failed to hook IRQ %d. Board will work in poll mode.\n", brd->irq); brd->intr_used = 0; - } - else + } else brd->intr_used = 1; - } else { + } else brd->intr_used = 0; - } return(0); } +static int dgap_firmware_load(struct pci_dev *pdev, int card_type) +{ + struct board_t *brd = dgap_Board[dgap_NumBoards - 1]; + const struct firmware *fw; + char *uaddr; + int ret; + + dgap_get_vpd(brd); + dgap_do_reset_board(brd); + + if ((fw_info[card_type].conf_name) && + (dgap_driver_state == DRIVER_NEED_CONFIG_LOAD)) { + ret = request_firmware(&fw, fw_info[card_type].conf_name, &pdev->dev); + if (ret) { + printk(KERN_ERR "DGAP: request_firmware failed. Make sure " + "you've placed '%s' file into your firmware " + "loader directory (e.g. /lib/firmware)\n", + fw_info[card_type].conf_name); + return ret; + } else { + if (!dgap_config_buf) { + uaddr = dgap_config_buf = dgap_driver_kzmalloc(fw->size + 1, GFP_ATOMIC); + if (!dgap_config_buf) { + DPR_INIT(("DGAP: dgap_firmware_load - unable to allocate memory for config file\n")); + release_firmware(fw); + return -ENOMEM; + } + } + + memcpy(uaddr, fw->data, fw->size); + release_firmware(fw); + uaddr[fw->size + 1] = '\0'; // The config file is treated as a string + + if (dgap_parsefile(&uaddr, TRUE) != 0) + return -EINVAL; + + dgap_driver_state = -1; + } + } + + ret = dgap_after_config_loaded(brd->boardnum); + if (ret != 0) + return ret; + /* + * Match this board to a config the user created for us. + */ + brd->bd_config = dgap_find_config(brd->type, brd->pci_bus, brd->pci_slot); + + /* + * Because the 4 port Xr products share the same PCI ID + * as the 8 port Xr products, if we receive a NULL config + * back, and this is a PAPORT8 board, retry with a + * PAPORT4 attempt as well. + */ + if (brd->type == PAPORT8 && !brd->bd_config) + brd->bd_config = dgap_find_config(PAPORT4, brd->pci_bus, brd->pci_slot); + + if (!brd->bd_config) { + printk(KERN_ERR "DGAP: dgap_firmware_load: No valid configuration found\n"); + return -EINVAL; + } + + dgap_tty_register(brd); + dgap_finalize_board_init(brd); + + if (fw_info[card_type].bios_name) { + ret = request_firmware(&fw, fw_info[card_type].bios_name, &pdev->dev); + if (ret) { + printk(KERN_ERR "DGAP: request_firmware failed. Make sure " + "you've placed '%s' file into your firmware " + "loader directory (e.g. /lib/firmware)\n", + fw_info[card_type].bios_name); + return ret; + } else { + uaddr = (char *)fw->data; + dgap_do_bios_load(brd, uaddr, fw->size); + release_firmware(fw); + + /* Wait for BIOS to test board... */ + dgap_do_wait_for_bios(brd); + + if (brd->state != FINISHED_BIOS_LOAD) + return -ENXIO; + } + } + + if (fw_info[card_type].fep_name) { + ret = request_firmware(&fw, fw_info[card_type].fep_name, &pdev->dev); + if (ret) { + printk(KERN_ERR "DGAP: request_firmware failed. Make sure " + "you've placed '%s' file into your firmware " + "loader directory (e.g. /lib/firmware)\n", + fw_info[card_type].fep_name); + return ret; + } else { + uaddr = (char *)fw->data; + dgap_do_fep_load(brd, uaddr, fw->size); + release_firmware(fw); + + /* Wait for FEP to load on board... */ + dgap_do_wait_for_fep(brd); + + if (brd->state != FINISHED_FEP_LOAD) + return -ENXIO; + } + } + +#ifdef DIGI_CONCENTRATORS_SUPPORTED + /* + * If this is a CX or EPCX, we need to see if the firmware + * is requesting a concentrator image from us. + */ + if ((bd->type == PCX) || (bd->type == PEPC)) { + chk_addr = (u16 *) (vaddr + DOWNREQ); + /* Nonzero if FEP is requesting concentrator image. */ + check = readw(chk_addr); + vaddr = brd->re_map_membase; + } + + if (fw_info[card_type].con_name && check && vaddr) { + ret = request_firmware(&fw, fw_info[card_type].con_name, &pdev->dev); + if (ret) { + printk(KERN_ERR "DGAP: request_firmware failed. Make sure " + "you've placed '%s' file into your firmware " + "loader directory (e.g. /lib/firmware)\n", + fw_info[card_type].con_name); + return ret; + } else { + /* Put concentrator firmware loading code here */ + offset = readw((u16 *) (vaddr + DOWNREQ)); + memcpy_toio(offset, fw->data, fw->size); + + uaddr = (char *)fw->data; + dgap_do_conc_load(brd, uaddr, fw->size) + release_firmware(fw); + } + } +#endif + /* + * Do tty device initialization. + */ + ret = dgap_tty_init(brd); + if (ret < 0) { + dgap_tty_uninit(brd); + printk("DGAP: dgap_firmware_load: Can't init tty devices (%d)\n", ret); + return -EIO; + } + + dgap_sysfs_create(brd); + + brd->state = BOARD_READY; + brd->dpastatus = BD_RUNNING; + + return 0; +} /* * Remap PCI memory. @@ -707,7 +933,6 @@ return 0; } - /***************************************************************************** * * Function: @@ -739,59 +964,38 @@ int i; struct board_t *brd; unsigned long lock_flags; - unsigned long lock_flags2; - ulong new_time; + ulong new_time; dgap_poll_counter++; - - /* - * If driver needs the config file still, - * keep trying to wake up the downloader to - * send us the file. - */ - if (dgap_driver_state == DRIVER_NEED_CONFIG_LOAD) { - /* - * Signal downloader, its got some work to do. - */ - DGAP_LOCK(dgap_dl_lock, lock_flags2); - if (dgap_dl_action != 1) { - dgap_dl_action = 1; - wake_up_interruptible(&dgap_dl_wait); - } - DGAP_UNLOCK(dgap_dl_lock, lock_flags2); - goto schedule_poller; - } /* * Do not start the board state machine until * driver tells us its up and running, and has * everything it needs. */ - else if (dgap_driver_state != DRIVER_READY) { + if (dgap_driver_state != DRIVER_READY) goto schedule_poller; - } - + /* * If we have just 1 board, or the system is not SMP, * then use the typical old style poller. * Otherwise, use our new tasklet based poller, which should * speed things up for multiple boards. */ - if ( (dgap_NumBoards == 1) || (num_online_cpus() <= 1) ) { + if ((dgap_NumBoards == 1) || (num_online_cpus() <= 1)) { for (i = 0; i < dgap_NumBoards; i++) { brd = dgap_Board[i]; - if (brd->state == BOARD_FAILED) { + if (brd->state == BOARD_FAILED) continue; - } - if (!brd->intr_running) { + + if (!brd->intr_running) /* Call the real board poller directly */ dgap_poll_tasklet((unsigned long) brd); - } + } - } - else { + } else { /* Go thru each board, kicking off a tasklet for each if needed */ for (i = 0; i < dgap_NumBoards; i++) { brd = dgap_Board[i]; @@ -803,9 +1007,8 @@ * Basically, I just really don't want to spin in here, because I want * to kick off my tasklets as fast as I can, and then get out the poller. */ - if (!spin_trylock(&brd->bd_lock)) { + if (!spin_trylock(&brd->bd_lock)) continue; - } /* If board is in a failed state, don't bother scheduling a tasklet */ if (brd->state == BOARD_FAILED) { @@ -814,9 +1017,8 @@ } /* Schedule a poll helper task */ - if (!brd->intr_running) { + if (!brd->intr_running) tasklet_schedule(&brd->helper_tasklet); - } /* * Can't do DGAP_UNLOCK here, as we don't have @@ -831,27 +1033,23 @@ /* * Schedule ourself back at the nominal wakeup interval. */ - DGAP_LOCK(dgap_poll_lock, lock_flags ); + DGAP_LOCK(dgap_poll_lock, lock_flags); dgap_poll_time += dgap_jiffies_from_ms(dgap_poll_tick); new_time = dgap_poll_time - jiffies; - if ((ulong) new_time >= 2 * dgap_poll_tick) { + if ((ulong) new_time >= 2 * dgap_poll_tick) dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick); - } dgap_poll_timer.function = dgap_poll_handler; dgap_poll_timer.data = 0; dgap_poll_timer.expires = dgap_poll_time; - DGAP_UNLOCK(dgap_poll_lock, lock_flags ); + DGAP_UNLOCK(dgap_poll_lock, lock_flags); if (!dgap_poll_stop) add_timer(&dgap_poll_timer); } - - - /* * dgap_intr() * @@ -883,7 +1081,6 @@ return IRQ_HANDLED; } - /* * dgap_init_globals() * @@ -899,24 +1096,21 @@ dgap_trcbuf_size = trcbuf_size; dgap_debug = debug; - for (i = 0; i < MAXBOARDS; i++) { + for (i = 0; i < MAXBOARDS; i++) dgap_Board[i] = NULL; - } - init_timer( &dgap_poll_timer ); + init_timer(&dgap_poll_timer); init_waitqueue_head(&dgap_dl_wait); dgap_dl_action = 0; } - /************************************************************************ * * Utility functions * ************************************************************************/ - /* * dgap_driver_kzmalloc() * @@ -930,7 +1124,6 @@ return(p); } - /* * dgap_mbuf() * @@ -967,7 +1160,6 @@ DGAP_UNLOCK(dgap_global_lock, flags); } - /* * dgap_ms_sleep() * @@ -982,8 +1174,6 @@ return (signal_pending(current)); } - - /* * dgap_ioctl_name() : Returns a text version of each ioctl value. */ @@ -1060,7 +1250,7 @@ if (n > len) n = len; - if (copy_from_user((char *) &buf, from_addr, n) == -1 ) + if (copy_from_user((char *) &buf, from_addr, n) == -1) return; /* Copy data from buffer to kernel memory */ @@ -1083,73 +1273,58 @@ return; } - -int dgap_after_config_loaded(void) +static int dgap_after_config_loaded(int board) { - int i = 0; - int rc = 0; + int ret = 0; /* - * Register our ttys, now that we have the config loaded. + * Initialize KME waitqueues... */ - for (i = 0; i < dgap_NumBoards; ++i) { + init_waitqueue_head(&(dgap_Board[board]->kme_wait)); - /* - * Initialize KME waitqueues... - */ - init_waitqueue_head(&(dgap_Board[i]->kme_wait)); - - /* - * allocate flip buffer for board. - */ - dgap_Board[i]->flipbuf = dgap_driver_kzmalloc(MYFLIPLEN, GFP_ATOMIC); - dgap_Board[i]->flipflagbuf = dgap_driver_kzmalloc(MYFLIPLEN, GFP_ATOMIC); + /* + * allocate flip buffer for board. + */ + dgap_Board[board]->flipbuf = dgap_driver_kzmalloc(MYFLIPLEN, GFP_ATOMIC); + if (!dgap_Board[board]->flipbuf) { + ret = -ENOMEM; + goto out; } + dgap_Board[board]->flipflagbuf = dgap_driver_kzmalloc(MYFLIPLEN, GFP_ATOMIC); + if (!dgap_Board[board]->flipflagbuf) + ret = -ENOMEM; - return rc; + out: + return ret; } - - -/*======================================================================= - * - * usertoboard - copy from user space to board space. - * - *=======================================================================*/ -static int dgap_usertoboard(struct board_t *brd, char *to_addr, char __user *from_addr, int len) +/* + * Create pr and tty device entries + */ +static void dgap_sysfs_create(struct board_t *brd) { - char buf[U2BSIZE]; - int n = U2BSIZE; - - if (!brd || brd->magic != DGAP_BOARD_MAGIC) - return -EFAULT; - - while (len) { - if (n > len) - n = len; - - if (copy_from_user((char *) &buf, from_addr, n) == -1 ) { - return -EFAULT; - } - - /* Copy data from buffer to card memory */ - memcpy_toio(to_addr, buf, n); + struct channel_t *ch; + int j = 0; - /* increment counts */ - len -= n; - to_addr += n; - from_addr += n; - n = U2BSIZE; - } - return 0; + ch = brd->channels[0]; + for (j = 0; j < brd->nasync; j++, ch = brd->channels[j]) { + struct device *classp; + classp = tty_register_device(brd->SerialDriver, j, &(ch->ch_bd->pdev->dev)); + ch->ch_tun.un_sysfs = classp; + dgap_create_tty_sysfs(&ch->ch_tun, classp); + + classp = tty_register_device(brd->PrintDriver, j, &(ch->ch_bd->pdev->dev)); + ch->ch_pun.un_sysfs = classp; + dgap_create_tty_sysfs(&ch->ch_pun, classp); + } + dgap_create_ports_sysfiles(brd); } - /* * Copies the BIOS code from the user to the board, * and starts the BIOS running. */ -void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len) +static void dgap_do_bios_load(struct board_t *brd, uchar *ubios, int len) { uchar *addr; uint offset; @@ -1172,21 +1347,15 @@ * Download bios */ offset = 0x1000; - if (dgap_usertoboard(brd, addr + offset, ubios, len) == -1 ) { - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - return; - } + memcpy_toio(addr + offset, ubios, len); writel(0x0bf00401, addr); writel(0, (addr + 4)); /* Clear the reset, and change states. */ writeb(FEPCLR, brd->re_map_port); - brd->state = WAIT_BIOS_LOAD; } - /* * Checks to see if the BIOS completed running on the card. */ @@ -1194,37 +1363,47 @@ { uchar *addr; u16 word; + u16 err1; + u16 err2; if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) return; - + addr = brd->re_map_membase; word = readw(addr + POSTAREA); - /* Check to see if BIOS thinks board is good. (GD). */ - if (word == *(u16 *) "GD") { - DPR_INIT(("GOT GD in memory, moving states.\n")); - brd->state = FINISHED_BIOS_LOAD; - return; + /* + * It can take 5-6 seconds for a board to + * pass the bios self test and post results. + * Give it 10 seconds. + */ + brd->wait_for_bios = 0; + while (brd->wait_for_bios < 1000) { + /* Check to see if BIOS thinks board is good. (GD). */ + if (word == *(u16 *) "GD") { + DPR_INIT(("GOT GD in memory, moving states.\n")); + brd->state = FINISHED_BIOS_LOAD; + return; + } + msleep_interruptible(10); + brd->wait_for_bios++; + word = readw(addr + POSTAREA); } - /* Give up on board after too long of time taken */ - if (brd->wait_for_bios++ > 5000) { - u16 err1 = readw(addr + SEQUENCE); - u16 err2 = readw(addr + ERROR); - APR(("***WARNING*** %s failed diagnostics. Error #(%x,%x).\n", - brd->name, err1, err2)); - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - } + /* Gave up on board after too long of time taken */ + err1 = readw(addr + SEQUENCE); + err2 = readw(addr + ERROR); + APR(("***WARNING*** %s failed diagnostics. Error #(%x,%x).\n", + brd->name, err1, err2)); + brd->state = BOARD_FAILED; + brd->dpastatus = BD_NOBIOS; } - /* * Copies the FEP code from the user to the board, * and starts the FEP running. */ -void dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len) +static void dgap_do_fep_load(struct board_t *brd, uchar *ufep, int len) { uchar *addr; uint offset; @@ -1240,11 +1419,7 @@ * Download FEP */ offset = 0x1000; - if (dgap_usertoboard(brd, addr + offset, ufep, len) == -1 ) { - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - return; - } + memcpy_toio(addr + offset, ufep, len); /* * If board is a concentrator product, we need to give @@ -1269,62 +1444,62 @@ writel(0xbfc01004, (addr + 0xc34)); writel(0x3, (addr + 0xc30)); - /* change states. */ - brd->state = WAIT_FEP_LOAD; - DPR_INIT(("dgap_do_fep_load() for board %s : finish\n", brd->name)); - } - /* * Waits for the FEP to report thats its ready for us to use. */ -static void dgap_do_wait_for_fep(struct board_t *brd) +void dgap_do_wait_for_fep(struct board_t *brd) { uchar *addr; u16 word; + u16 err1; + u16 err2; if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) return; addr = brd->re_map_membase; - - DPR_INIT(("dgap_do_wait_for_fep() for board %s : start. addr: %p\n", brd->name, addr)); - word = readw(addr + FEPSTAT); - /* Check to see if FEP is up and running now. */ - if (word == *(u16 *) "OS") { - DPR_INIT(("GOT OS in memory for board %s, moving states.\n", brd->name)); - brd->state = FINISHED_FEP_LOAD; + /* + * It can take 2-3 seconds for the FEP to + * be up and running. Give it 5 secs. + */ + brd->wait_for_fep = 0; + while (brd->wait_for_fep < 500) { + /* Check to see if FEP is up and running now. */ + if (word == *(u16 *) "OS") { + DPR_INIT(("GOT OS in memory for board %s, moving states.\n", brd->name)); + brd->state = FINISHED_FEP_LOAD; + /* + * Check to see if the board can support FEP5+ commands. + */ + word = readw(addr + FEP5_PLUS); + if (word == *(u16 *) "5A") { + DPR_INIT(("GOT 5A in memory for board %s, board supports extended FEP5 commands.\n", brd->name)); + brd->bd_flags |= BD_FEP5PLUS; + } - /* - * Check to see if the board can support FEP5+ commands. - */ - word = readw(addr + FEP5_PLUS); - if (word == *(u16 *) "5A") { - DPR_INIT(("GOT 5A in memory for board %s, board supports extended FEP5 commands.\n", brd->name)); - brd->bd_flags |= BD_FEP5PLUS; + return; } - - return; + msleep_interruptible(10); + brd->wait_for_fep++; + word = readw(addr + FEPSTAT); } - /* Give up on board after too long of time taken */ - if (brd->wait_for_fep++ > 5000) { - u16 err1 = readw(addr + SEQUENCE); - u16 err2 = readw(addr + ERROR); - APR(("***WARNING*** FEPOS for %s not functioning. Error #(%x,%x).\n", - brd->name, err1, err2)); - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - } + /* Gave up on board after too long of time taken */ + err1 = readw(addr + SEQUENCE); + err2 = readw(addr + ERROR); + APR(("***WARNING*** FEPOS for %s not functioning. Error #(%x,%x).\n", + brd->name, err1, err2)); + brd->state = BOARD_FAILED; + brd->dpastatus = BD_NOFEP; DPR_INIT(("dgap_do_wait_for_fep() for board %s : finish\n", brd->name)); } - /* * Physically forces the FEP5 card to reset itself. */ @@ -1382,9 +1557,9 @@ DPR_INIT(("dgap_do_reset_board() finish\n")); } - +#ifdef DIGI_CONCENTRATORS_SUPPORTED /* - * Sends a concentrator image into the FEP5 board. + * Sends a concentrator image into the FEP5 board. FIXME: */ void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len) { @@ -1399,19 +1574,12 @@ offset = readw((u16 *) (vaddr + DOWNREQ)); to_dp = (struct downld_t *) (vaddr + (int) offset); - - /* - * The image was already read into kernel space, - * we do NOT need a user space read here - */ - memcpy_toio((char *) to_dp, uaddr, sizeof(struct downld_t)); + memcpy_toio(to_dp, uaddr, len); /* Tell card we have data for it */ writew(0, vaddr + (DOWNREQ)); - - brd->conc_dl_status = NO_PENDING_CONCENTRATOR_REQUESTS; } - +#endif #define EXPANSION_ROM_SIZE (64 * 1024) #define FEP5_ROM_MAGIC (0xFEFFFFFF) @@ -1517,7 +1685,6 @@ pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic); } - /* * Our board poller function. */ @@ -1528,8 +1695,6 @@ ulong lock_flags2; char *vaddr; u16 head, tail; - u16 *chk_addr; - u16 check = 0; if (!bd || (bd->magic != DGAP_BOARD_MAGIC)) { APR(("dgap_poll_tasklet() - NULL or bad bd.\n")); @@ -1563,30 +1728,6 @@ goto out; } - /* - * If this is a CX or EPCX, we need to see if the firmware - * is requesting a concentrator image from us. - */ - if ((bd->type == PCX) || (bd->type == PEPC)) { - chk_addr = (u16 *) (vaddr + DOWNREQ); - check = readw(chk_addr); - /* Nonzero if FEP is requesting concentrator image. */ - if (check) { - if (bd->conc_dl_status == NO_PENDING_CONCENTRATOR_REQUESTS) - bd->conc_dl_status = NEED_CONCENTRATOR; - /* - * Signal downloader, its got some work to do. - */ - DGAP_LOCK(dgap_dl_lock, lock_flags2); - if (dgap_dl_action != 1) { - dgap_dl_action = 1; - wake_up_interruptible(&dgap_dl_wait); - } - DGAP_UNLOCK(dgap_dl_lock, lock_flags2); - - } - } - eaddr = (struct ev_t *) (vaddr + EVBUF); /* Get our head and tail */ @@ -1774,7 +1915,6 @@ DGAP_UNLOCK(bd->bd_lock, lock_flags); } - /*======================================================================= * * dgap_cmdb - Sends a 2 byte command to the FEP. @@ -1865,7 +2005,6 @@ } } - /*======================================================================= * * dgap_cmdw - Sends a 1 word command to the FEP. @@ -1953,8 +2092,6 @@ } } - - /*======================================================================= * * dgap_cmdw_ext - Sends a extended word command to the FEP. @@ -2055,7 +2192,6 @@ } } - /*======================================================================= * * dgap_wmove - Write data to FEP buffer. @@ -2153,7 +2289,6 @@ return value; } - /* * Calls the firmware to reset this channel. */ @@ -2180,7 +2315,6 @@ ch->ch_hflow = 0; } - /*======================================================================= * * dgap_param - Set Digi parameters. @@ -2528,7 +2662,6 @@ return 0; } - /* * dgap_parity_scan() * @@ -2615,9 +2748,6 @@ DPR_PSCAN(("dgap_parity_scan finish\n")); } - - - /*======================================================================= * * dgap_event - FEP to host event processing routine. @@ -2693,19 +2823,16 @@ /* * Make sure the interrupt is valid. */ - if ( port >= bd->nasync) { + if (port >= bd->nasync) goto next; - } - if (!(reason & (IFMODEM | IFBREAK | IFTLW | IFTEM | IFDATA))) { + if (!(reason & (IFMODEM | IFBREAK | IFTLW | IFTEM | IFDATA))) goto next; - } ch = bd->channels[port]; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) { + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) goto next; - } /* * If we have made it here, the event was valid. diff -urN linux-3.13.1-orig/drivers/staging/dgap/dgap_driver.h linux-3.13.1-new/drivers/staging/dgap/dgap_driver.h --- linux-3.13.1-orig/drivers/staging/dgap/dgap_driver.h 2014-02-03 13:34:50.489287314 -0500 +++ linux-3.13.1-new/drivers/staging/dgap/dgap_driver.h 2014-02-03 14:14:40.992545649 -0500 @@ -580,12 +580,6 @@ extern int dgap_ms_sleep(ulong ms); extern void *dgap_driver_kzmalloc(size_t size, int priority); extern char *dgap_ioctl_name(int cmd); -extern void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len); -extern void dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len); -extern void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len); -extern void dgap_do_config_load(uchar __user *uaddr, int len); -extern int dgap_after_config_loaded(void); -extern int dgap_finalize_board_init(struct board_t *brd); /* * Our Global Variables. _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel