/* * idr_driver.c * code module for Linux 2.6.x driver for PCI DR11 boards * * Tahoma Technology * (formerly Ikon Corporation) * 107 2nd Avenue North * Seattle, WA, USA 98109 * * 206.728.6465 * http://www.tahomatech.com * tahoma@tahomatech.com * * This code released under the GPL, and in the public domain * References to IKON left in place for compatibility and historical reasons * * Please send us code modifications and BUG reports */ /* * linux includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * tahoma ("ikon") includes */ #include "idr_changes.h" #include "idr_reg.h" #include "idr_io.h" #include "idr_var.h" /* * prototypes */ static int idr_init_module(void); static void idr_cleanup_module(void); static void idr_free_units(void); static int idr_open(struct inode *, struct file *); static int idr_close(struct inode *, struct file *); static ssize_t idr_read(struct file *, char *, size_t, loff_t *); static ssize_t idr_write(struct file *, const char *, size_t, loff_t *); static long idr_new_ioctl(struct file *, u_int, u_long); static int idr_ioctl(struct inode *, struct file *, u_int, u_long); static irqreturn_t idr_intr(int, void * IDR__PT_REGS); static int idr_strategy(struct idr_unit_t *, char *, int, int, int); static void plx_soft_reset(struct idr_unit_t *); static void idr_set_global_defaults(void); static int idr_init_one_board(struct idr_unit_t *, int); static void idr_set_board_defaults(struct idr_unit_t *, int); static int idr_dma_alloc(struct idr_unit_t *, int); static void idr_dma_free(struct idr_unit_t *, int); static int idr_map_regs(struct idr_unit_t *, int); static void idr_unmap_regs(struct idr_unit_t *, int); static int idr_map_or_copy_buf(struct idr_unit_t *, int, char *, int, int); static int idr_unmap_or_copy_buf(struct idr_unit_t *, int); static void idr_unmap_on_error(struct idr_unit_t *, int); static void idr_unmap_user_buf(struct idr_unit_t *, int); static int idr_map_user_buf(struct idr_unit_t *, int); static int idr_maplist_to_sg_list(struct idr_unit_t *, int); static int idr_sg_list_to_iopb_list(struct idr_unit_t *, int); static int idr_maplist_check(struct idr_unit_t *, int); /* * mutex and conditional variable stuff - was in ikon_mutex.h (Kaz Kylheku & wdw) */ static void idr_mutex_init(idr_mutex_t *); static void idr_mutex_lock(idr_mutex_t *); static void idr_mutex_unlock(idr_mutex_t *); static void idr_cond_init(idr_cond_t *); static int idr_cond_timed_wait_rel(idr_cond_t *, idr_mutex_t *, long); static void idr_cond_broadcast(idr_cond_t *); /* * configuration variables that may be specified at module install time * see idr_io.h for possible values * * each internal variable is paired with one that can be modified by insmod * * all of the function bits are kept separate, rather than combined into * three variables to preserve some kind of compatibility with the * solaris conf file */ static int speed_def = -1; static int dma_time_def = -1; static int attn_time_def = -1; static int rdy_time_def = -1; static int byte_swap_def = -1; static int cycle_pol_def = -1; static int busy_pol_def = -1; static int write_cycle_def = -1; static int read_cycle_def = -1; static int read_acf2_def = -1; static int open_f3_def = -1; static int open_f2_def = -1; static int open_f1_def = -1; static int write_f3_def = -1; static int write_f2_def = -1; static int write_f1_def = -1; static int read_f3_def = -1; static int read_f2_def = -1; static int read_f1_def = -1; static int max_boards = -1; static int max_phys_order = -1; /* 2**max_phys_order * PAGE_SIZE = max xfer */ module_param(speed_def, int, 0); module_param(dma_time_def, int, 0); module_param(attn_time_def, int, 0); module_param(rdy_time_def, int, 0); module_param(byte_swap_def, int, 0); module_param(cycle_pol_def, int, 0); module_param(busy_pol_def, int, 0); module_param(write_cycle_def, int, 0); module_param(read_cycle_def, int, 0); module_param(read_acf2_def, int, 0); module_param(open_f3_def, int, 0); module_param(open_f2_def, int, 0); module_param(open_f1_def, int, 0); module_param(write_f3_def, int, 0); module_param(write_f2_def, int, 0); module_param(write_f1_def, int, 0); module_param(read_f3_def, int, 0); module_param(read_f2_def, int, 0); module_param(read_f1_def, int, 0); module_param(max_phys_order, int, 0); module_param(max_boards, int, 0); /* * internal variables will use defaults if paired modifiable variables are still -1 after insmod * most of these variables have working versions kept in the unit structures on a per-board basis * this multi-layered approach is to preserve some similarity with the solaris driver */ static int idr_speed_def; static int idr_dma_time_def; static int idr_attn_time_def; static int idr_rdy_time_def; static int idr_byte_swap_def; static int idr_cycle_pol_def; static int idr_busy_pol_def; static int idr_write_cycle_def; static int idr_read_cycle_def; static int idr_read_acf2_def; static int idr_open_f3_def; static int idr_open_f2_def; static int idr_open_f1_def; static int idr_write_f3_def; static int idr_write_f2_def; static int idr_write_f1_def; static int idr_read_f3_def; static int idr_read_f2_def; static int idr_read_f1_def; static int idr_max_phys_order; static int idr_max_boards; /* * some global variables */ int idr_device_id_list[] = {IDR_DEVICE_ID_LIST, 0}; /* supported board PCI IDs */ static int idr_boards_found; /* number of boards actually detected */ static int idr_boards_attached; /* number of boards successfully attached */ static int idr_module_initialized; /* non zero if any board attaches and module */ /* initialized successfully */ static int idr_device_major; /* major number dynamically assigned to this driver */ static int idr_max_buf_pages; /* # of pages in copy buf = 2**idr_max_phys_order */ /* if copy buff used, copies will be to 0 offset in buf */ /* so extra page not necessary */ static int idr_max_buf_bytes; /* in bytes = idr_max_buf_pages * PAGE+SIZE */ static int idr_max_sg_length; /* idr_max_buf_pages + 1 (allows for user buff offset) */ /* MUST TRACK KIOBUF MAP SIZE AND COPY BUF SIZE */ static int idr_iopb_mem_size; /* size of mem allocated for iopb list */ /* * pointer at base of unit structure array */ static struct idr_unit_t *idr_unit_base_p; /* * declare dummy variables used to the left of = when we read a board * register to force the write cache to flush a register write to the bus * * may not be necessary in PC architecture */ static volatile u_long read_dump_0; static volatile u_long read_dump_1; struct file_operations idr_fops = { owner:THIS_MODULE, read:idr_read, write:idr_write, ioctl:idr_ioctl, IDR_UNLOCKED_IOCTL IDR_COMPAT_IOCTL open:idr_open, release:idr_close, }; /* * do global initialization and resource allocation, per-instance init * and resource allocation (interrupts, copy buffer if required), and * register the driver * * unless debug printks are enabled, init_module and cleanup_module are silent, * with the exception of a dma/copy mode anouncement and a single success or * failure message for each board instance */ static int idr_init_module(void) { register struct idr_unit_t *unit_p; int instance; int unit_array_size; u_long temp; struct pci_dev *temp_pci_dev_p; int *device_id_list_p = idr_device_id_list; DPRINT("entering init_module"); temp = LINUX_VERSION_CODE; DPRINT("compiled under linux version %ld.%ld.%ld uts release:\n" " %s", (temp >> 16) & 0xffff, (temp >> 8) & 0xff, temp & 0xff, UTS_RELEASE); /* * identify our memory mode/copy buffer status in msg log */ IPRINT(IDR_DMA_MODE_MSG); idr_module_initialized = 0; /* * set board and driver global defaults from parameters * includes things like iopb mem size */ idr_set_global_defaults(); /* * allocate and zero space for max_boards unit structs */ unit_array_size = idr_max_boards * sizeof(struct idr_unit_t); idr_unit_base_p = (struct idr_unit_t *) kmalloc(unit_array_size, GFP_KERNEL); if (idr_unit_base_p == NULL) { EPRINT("can't allocate unit struct array (lmalloc error)!"); return -ENOMEM; } memset(idr_unit_base_p, 0, unit_array_size); DPRINT("allocated unit structure array,\n" " idr_unit_base_p = 0x%p, size = 0x%x", idr_unit_base_p, unit_array_size); /* * loop, looking for our boards - there better be at least one */ DPRINT("starting search for boards"); idr_boards_found = 0; idr_boards_attached = 0; instance =0; while(*device_id_list_p) { temp_pci_dev_p = NULL; DPRINT("probing for %x boards", *device_id_list_p); /* * loop while we keep finding boards w/this id * * make sure we don't exceed max boards and go past the end * of the unit struct array * * each get_device call decrements the previous pci dev ref count, * so bump the ref count for each found - dec ("put") at unload time * (we need pci dev to persist since we use it elsewhere) */ while((temp_pci_dev_p = pci_get_device(IKON_VENDOR_ID, *device_id_list_p, temp_pci_dev_p)) != NULL) { /* * if we are still finding boards beyond max allowed, warn, * drop the ref count on the board we just found, and exit the loop * * we just exit the inner loop - and may drop in again if more * IDs in the list - is this OK ??? */ if(instance >= idr_max_boards) { WPRINTI("boards found > max boards!\n" " max boards should be increased"); pci_dev_put(temp_pci_dev_p); break; } unit_p = idr_unit_base_p + instance; unit_p->instance = instance; /* * save pointer to this board's pci dev structure * and bump the ref count, since next loop through pci_get_device * will decrement it */ unit_p->pci_dev_p = temp_pci_dev_p; pci_dev_get(unit_p->pci_dev_p); DPRINTI("%x board found, initializing unit structure", *device_id_list_p); /* * do per-board init and set attach flag and bump * attached count if successful (==0) * bump instance even if not attached since board exists * and takes space in the array */ if(!idr_init_one_board(unit_p, instance)) { DPRINTI("%x board attached", *device_id_list_p); unit_p->unit_attached = 1; idr_boards_attached++; } else { EPRINTI("idr_init_one_board error! board not attached!"); } idr_boards_found++; instance++; } /* while board found */ device_id_list_p++; } /* while *device_id_list_p */ DPRINT("no (more) boards found, ending search"); /* * if no boards have attached, free any resources assigned to found boards * (pci_dev reference counts), give back the unit structure array and return an error * * if no boards are found, just give back the unit struct array and print a different * message */ if (!idr_boards_attached) { if (!idr_boards_found) WPRINT("no boards found! module not initialized!"); else WPRINT("%d board(s) found but no boards attached! module not initialized!", idr_boards_found); idr_free_units(); kfree(idr_unit_base_p); return -ENODEV; } /* * register the module, and get dynamic major number assigned * **TODO** go to new style cdev-type registration */ idr_device_major = register_chrdev(0, "idr", &idr_fops); if (idr_device_major < 0) { EPRINT("register_chrdev error! module not initialized!"); /* * free all resources owned by attached boards * give back the unit array when done */ idr_free_units(); kfree(idr_unit_base_p); return -ENODEV; } DPRINT("driver registered, major # = %d", idr_device_major); /* * flag module as initialized and return good status to insmod */ idr_module_initialized = 1; IPRINT("%d board(s) found, %d board(s) attached, module initialized", idr_boards_found, idr_boards_attached); return 0; } /* end of init_module */ /* * idr_free_units walks through the allocated unit structure array and frees all the * resources of any board that was successfully attached, including iopb memory, * scatterlist, user buf mapping space, copy buffer (if allocated), register mappings, * and interrupt line, and disables the device * * attached boards are fully reset before anything is freed * * it looks at all the slots, up to max_boards, not up to boards_attached, because it is * theoretically possible for pcibios errors to cause some boards to be found, but not * attach (VERY UNLIKELY) * * even if not attached, it "puts" the board to decrement the ref count * * THIS ROUTINE DOES NOT RETURN THE UNIT STRUCTURE ARRAY - THAT IS LEFT TO THE CALLING ROUTINE */ static void idr_free_units(void) { register struct idr_unit_t *unit_p; int instance; int boards_detached = 0; /* * look at each unit structure element of array * if board exists (pci_dev_p not zero) then check for * attached and do the appropriate stuff */ DPRINT("max boards = %d, boards found = %d, boards attached = %d", idr_max_boards, idr_boards_found, idr_boards_attached); for (instance = 0; instance < idr_max_boards; instance++) { unit_p = idr_unit_base_p + instance; if(unit_p->pci_dev_p) { if (unit_p->unit_attached) { /* * issue soft reset to clear plx and idr logic (and disable * dma and ints) */ plx_soft_reset(unit_p); DPRINTI("soft_reset issued"); /* * soft reset leaves some int enb bits on -- we will just hammer * off all the dma and int enable bits we can think of (most are * already cleared) */ PLX_PUTL(PLX_INT_CSTAT, 0); PLX_PUTL(PLX_DMA_CMD_STAT_BOTH, 0); IDR_PUTL(IDR_LATCHED_FUNCTIONS, 0); DPRINTI("freeing interrupt, mappings, copy buffer (if any),\n" " scatterlist, iopb memory, and disabling device"); free_irq(unit_p->pci_dev_int_level, (void *) unit_p); idr_unmap_regs(unit_p, instance); idr_dma_free(unit_p, instance); pci_disable_device(unit_p->pci_dev_p); unit_p->unit_attached = 0; boards_detached++; } else { DPRINTI("this instance not attached - no action taken"); } /* * dec ref count incremented w/pci_get_device - if board exists */ DPRINTI("decrementing ref count"); pci_dev_put(unit_p->pci_dev_p); } } /* end of for (instance) */ IPRINT("%d board(s) detached", boards_detached); } /* end of idr_free_units */ /* * When our driver is unloaded, cleanup_module cleans up and frees the resources * we allocated in init_module * unregister the driver return resources on an per instance basis (interrupts, * kiovec, iopb stuff, etc)and free the unit structure array */ static void idr_cleanup_module(void) { DPRINT("entering cleanup_module"); if (!idr_module_initialized) { EPRINT("cleanup called when module not previously initialized!"); return; } /* * unregister_chrdev always returned 0, and now it's void */ unregister_chrdev(idr_device_major, "idr"); DPRINT("device (driver) successfully unregistered"); /* * call idr_free_units to release resources * and turn off attached flag(s) * * return unit structure memory */ idr_free_units(); kfree(idr_unit_base_p); idr_module_initialized = 0; /* * this is as good a place as any to do phony references to the read dump varaibles * to try to absolutely guarantee that the optimizer won't remove our cache flush reads * * and to try to shut lint up */ read_dump_0 += read_dump_1; return; } /* * do various error checking, move the defaults into the boards logic, * then make the board available for read, write, and ioctl calls * * bump the usage count so driver can't be unlaoded until close called * * **TODO** we don't protect the already open test that enforces * exclusive open. that race is unlikely, and the way our boards get * used 2 different processes will never try to open the same board * anyway - but to be complete we should probably protect w/a semaphore * or mutex (or atomic test - but that will also require an add'l state * variable - open flag is wrong sense */ static int idr_open(struct inode *inode_p, struct file *file_p) { int instance; register struct idr_unit_t *unit_p; instance = MINOR(inode_p->i_rdev); DPRINTI("entering idr_open"); if ((instance < 0) || (instance >= idr_max_boards)) { EPRINTI("instance out of range!"); return -ENODEV; } unit_p = idr_unit_base_p + instance; DPRINTI("unit pointer = 0x%p", unit_p); if (unit_p->unit_attached == 0) { WPRINTI("open attempted when board not attached!"); return -ENODEV; } /* * Only allow a single open */ spin_lock(&unit_p->open_lock); if (unit_p->unit_open != 0) { DPRINTI("open called when already open!"); spin_unlock(&unit_p->open_lock); return -EBUSY; } unit_p->unit_open = 1; spin_unlock(&unit_p->open_lock); /* * initialize DVMA and DR11 logic * SOFT RESET WILL ALSO CAUSE AN INIT TO BE SENT TO THE DEVICE! * if this causes problems, the plx_soft_reset() should be commented out */ plx_soft_reset(unit_p); /* * initialize various defaults using values in soft state * from global values set in init_module() */ /* * initialize time out values to defaults */ unit_p->dma_time = (u_long) (HZ * unit_p->dma_time_def); unit_p->attn_time = (u_long) (HZ * unit_p->attn_time_def); unit_p->rdy_time = (u_long) (HZ * unit_p->rdy_time_def); /* * set read and write pulse and function values to defaults */ unit_p->read_fcn = unit_p->read_fcn_def; unit_p->write_fcn = unit_p->write_fcn_def; unit_p->read_pulse = unit_p->read_pulse_def; unit_p->write_pulse = unit_p->write_pulse_def; /* * set the mode and latch registers to their default values */ IDR_PUTL(IDR_LATCHED_FUNCTIONS, unit_p->latch_reg_def); IDR_PUTL(IDR_MODE, unit_p->mode_reg_def); /* * set plx chip (9060sd and later) to default endian mode * * note that normal default is big_endian to un-swap the byte * swapping that the memory path does to 16 bit words in SPARC * and little_endian in x86 systems */ PLX_PUTL(PLX_ENDIAN_REG, unit_p->endian_def); unit_p->unit_flags = 0; DPRINTI("open complete"); return 0; } /* * make the board unavailable for read, write and ioctl calls * decrement use count, so driver can be unloaded if desired */ static int idr_close(struct inode *inode_p, struct file *file_p) { int instance; register struct idr_unit_t *unit_p; instance = MINOR(inode_p->i_rdev); DPRINT("entering idr_close"); if ((instance < 0) || (instance >= idr_max_boards)) { EPRINTI("instance out of range!"); return -ENODEV; } unit_p = idr_unit_base_p + instance; DPRINTI("Unit pointer = 0x%p", unit_p); if (unit_p->unit_open == 0) { WPRINTI("close attempted when board not open!"); return -ENODEV; } unit_p->unit_open = 0; /* * reset dma logic, DR11 logic, and flush fifo * THIS CAUSES AN INIT TO BE SENT TO THE ATTACHED DEVICE! * if the init causes problems the soft reset should be commented out */ plx_soft_reset(unit_p); DPRINTI("soft_reset issued"); DPRINTI("close complete"); return 0; } /* * set up dr11 range counter (if automatic mode). set transfer direction * * loop on data transfer from device to user memory unitl full * user count exhausted * * NOTE THAT THERE ARE SOME ERROR RETURNS IN THIS CODE -- IF WE EVER NEED * A MUTEX HERE, OR ITS EQUIVALENT, THESE WILL ALL NEED TO SET AN ERROR CODE AND * GOTO .. TO AVOID LEAKING OUT THE SIDE OF THE MUTEX */ static ssize_t idr_read(struct file *file_p, char *user_buf_p, size_t user_count, loff_t * loff_p) { struct inode *inode_p; register struct idr_unit_t *unit_p; int retval; int instance; int dma_count; int range; int strategy_retval; int first_dma_flag; int last_dma_flag; /* * we always say we xferred all the bytes, unless error * the plx chip can't read back the dma count anyway * * some idea of the residual after a failure can be read from the dr11 range counter */ retval = user_count; inode_p = file_p->f_dentry->d_inode; instance = MINOR(inode_p->i_rdev); DPRINTI("entering read routine, user_buf_p = 0x%p, count = 0x%x", user_buf_p, (unsigned int)user_count); if ((instance < 0) || (instance >= idr_max_boards)) { EPRINTI("instance out of range!"); return -ENODEV; } unit_p = idr_unit_base_p + instance; if (!unit_p->unit_open) { EPRINTI("read called when unit not open!"); return -EIO; } /* * clear the timeout, multicycle error, parity, sig received, and "waiting for" flags * strategy will set the waiting for dvma or eor flag. set input flag */ unit_p->unit_flags &= IDR_CLEAR_FLAGS; unit_p->unit_flags |= IDR_INPUT; /* * buffer size and start address must be even (16 bit aligned) * and buffer size must be non-zero */ if ((unsigned long) user_buf_p & 1) { WPRINTI("odd buffer address!"); return -EINVAL; } if ((user_count == 0) || (user_count & 1)) { WPRINTI("zero or odd buffer size!"); return -EINVAL; } /* * if automatic mode, set up dr11 range count and set first_dma_flag * to indicate first call to strategy in auto mode * * first dma flag will be set back to 0 after first strategy call */ if (!(unit_p->unit_flags & IDR_MANUAL)) { DPRINTI("auto mode, setting range counter to 0x%x (words - 1)", (unsigned int)(user_count >> 1) - 1); /* * dr11 counter wants WORD count minus 1 */ range = (user_count >> 1) - 1; if (range > IDR_DR11_MAXBLOCK) { WPRINTI("DR11 range count too large!"); return -EINVAL; } IDR_PUTL(IDR_RANGE_HIGH, range >> 16); IDR_PUTL(IDR_RANGE_MID, range >> 8); IDR_PUTL(IDR_RANGE_LOW, range); first_dma_flag = 1; /* * we have some bookkeeping to do that would normally be in strategy * but since we may have to call strategy multiple times, and we * only want to do this stuff once, we will have to do it here */ /* * in auto mode, pulse off any error flags (leave on for later code if manual) */ IDR_PUTL(IDR_116_PULSES, RESET_EOR_FLAG | RESET_ATTENTION_FLAG | RESET_ERROR_FLAGS); /* * force off idr dma enb and direction bit * set input mode, then re-enable dma * we don't fiddle interrupts here - that will be done in strategy */ IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~(IDR_DMA_ENABLE | DMA_INPUT_MODE)); IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) | DMA_INPUT_MODE); IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) | IDR_DMA_ENABLE); } else { /* * in manual mode, just clear first dma flag * pulses will be issued by user via ioctl */ first_dma_flag = 0; } /* * loop on strategy while user_count >0 * strategy expects the virtual address of the next chunk of the user buffer */ while (user_count > 0) { dma_count = (user_count < idr_max_buf_bytes) ? user_count : idr_max_buf_bytes; DPRINTI("inside while loop, buf_pointer = 0x%p, dma_count = 0x%x," " first_dma_flag = 0x%x", user_buf_p, dma_count, first_dma_flag); /* * if auto mode and this is the last call to strategy required to satisfy * user count, set last_dma_flag - it is probably not going to be used by * strategy for input operations, but output will require it */ if ((!(unit_p->unit_flags & IDR_MANUAL)) && (dma_count >= user_count)) { DPRINTI("setting last_dma_flag to 1"); last_dma_flag = 1; } else { DPRINTI("setting last_dma_flag to 0"); last_dma_flag = 0; } DPRINTI("calling idr_strategy"); strategy_retval = idr_strategy(unit_p, user_buf_p, dma_count, first_dma_flag, last_dma_flag); DPRINTI("idr_strategy returns 0x%x", strategy_retval); if (strategy_retval) { WPRINTI("idr_strategy returns error = %d", strategy_retval); return strategy_retval; } user_buf_p += dma_count; user_count -= dma_count; first_dma_flag = 0; } /* end of while(user_count) */ /* * if automatic mode - turn off dma enable, then check the board for * multicycle error or parity error and set flags accordingly * this was done in strategy in the solaris driver * * regardless of mode, we will then look at those flags and the sig received * and timeout flags passed from strategy, and return errors accordingly */ if (!(unit_p->unit_flags & IDR_MANUAL)) { IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~IDR_DMA_ENABLE); if (IDR_GETL(IDR_FLAGS) & PARITY_ERROR_FLAG) { DPRINTI("parity error!"); unit_p->unit_flags |= IDR_PAR_ERR; } if (IDR_GETL(IDR_FLAGS) & MULTI_CYCLE_ERROR_FLAG) { WPRINTI("multi-cycle error!"); unit_p->unit_flags |= IDR_MCYL_ERR; } } /* * check flags for timeout or multicycle error or sig received * * most dr11 devices do not check parity on the dr11 cable * most tahoma dr11s check dr11 cable parity and flag an error * * we will not report parity errors as read or write errors here, since * most applications (that don't support parity) will cause the flag to * set often * * parity errors can be tested for by examining the driver flag word, or * the board's flag register using the IDRIO_GET_NEW_FLAGS ioctl * * if parity checking is desired within the read or write routine, add * the following code and re make the driver * * if(unit_p->unit_flags & IDR_PAR_ERR) { * printk(KERN_WARNING "idr_read: istance %d: parity error!\n", instance); * return -EIO; * } */ if (unit_p->unit_flags & (IDR_DVMA_TIMEOUT | IDR_EOR_TIMEOUT)) { WPRINTI("DMA timeout!"); return -EIO; } if (unit_p->unit_flags & IDR_MCYL_ERR) { WPRINTI("Multicycle error!"); return -EIO; } if (unit_p->unit_flags & IDR_SIG_RECEIVED) { WPRINTI("signal received!"); return -EINTR; } DPRINTI("leaving read routine"); return (retval); } /* * set up dr11 range counter (if automatic mode), set direction of transfer * * loop on dma transfer to device until user count exhausted * * NOTE THAT THERE ARE LOTS OF ERROR RETURNS IN THIS CODE -- IF WE EVER NEED A MUTEX HERE, * OR ITS EQUIVALENT, THESE WILL ALL NEED TO SET AN ERROR CODE AND GOTO ... TO AVOID * LEAKING OUT THE SIDE OF THE MUTEX */ static ssize_t idr_write(struct file *file_p, const char *user_buf_p, size_t user_count, loff_t * loff_p) { struct inode *inode_p; register struct idr_unit_t *unit_p; int retval; int instance; int dma_count; int range; int strategy_retval; int first_dma_flag; int last_dma_flag; /* * we always say we xferred all the bytes, unless error * the plx chip can't read back the dma count anyway * * some idea of the residual after a failure can be read from the dr11 range counter */ retval = user_count; inode_p = file_p->f_dentry->d_inode; instance = MINOR(inode_p->i_rdev); DPRINTI("entering write routine, user_buf_p = 0x%p, count = 0x%x", user_buf_p, (unsigned int)user_count); if ((instance < 0) || (instance >= idr_max_boards)) { EPRINTI("instance out of range!"); return -ENODEV; } unit_p = idr_unit_base_p + instance; if (!unit_p->unit_open) { EPRINTI("write called when unit not open!"); return -EIO; } /* * clear the timeout, multicycle error, parity, sig received, and "waiting for" flags * strategy will set the waiting for dvma or eor flag. clear input flag == output mode */ unit_p->unit_flags &= IDR_CLEAR_FLAGS; unit_p->unit_flags &= ~IDR_INPUT; /* * buffer size and start address must be even (16 bit aligned) * and buffer size must be non-zero */ if ((unsigned long) user_buf_p & 1) { WPRINTI("odd buffer address!"); return -EINVAL; } if ((user_count == 0) || (user_count & 1)) { WPRINTI("zero or odd buffer size!"); return -EINVAL; } /* * if automatic mode, set up dr11 range count and set first_dma_flag * to indicate first call to strategy in auto mode * * first_dma_flag will be set back to 0 after first strategy call */ if (!(unit_p->unit_flags & IDR_MANUAL)) { DPRINTI("auto mode, setting range counter to 0x%x (words - 1)", (unsigned int)(user_count >> 1) - 1); /* * dr11 counter wants WORD count minus 1 */ range = (user_count >> 1) - 1; if (range > IDR_DR11_MAXBLOCK) { WPRINTI("DR11 range count too large!"); return -EINVAL; } IDR_PUTL(IDR_RANGE_HIGH, range >> 16); IDR_PUTL(IDR_RANGE_MID, range >> 8); IDR_PUTL(IDR_RANGE_LOW, range); first_dma_flag = 1; /* * we have some bookkeeping to do that would normally be in strategy * but since we may have to call strategy multiple times, and we * only want to do this stuff once, we will have to do it here */ /* * in auto mode, pulse off any error flags (leave on for later code if manual) */ IDR_PUTL(IDR_116_PULSES, RESET_EOR_FLAG | RESET_ATTENTION_FLAG | RESET_ERROR_FLAGS); /* * force off idr dma enb and direction bit * then re-enable dma in output mode * * we don't fiddle interrupts here - that will be done in strategy */ IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~(IDR_DMA_ENABLE | DMA_INPUT_MODE)); IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) | IDR_DMA_ENABLE); } else { /* * in manual mode, just clear first_dma_flag * pulses will be issued by user via ioctl */ first_dma_flag = 0; } /* * loop on strategy while user_count > 0 * strategy expects the virtual address of the next chunk of the user buffer */ while (user_count > 0) { dma_count = (user_count < idr_max_buf_bytes) ? user_count : idr_max_buf_bytes; DPRINTI("inside while loop, buf_pointer = 0x%p, dma_count = 0x%x," " first_dma_flag = 0x%x", user_buf_p, dma_count, first_dma_flag); /* * if auto mode and this is the last call to strategy required to satisfy * user count, set last_dma_flag - it is probably not going to be used by * strategy for input operations, but output will require it */ if ((!(unit_p->unit_flags & IDR_MANUAL)) && (dma_count >= user_count)) { DPRINTI("setting last_dma_flag to 1"); last_dma_flag = 1; } else { DPRINTI("setting last_dma_flag to 0"); last_dma_flag = 0; } DPRINTI("calling idr_strategy"); strategy_retval = idr_strategy(unit_p, (char *) user_buf_p, dma_count, first_dma_flag, last_dma_flag); DPRINTI("idr_strategy returns 0x%x", strategy_retval); if (strategy_retval) { WPRINTI("idr_strategy returns error = %d", strategy_retval); return strategy_retval; } /* * bump user buffer pointer, and decrement counter * force first_dma_flag off (if on) */ user_buf_p += dma_count; user_count -= dma_count; first_dma_flag = 0; } /* end of while(user_count) */ /* * if auto mode, make sure idr dma enb is off * * check for multicycle error and flag in unit structure * in manual mode, this stuff is done in block_end * * we will then look at the flags we just set, and return * errors, if appropriate * * (this looks weird, but it happened when some of the hardware * error checking moved here from strategy for the linux driver) * */ if (!(unit_p->unit_flags & IDR_MANUAL)) { IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~IDR_DMA_ENABLE); if (IDR_GETL(IDR_FLAGS) & MULTI_CYCLE_ERROR_FLAG) { WPRINTI("multi-cycle error!"); unit_p->unit_flags |= IDR_MCYL_ERR; } } /* * check flags for timeout or multicycle error or sig received * doesn't make any sense to test for parity error on output */ if (unit_p->unit_flags & (IDR_DVMA_TIMEOUT | IDR_EOR_TIMEOUT)) { WPRINTI("DMA timeout!"); return -EIO; } if (unit_p->unit_flags & IDR_MCYL_ERR) { WPRINTI("Multicycle error!"); return -EIO; } if (unit_p->unit_flags & IDR_SIG_RECEIVED) { WPRINTI("signal received!"); return -EINTR; } DPRINTI("leaving write routine, return value = 0x%x", retval); /* * retval should be original byte count if we get to this point */ return retval; } /* * old-style wrapper for new ioctl entry points (for older kernels) */ static int idr_ioctl(struct inode *inode_p, struct file *file_p, u_int cmd, u_long arg) { DPRINT("instance %d: old ioctl called, calling new ioctl", MINOR(file_p->f_dentry->d_inode->i_rdev)); return idr_new_ioctl(file_p, cmd, arg); } /* * provide mechanism for controlling device and driver * * THIS CODE USES A FEW ERROR RETURNS - IF WE SOMEDAY NEED A MUTEX OR EQUIVALENT, GO BACK TO * SOLARIS STYLE .. SET RETVAL CODES AND JUMP TO IOCTLEXIT, SO WE DON'T * RISK LEAKING OUT THE SIDE OF A MUTEX!! * * note that the ioctl routine treats arg as a pointer - to u32 in this version */ static long idr_new_ioctl(struct file *file_p, u_int cmd, u_long arg) { struct inode *inode_p; register struct idr_unit_t *unit_p; u32 return_array[IDR_RETURN_ARRAY_SIZE]; u32 bits; u32 lt; u_int command; int count; int instance; int i; int wait_return; inode_p = file_p->f_dentry->d_inode; instance = MINOR(inode_p->i_rdev); DPRINTI("entering ioctl routine, command = 0x%x, arg = 0x%lx", cmd, arg); if ((instance < 0) || (instance >= idr_max_boards)) { EPRINTI("instance out of range!"); return -ENODEV; } unit_p = idr_unit_base_p + instance; if (!unit_p->unit_open) { EPRINTI("ioctl called when unit not open!"); return -EIO; } /* * get command and argument size */ command = cmd & IDRIO_CMD_MASK; count = (cmd & IDRIO_COUNT_MASK) >> _IOC_SIZESHIFT; DPRINTI("masked command = 0x%x, argument size = 0x%x", command, count); /* * get first word of argument (even if we are eventually doing a * copyout operation) */ if (copy_from_user(&bits, (caddr_t) arg, sizeof(bits))) { EPRINTI("copy_from_user error!"); return -EINVAL; } DPRINTI("arg = 0x%lx, *arg = 0x%x", arg, bits); /* * use MASK to strip the count from cases */ #define MASK IDRIO_CMD_MASK switch (command) { case MASK & IDRIO_SET_MODE: /* set operating mode using old sbus bit */ /* definitions to preserve compatibility with */ /* existing applications */ DPRINTI("at set mode"); lt = bits & IDR_SPEED_MASK; /* speed bits are in the same place */ if (bits & IDR_RDYT) lt |= LONG_READY; if (bits & IDR_BDIS) lt |= DISABLE_CRQ_B; if (bits & IDR_CRQP) lt |= CYCLE_POLARITY; if (bits & IDR_BSYP) lt |= BUSY_POLARITY; if (bits & IDR_RDISX) lt |= DISABLE_RANGE; IDR_PUTL(IDR_MODE, lt); /* * check dma byte swap mode - request for swapping will turn off big endian * mode (SPARC) SPARC swaps bytes between dma and memory, so big_endian = swap * again, to give un-swapped data * x86 doesn't swap - so SWAP really means swap in the plx hardware */ if (bits & IDR_SWAP) PLX_PUTL(PLX_ENDIAN_REG, PLX_GETL(PLX_ENDIAN_REG) | DMA_1_BIG_ENDIAN); else PLX_PUTL(PLX_ENDIAN_REG, PLX_GETL(PLX_ENDIAN_REG) & ~DMA_1_BIG_ENDIAN); return 0; break; case MASK & IDRIO_IMM_FCN: /* set function bits immediately */ DPRINTI("at immediate funtion"); /* * just mask the function bits and stuff them directly into the latched * function register - the other register bits should all be either * zero or don't care at this point! * * the pci and sbus boards have the funtions bits in the same places * in their respective registers - so no bit fiddling necessary */ IDR_PUTL(IDR_LATCHED_FUNCTIONS, bits & FUNCTION_MASK); return 0; break; case MASK & IDRIO_READ_FCN: /* save fcn bits for use at read start */ DPRINTI("at read function"); unit_p->read_fcn = (bits & FUNCTION_MASK); return 0; break; case MASK & IDRIO_WRITE_FCN: /* save fcn bits for use at write start */ DPRINTI("at write function"); unit_p->write_fcn = (bits & FUNCTION_MASK); return 0; break; case MASK & IDRIO_IMM_PULSE: /* issue pulses asap */ DPRINTI("at immediate pulse"); /* * wait for attention off if issuing go pulse * wait 100 us max - ?????? */ if (bits & IDR_GO) { i = 0; while ((IDR_GETL(IDR_STATUS) & ATTENTION) && (i < 100)) { udelay(1); i++; } if (IDR_GETL(IDR_STATUS) & ATTENTION) { WPRINTI("at IMM_PULSE: attempt to issue GO while ATTENTION true!"); return -EIO; } } /* * fiddle bits to maintain sbus driver compatibility */ lt = 0; if (bits & IDR_TERM) lt |= SET_READY; if (bits & IDR_INIT) lt |= DEVICE_INIT; if (bits & IDR_ACF2) lt |= ACLO_FCN_2; if (bits & IDR_CYCL) lt |= SOFT_CYCLE; if (bits & IDR_GO) lt |= GO; IDR_PUTL(IDR_DEVICE_PULSES, lt); /* * we will allow a master clear pulse here - since the sbus driver did * but it should not be used lightly * it clears the idr logic only, not the plx logic * we will also permit a reset attention flag pulse - for compatibility */ lt = 0; if (bits & IDR_RATN) lt |= RESET_ATTENTION_FLAG; if (bits & IDR_MCLR) lt |= MASTER_CLEAR; IDR_PUTL(IDR_116_PULSES, lt); return 0; break; case MASK & IDRIO_READ_PULSE: /* save pulses for read start (in pci format) */ DPRINTI("at read pulse"); /* * fiddle bits to maintain sbus driver compatibility */ lt = 0; if (bits & IDR_TERM) lt |= SET_READY; if (bits & IDR_INIT) lt |= DEVICE_INIT; if (bits & IDR_ACF2) lt |= ACLO_FCN_2; if (bits & IDR_CYCL) lt |= SOFT_CYCLE; if (bits & IDR_GO) lt |= GO; unit_p->read_pulse = lt; return 0; break; case MASK & IDRIO_WRITE_PULSE: /* save pulses for write start */ DPRINTI("at write pulse"); /* * fiddle bits to maintain sbus driver compatibility */ lt = 0; if (bits & IDR_TERM) lt |= SET_READY; if (bits & IDR_INIT) lt |= DEVICE_INIT; if (bits & IDR_ACF2) lt |= ACLO_FCN_2; if (bits & IDR_CYCL) lt |= SOFT_CYCLE; if (bits & IDR_GO) lt |= GO; unit_p->write_pulse = lt; return 0; break; case MASK & IDRIO_SET_DMA_TIME: /* set dma timeout parameter - in ticks */ DPRINTI("at set dma time"); if (bits < DMA_TIME_MIN) bits = DMA_TIME_MIN; if (bits > DMA_TIME_MAX) bits = DMA_TIME_MAX; unit_p->dma_time = (u_long) (bits * HZ); return 0; break; case MASK & IDRIO_SET_ATTN_TIME: /* set wait for attention timeout value */ DPRINTI("at set attn time"); if (bits < ATTN_TIME_MIN) bits = ATTN_TIME_MIN; if (bits > ATTN_TIME_MAX) bits = ATTN_TIME_MAX; unit_p->attn_time = (u_long) (bits * HZ); return 0; break; case MASK & IDRIO_SET_RDY_TIME: /* set wait for ready timeout value */ DPRINTI("at set rdy time"); if (bits < RDY_TIME_MIN) bits = RDY_TIME_MIN; if (bits > RDY_TIME_MAX) bits = RDY_TIME_MAX; unit_p->rdy_time = (u_long) (bits * HZ); return 0; break; case MASK & IDRIO_ATTN_WAIT: /* wait for attention to set attf */ DPRINTI("at attn wait"); /* * clear the "waiting-for" flags in the soft state * these flags are maintained for compatibility with the sbus driver * they are probably not necessary */ unit_p->unit_flags &= IDR_CLEAR_FLAGS; /* * if the attention flag is already set, clear it and return */ if (IDR_GETL(IDR_FLAGS) & ATTENTION_FLAG) { DPRINTI("at attn wait, attf already set, returning w/out waiting"); IDR_PUTL(IDR_116_PULSES, RESET_ATTENTION_FLAG); return 0; } idr_mutex_lock(&unit_p->mutex); /* * set "waiting-for" flag */ unit_p->unit_flags |= IDR_ATTN_WAIT; /* * set sleeping flag, so we can detect an abnormal return from sleep */ unit_p->sleeping = 1; /* * enable attention flag interrupts in the idr logic, and local ints * in the plx logic * we have to or in the idr bits, since the speed bits are * also in that register */ IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) | ATTENTION_INT_ENB); PLX_PUTL(PLX_INT_CSTAT, PCI_INTERRUPT_ENABLE | PCI_LOCAL_INT_ENABLE); /* * snooze until attention interrupt, timeout, or signal */ DPRINTI("at attn wait, time_now = %ld, unit_p->attn_time = %d", jiffies, unit_p->attn_time); /* * it looks like (from kernel source) that this returns 0 if timeout, >0 if not */ wait_return = idr_cond_timed_wait_rel(&unit_p->cond, &unit_p->mutex, unit_p->attn_time); /* * make sure interrupt enables are off - we may have gotten here * via signal or timeout */ IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~ATTENTION_INT_ENB); PLX_PUTL(PLX_INT_CSTAT, 0); idr_mutex_unlock(&unit_p->mutex); /* * find out why we woke up */ if (unit_p->sleeping) { unit_p->sleeping = 0; DPRINTI("at wait for attention, abnormal return from idr_cond_timed_wait_rel!"); if (wait_return == IDR_COND_WAIT_TIMEOUT) { /* * timeout may not be an error - so no error msg * let caller test flags for timeout */ DPRINTI("timeout waiting for attention!"); unit_p->unit_flags |= IDR_ATTN_TIMEOUT; return -EIO; } if (wait_return == IDR_COND_WAIT_SIGNAL) { /* * signal is not exactly an error - but send to console log * return EINTR to caller can decide what to do */ WPRINTI("signal while waiting for attention!"); unit_p->unit_flags |= IDR_SIG_RECEIVED; return -EINTR; } } /* if sleeping */ /* * clear attention flag */ IDR_PUTL(IDR_116_PULSES, RESET_ATTENTION_FLAG); return 0; break; case MASK & IDRIO_RDY_WAIT: /* wait for REDY to go true from attn or eor */ /* if already set - just return */ /* look at flags to figure out why redy was */ /* set. if we were waiting for eor and got */ /* an attention also - the attn flag is left */ /* on since it might represent an incoming */ /* attention that followed the block xfer */ DPRINTI("at ready wait"); unit_p->unit_flags &= IDR_CLEAR_FLAGS; if (!(IDR_GETL(IDR_STATUS) & READY)) { DPRINTI("at ready wait, board not already ready"); idr_mutex_lock(&unit_p->mutex); /* * set "waiting-for" flag */ unit_p->unit_flags |= IDR_RDY_WAIT; /* * set sleeping flag, so we can detect an abnormal return from sleep */ unit_p->sleeping = 1; /* * enable attention and eor flag interrupts in the idr logic, and * local ints in the plx logic * we have to or in the idr bits, since the speed bits are * also in that register */ IDR_PUTL(IDR_LATCHED_FUNCTIONS, (IDR_GETL(IDR_LATCHED_FUNCTIONS) | ATTENTION_INT_ENB | END_OF_RANGE_INT_ENB)); PLX_PUTL(PLX_INT_CSTAT, (PCI_INTERRUPT_ENABLE | PCI_LOCAL_INT_ENABLE)); /* * snooze until attention interrupt, timeout, or signal */ DPRINTI("at ready wait, time_now = %ld, unit_p->rdy_time = %d", jiffies, unit_p->rdy_time); wait_return = idr_cond_timed_wait_rel(&unit_p->cond, &unit_p->mutex, unit_p->rdy_time); /* * make sure interrupt enables are off - we may have gotten here * via signal or timeout */ IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~(ATTENTION_INT_ENB | END_OF_RANGE_INT_ENB)); PLX_PUTL(PLX_INT_CSTAT, 0); idr_mutex_unlock(&unit_p->mutex); /* * find out why we woke up */ if (unit_p->sleeping) { DPRINTI("at rdy wait, abnormal return from idr_cond_timed_wait_rel!"); if (wait_return == IDR_COND_WAIT_TIMEOUT) { /* * timeout may not be an error - so no error msg * let caller test flags for timeout */ DPRINTI("timeout waiting for ready!"); unit_p->unit_flags |= IDR_RDY_TIMEOUT; return -EIO; } if (IDR_COND_WAIT_SIGNAL) { /* * signal is not exactly an error - but send to console log * return EINTR to caller can decide what to do */ WPRINTI("signal while waiting for ready!"); unit_p->unit_flags |= IDR_SIG_RECEIVED; return -EINTR; } } /* if sleeping */ } /* if not ready */ else { DPRINTI("at ready wait, board already ready"); } /* * either board was ready when case was entered, or it is ready now * after sleeping, so ... * * examine dr11 flag bits to figure out why ready was set * if attf is set and eor is not - clear attf */ if ((IDR_GETL(IDR_FLAGS) & ATTENTION_FLAG) && !(IDR_GETL(IDR_FLAGS) & END_OF_RANGE_FLAG)) { DPRINTI("at ready wait - attf w/out eorf"); IDR_PUTL(IDR_116_PULSES, RESET_ATTENTION_FLAG); } /* * always clear eorf */ IDR_PUTL(IDR_116_PULSES, RESET_EOR_FLAG); return 0; break; case MASK & IDRIO_GET_STATUS: /* return dr11 status register - in sbus format */ DPRINTI("at get status"); /* * get flags and status registers and fiddle bits * to look like sbus status register */ bits = 0; lt = IDR_GETL(IDR_FLAGS); if (lt & END_OF_RANGE_FLAG) bits |= IDR_EORF; if (lt & ATTENTION_FLAG) bits |= IDR_ATTF; if (lt & MULTI_CYCLE_ERROR_FLAG) bits |= IDR_MCER; lt = IDR_GETL(IDR_STATUS); if (lt & READY) bits |= IDR_REDY; if (lt & ATTENTION) bits |= IDR_ATTN; /* * dr11 status bits are in the same place in sbus and pci */ bits |= (lt & STATUS_MASK); if (copy_to_user((caddr_t) arg, &bits, count)) { EPRINTI("copy_to_user error!"); return -EINVAL; } return 0; break; case MASK & IDRIO_GET_RANGE: /* gets 24 bit range counter value */ /* in raw form: = word count minus 1 */ DPRINTI("at get range"); bits = ((IDR_GETL(IDR_RANGE_HIGH) & 0xFF) << 16) | ((IDR_GETL(IDR_RANGE_MID) & 0xFF) << 8) | (IDR_GETL(IDR_RANGE_LOW) & 0xFF); if (copy_to_user((caddr_t) arg, &bits, count)) { EPRINTI("copy_to_user error!"); return -EINVAL; } return 0; break; case MASK & IDRIO_GET_REGS: /* get most of the board's registers */ DPRINTI("at get regs"); return_array[0] = unit_p->dev_and_vendor_id; return_array[1] = unit_p->revision_id; return_array[2] = PLX_GETL(PLX_INT_CSTAT); return_array[3] = PLX_GETL(PLX_EEPROM_USER); return_array[4] = PLX_GETL(PLX_DMA_MODE_1); return_array[5] = PLX_GETL(PLX_DMA_PCI_ADD_1); return_array[6] = PLX_GETL(PLX_DMA_LOC_ADD_1); return_array[7] = PLX_GETL(PLX_DMA_COUNT_1); return_array[8] = PLX_GETL(PLX_DMA_DESC_PTR_1); return_array[9] = PLX_GETL(PLX_DMA_CMD_STAT_BOTH); return_array[11] = IDR_GETL(IDR_FLAGS) & 0xFF; return_array[12] = IDR_GETL(IDR_STATUS) & 0xFF; return_array[13] = IDR_GETL(IDR_MODE) & 0xFF; return_array[14] = IDR_GETL(IDR_RANGE_LOW) & 0xFF; return_array[15] = IDR_GETL(IDR_RANGE_MID) & 0xFF; return_array[16] = IDR_GETL(IDR_RANGE_HIGH) & 0xFF; return_array[17] = IDR_GETL(IDR_FIFO_STATUS) & 0xFF; /* * reading the data in lines requires clearing the input fifo, * forcing a dr11 input word into the input fifo, * and then reading in * * use the latched function read to guarantee time between the * write_input_fifo write and the data in read */ IDR_PUTL(IDR_116_PULSES, CLEAR_INPUT_FIFO); IDR_PUTL(IDR_116_PULSES, WRITE_INPUT_FIFO); return_array[10] = IDR_GETL(IDR_LATCHED_FUNCTIONS) & 0xFF; return_array[18] = IDR_GETL(IDR_DATA_IN) & 0xFFFF; if (copy_to_user((caddr_t) arg, return_array, count)) { EPRINTI("copy_to_user error!"); return -EINVAL; } return 0; break; case MASK & IDRIO_GET_FLAGS: /* return unit flags longword to caller */ DPRINTI("at get flags, flags = 0x%x", unit_p->unit_flags); bits = unit_p->unit_flags; if (copy_to_user((caddr_t) arg, &bits, count)) { EPRINTI("copy_to_user error!"); return -EINVAL; } return 0; break; case MASK & IDRIO_DATA_OUT: /* output 16 bit word to data out reg */ DPRINTI("at data out, data = 0x%x", bits); /* * first we clear the output fifo, then write to it, then force a read from it * into the output data latches * * we use a throwaway read to add some time before read output fifo cmd - * w/heavy pci traffic (DMA??) the writes and the "read" may stack * (somewhere) and the read may happed before the fifo is quite * ready */ IDR_PUTL(IDR_116_PULSES, CLEAR_OUTPUT_FIFO); IDR_PUTL(IDR_DATA_OUT, bits); read_dump_0 = IDR_GETL(IDR_LATCHED_FUNCTIONS); IDR_PUTL(IDR_116_PULSES, READ_OUTPUT_FIFO); return 0; break; case MASK & IDRIO_DATA_IN: /* read dr11 input data register */ DPRINTI("at data in"); /* * clear the input fifo, force a write into it from the data in lines * then read the fifo * * we use a throwaway read to add some time before the real read - * w/heavy pci traffic (DMA??) the writes and the read may stack * (somewhere) and the read may happed before the fifo is quite * ready */ IDR_PUTL(IDR_116_PULSES, CLEAR_INPUT_FIFO); IDR_PUTL(IDR_116_PULSES, WRITE_INPUT_FIFO); read_dump_0 = IDR_GETL(IDR_LATCHED_FUNCTIONS); bits = IDR_GETL(IDR_DATA_IN) & 0xFFFF; if (copy_to_user((caddr_t) arg, &bits, count)) { EPRINTI("copy_to_user error!"); return -EINVAL; } return 0; break; case MASK & IDRIO_SET_RANGE: /* set dr11 range counter to desired value */ /* count is not adjusted - calling argument */ /* will be plugged directly into range */ /* arg should be word count minus one!!! */ DPRINTI("at set range, range = 0x%x", bits); if (bits > IDR_DR11_MAXBLOCK) { WPRINTI("at SET_RANGE - range count too big!"); return -EINVAL; } IDR_PUTL(IDR_RANGE_HIGH, (bits >> 16)); IDR_PUTL(IDR_RANGE_MID, (bits >> 8)); IDR_PUTL(IDR_RANGE_LOW, bits); return 0; break; case MASK & IDRIO_AUTO: /* set automatic mode (default) */ DPRINTI("idr auto"); unit_p->unit_flags &= ~IDR_MANUAL; return 0; break; case MASK & IDRIO_MANUAL: /* set manual mode */ DPRINTI("at idr manual"); unit_p->unit_flags |= IDR_MANUAL; return 0; break; case MASK & IDRIO_START_READ: /* enables block read in manual mode */ DPRINTI("at start read"); /* * make sure that the "end" flags are clear and reset error flags * also clear the input fifo */ IDR_PUTL(IDR_116_PULSES, (RESET_ATTENTION_FLAG | RESET_EOR_FLAG | RESET_ERROR_FLAGS | CLEAR_INPUT_FIFO)); /* * make sure dma rqs are off, switch to input mode, and enable dma * the plx dma logic will be set up and enabled by strategy */ IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~IDR_DMA_ENABLE); IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) | DMA_INPUT_MODE); IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) | IDR_DMA_ENABLE); return 0; break; case MASK & IDRIO_START_WRITE: /* enables block write in man mode */ DPRINTI("at start write"); /* * make sure "end" flags are clean * and reset error flags and output fifo */ IDR_PUTL(IDR_116_PULSES, (RESET_ATTENTION_FLAG | RESET_EOR_FLAG | RESET_ERROR_FLAGS | CLEAR_OUTPUT_FIFO)); /* * make sure dma rqs are off, switch to output mode, and enable dma * the plx dma logic will be set up and enabled by strategy */ IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~IDR_DMA_ENABLE); IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~DMA_INPUT_MODE); IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) | IDR_DMA_ENABLE); return 0; break; case MASK & IDRIO_BLOCK_END: /* terminate overall block transfer */ DPRINTI("at block end"); /* * turn off dma enable bit and interrupt masks * interrupt masks should already be off */ IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~(END_OF_RANGE_INT_ENB | ATTENTION_INT_ENB | IDR_DMA_ENABLE)); /* * make sure ready is true */ IDR_PUTL(IDR_DEVICE_PULSES, SET_READY); /* * check for multicycle error or parity error and flag in unit structure * parity error will occur frequently when connected to device that don't * support parity (most!) so don't do a cmn_err print */ if (IDR_GETL(IDR_FLAGS) & PARITY_ERROR_FLAG) { DPRINTI("at BLOCK_END, parity error!"); unit_p->unit_flags |= IDR_PAR_ERR; } if (IDR_GETL(IDR_FLAGS) & MULTI_CYCLE_ERROR_FLAG) { WPRINTI("at BLOCK_END, multi-cycle error!"); unit_p->unit_flags |= IDR_MCYL_ERR; } /* * just to be sure, force off plx dma and interrupt enable bits */ PLX_PUTL(PLX_INT_CSTAT, 0); PLX_PUTL(PLX_DMA_CMD_STAT_BOTH, 0); return 0; break; case MASK & IDRIO_DEV_AND_VEND_ID: /* return vendor id in low 16 bits, */ /* device id in high 16 bits */ DPRINTI("at dev and vend id"); bits = unit_p->dev_and_vendor_id; if (copy_to_user((caddr_t) arg, &bits, count)) { EPRINTI("copy_to_user error!"); return -EINVAL; } return 0; break; case MASK & IDRIO_REVISION_ID: /* return board revision id */ DPRINTI("at revision id"); bits = unit_p->revision_id; if (copy_to_user((caddr_t) arg, &bits, count)) { EPRINTI("copy_to_user error!"); return -EINVAL; } return 0; break; case MASK & IDRIO_SET_NEW_MODE: /* direct write to pci dr11 mode register */ DPRINTI("at set new mode"); IDR_PUTL(IDR_MODE, bits); return 0; break; case MASK & IDRIO_GET_NEW_STATUS: /* direct read of pci dr11 status register */ DPRINTI("at get new status"); bits = IDR_GETL(IDR_STATUS) & 0xFF; if (copy_to_user((caddr_t) arg, &bits, count)) { EPRINTI("copy_to_user error!"); return -EINVAL; } return 0; break; case MASK & IDRIO_GET_NEW_FLAGS: /* direct read of pci dr11 flags register */ DPRINTI("at get new flags"); bits = IDR_GETL(IDR_FLAGS) & 0xFF; if (copy_to_user((caddr_t) arg, &bits, count)) { EPRINTI("copy_to_user error!"); return -EINVAL; } return 0; break; case MASK & IDRIO_MASTER_CLEAR: /* do a total reset of the board - don't try this at home! */ DPRINTI("at master clear"); /* * call soft reset to completely reset the board - including the dr11 mode register * this will also cause an init pulse to be sent to the attached device */ plx_soft_reset(unit_p); return 0; break; default: /* * an unrecognized ioctl command may not be an error - we may * get probed by pipe logic w/ a generic TCGETA ioctl. * return an error so we don't look like a terminal, but * don`t print an error. */ return -EINVAL; break; } } /* * our interrupt handler - registered with the system in init_module * each board's instance will register the same handler, but with a different unit structure pointer * when called, dev_id is a pointer at the soft state structure for this instance * * as of the 2.3.x kiobuf version, we use mutex and conditional variable for SMP compatibility * 2.6.x adds an interrupt claimed return value */ static irqreturn_t idr_intr(int irq, void *dev_id IDR__PT_REGS) { struct idr_unit_t *unit_p; volatile u_long temp; int instance; int wake_up_needed; unit_p = (struct idr_unit_t *) dev_id; instance = unit_p->instance; wake_up_needed = 0; idr_mutex_lock(&unit_p->mutex); /* * get plx interrupt control/status register and check for interrupt * look for master interrupt enable bit and either local int rq or dma int rq */ temp = PLX_GETL(PLX_INT_CSTAT); if ((temp & PCI_INTERRUPT_ENABLE) && ((temp & LOCAL_INTERRUPT) || (temp & DMA_1_INTERRUPT))) { DPRINTI("interrupt claimed, unit_p = 0x%p", unit_p); /* * clear sleeping flag so sleeping process will know we got a normal interrupt */ unit_p->sleeping = 0; wake_up_needed = 1; /* * turn off interrupts now - but leave dma enabled if it is * not already off * * in input mode, it is possible to terminate a block before the * dr11 or dma range count is exhausted, by pulsing attention * * the idr portion of the logic will hold off the attention * interrupt until the big fifo is empty, but there may still be * a few long words in the plx fifo * * we will leave dma on (if it is still on) in the plx logic, * and turn it off later in strategy * */ PLX_PUTL(PLX_INT_CSTAT, 0); IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~(END_OF_RANGE_INT_ENB | ATTENTION_INT_ENB)); /* * figure out why we were waiting for an interrupt * unfortunately, we can't treat all interrupts the same way */ switch (unit_p-> unit_flags & (IDR_DVMA_WAIT | IDR_EOR_WAIT | IDR_ATTN_WAIT | IDR_RDY_WAIT)) { case IDR_DVMA_WAIT: DPRINTI("at case dvma wait"); /* * we are waiting for dma t/c interrupt - attention interrupts will also * be enabled, so we will have to figure out what caused the interrupt * and whether the transfer is complete */ case IDR_EOR_WAIT: DPRINTI("at case eor wait"); /* * or we are waiting for a dr11 end of range * in auto output mode, eor is the desired interrupt * in input mode, or manual mode (either in or out), dma tc * is the desired interrupt */ /* * in the solaris driver we would turn off idr dma enb if * we are in automatic mode, but since the linux driver * may use several dma blocks to satisfy a user count, * we leave it on here, and turn it off (if automatic) * in read or write * * solaris code was: * * if(!(unit_p->unit_flags & IDR_MANUAL)) * IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) * & ~IDR_DMA_ENABLE); */ /* * if we are waiting for an output interrupt, force the plx dma logic * off, since either we are done with dma, or an attention has terminated * the dr11 transfer, and any further output data is destined for the * bit bucket * * if we are doing input, the attention or eor interrupt will be held * off until the big fifos are empty, but there may still be a few * long words in the plx fifos, so leave dma on for now - strategy * will clean things up */ if (!(unit_p->unit_flags & IDR_INPUT)) PLX_PUTL(PLX_DMA_CMD_STAT_BOTH, 0); if (! ((PLX_GETL (PLX_DMA_CMD_STAT_BOTH) & DMA_1_DONE) || (IDR_GETL(IDR_FLAGS) & END_OF_RANGE_FLAG))) { /* * if not eor or end of range, we must have been terminated by * an attention pulse - in this case, do not save the attn flag */ IDR_PUTL(IDR_116_PULSES, RESET_ATTENTION_FLAG); } if (unit_p->unit_flags & IDR_EOR_WAIT) { /* * if waiting for dr11 eor, turn it off - if not, it * may be useful later, so leave it on for now */ IDR_PUTL(IDR_116_PULSES, RESET_EOR_FLAG); } /* * turn off "waiting for" flags for dma t/c and eor */ unit_p->unit_flags &= ~(IDR_DVMA_WAIT | IDR_EOR_WAIT); break; case IDR_ATTN_WAIT: DPRINTI("at case attn wait"); /* * we are waiting for an attention interrupt * i would like to make sure attf is set, but there * is no way to flag an error * so we will * just reset the "waiting for" flag * * the attention flag gets reset in the ioctl code * we could do it here, but we will stick with the * way it was done in the Sbus driver */ unit_p->unit_flags &= ~IDR_ATTN_WAIT; break; case IDR_RDY_WAIT: DPRINTI("at case rdy wait"); /* * waiting for ready - either attention or eor * like attn wait, we could check for either flag set * and report an error if neither was set (serious * hardware error) but there is no good way to do so * * we will just turn off the "waiting for" flag * to try to keep some similarity with the Sbus * driver */ unit_p->unit_flags &= ~IDR_RDY_WAIT; break; default: /* * if we got here, we claimed the interrupt flag, but no * "waiting" flag was set * this is a major error -- all we can do is pump out a message, and we * probably better issue a wakeup anyway */ EPRINTI("got interrupt while not waiting!"); break; } } /* * if we claimed this int, wake up waiting code and tell kernel */ idr_mutex_unlock(&unit_p->mutex); if (wake_up_needed) { DPRINTI("claiming int and waking up sleeping process"); idr_cond_broadcast(&unit_p->cond); return IRQ_HANDLED; } else { DPRINTI("interrupt not claimed"); return IRQ_NONE; } } /* * call strategy with the virtual address of the user buffer * it must be 16 bit aligned and the byte count must be even * * if we are in user buffer DMA mode, strategy will map and pin the buffer, construct * an sg list of buffer pages, map the pages to the bus (using the dynamic mapping stuff), * build the PLX scatter-gather list in iopb memory, synch the iopb memory, and start the * dma block transfer * * if we are in copy user buffer mode ( machine has >4G of ram) strategy will copy data * to/from a kernel buffer, and do DMA from that buffer * * if the first_dma_flag argument is non-zero, strategy will set the function bits and issue * pulses immediately after starting dma if input, and before starting dma if output * to avoid long gaps between go and dma on in input mode - which might allow a very fast * device to overflow the input buffer before dma starts (if linux interrupts for something * else between go and dma enb, and causes a long delay) * * this must only be done for the FIRST call to strategy for a given read or write buffer, * and will only be done if in automatic mode * * it is up to the read/write code to set this flag for the first call to strategy ONLY * * if the last_dma_flag argument is non-zero, strategy will wait for eor in output mode * if zero, strategy will wait for dma done in output mode, since multiple calls to strategy * will be made before eor is reached * * THERE ARE SOME ERROR AND OTHER RETURNS IN THIS CODE - IF WE EVER NEED A MUTEX, GATHER * THEM WITH GOTOs, SO WE WON'T ESCAPE OUT THE SIDE OF THE MUTEX */ static int idr_strategy(struct idr_unit_t *unit_p, char *dma_buf_p, int dma_count, int first_dma_flag, int last_dma_flag) { int instance; int idr_input; u_long plx_direction; u_long plx_dma_done_int; u_long plx_local_dma_int; int wait_return; u_long temp; u_long temp_mode; u_long temp_latches; int i; instance = unit_p->instance; DPRINTI("entering strategy, unit_p = 0x%p, buf_p = 0x%p, count = 0x%x, first_dma_flag = 0x%x, last_dma_flag = 0x%x", unit_p, dma_buf_p, dma_count, first_dma_flag, last_dma_flag); /* * assorted checks */ if ((u_long) dma_buf_p & 0x1) { WPRINTI("buffer not 16 bit aligned!"); return -EINVAL; } if (dma_count == 0) { WPRINTI("dma count zero!"); return -EINVAL; } if (dma_count & 0x1) { WPRINTI("dma count not even!"); return -EINVAL; } if (dma_count > idr_max_buf_bytes) { WPRINTI("dma count too large!"); return -EINVAL; } /* * set local input flag, plx direction, and save in unit struct */ if (unit_p->unit_flags & IDR_INPUT) { idr_input = 1; plx_direction = DMA_INPUT; } else { idr_input = 0; plx_direction = 0; } /* * interrupts enabled and other housekeeping differ in auto and manual modes */ if (!(unit_p->unit_flags & IDR_MANUAL)) { DPRINTI("in auto mode"); if (idr_input) { DPRINTI("auto read mode, setting dvma_wait"); /* * if first_dma_flag is on, set read function bits to pre-selected pattern * and clear the input fifo (in manual mode, that is done in start read) */ if (first_dma_flag) { DPRINTI("setting read function bits to 0x%x", unit_p->read_fcn); IDR_PUTL(IDR_LATCHED_FUNCTIONS, (IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~FUNCTION_MASK) | unit_p-> read_fcn); IDR_PUTL(IDR_116_PULSES, CLEAR_INPUT_FIFO); } /* * in auto read mode, set direction to input * and enable attention interrupt, but not eor interrupt */ IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) | DMA_INPUT_MODE | ATTENTION_INT_ENB); /* * set to dma t/c wait - the one to use for input mode */ unit_p->unit_flags |= IDR_DVMA_WAIT; } else { DPRINTI("auto write mode"); /* * if first_dma_flag is on, set write function bits to pre-selected patern * and clear the output fifo (in manual mode, that is done in start write) */ if (first_dma_flag) { DPRINTI("setting write function bits to 0x%x", unit_p->write_fcn); IDR_PUTL(IDR_LATCHED_FUNCTIONS, (IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~FUNCTION_MASK) | unit_p-> write_fcn); IDR_PUTL(IDR_116_PULSES, CLEAR_OUTPUT_FIFO); } /* * if last_dma_flag is on, enb eor and attn ints, if not, * use dma done and attn ints */ if (last_dma_flag) { /* * automatic write mode - leave input mode bit off * enable eor or attention interrupt since last dma */ DPRINTI("auto write mode & last dma, using eor and attn ints"); IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) | END_OF_RANGE_INT_ENB | ATTENTION_INT_ENB); /* * since automatic output and last dma, wait for end-of-range */ unit_p->unit_flags |= IDR_EOR_WAIT; } else { /* * auto write mode - leave input mode bit off * enable attn ints only (here - dma will be enabled in later * code) since not last dma */ IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) | ATTENTION_INT_ENB); /* * set to dma t/c wait - the one to use for output mode if not * last dma */ unit_p->unit_flags |= IDR_DVMA_WAIT; } } /* end of if not input */ } /* end of if not manual mode */ else { DPRINTI("manual mode, setting dvma_wait"); /* * manual mode - always wait for dma terminal count * and always enable attention interrupt * * direction and idr dma enable bit will be set in start read or start write */ unit_p->unit_flags |= IDR_DVMA_WAIT; IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) | ATTENTION_INT_ENB); } /* * the error flags are not cleared here so they will persist for multiple * calls to strategy by read/write * * we assume that we will always be issuing a go here if in automatic mode * and the first_dma_flag is set (1st call from read or write) * in manual mode, issuing go is up to the calling program * * we will issue the dr11 pulses before starting dma if we are doing output, * and after starting dma if doing input * * the reasoning is as follows: if we do the go before dma is started for input, * a very fast device might fill our fifos before we could get dma started -- very * unlikely with 16K fifos, but there is a small chance that our code could be * pre-empted for a long time * * if we start dma first for output, the bus will get very busy, and it is not clear * that the p-i/o accesses necessary to issue the function and go bits will get through * (this was a serious problem on the sbus - probably not an issue with plx on pci) */ if ((first_dma_flag) && !(unit_p->unit_flags & IDR_MANUAL)) { /* * test for attention stuck on - it will prevent the block * from starting if it is on - allow some time for a software- * generated pulse from the other end to finish * * do it here since we need to check for both input and output * modes - in automatic mode */ i = 0; while ((IDR_GETL(IDR_STATUS) & ATTENTION) && (i < 100)) { udelay(1); i++; } if (IDR_GETL(IDR_STATUS) & ATTENTION) { WPRINTI("attempt to issue GO while ATTENTION true!"); /* * DMON may be on at this point - shut down everything!! */ IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~(IDR_DMA_ENABLE | END_OF_RANGE_INT_ENB | ATTENTION_INT_ENB)); return -EIO; } if (!idr_input) { /* * auto write issues pulses before dma starts * if first_dma_flag on!! */ DPRINTI("auto write & first_dma_flag on - issuing GO before starting dma"); IDR_PUTL(IDR_DEVICE_PULSES, unit_p->write_pulse | GO); } } /* * disable dma done interrupt if auto out mode, and last dma flag is set * otherwise, use dma done ints (for intermediate dma blocks in manual or auto, * or input mode) */ if ((unit_p->unit_flags & IDR_MANUAL) || idr_input || (!last_dma_flag)) { DPRINTI("manual read/write, auto read, or ! last dma, enabling dma done interrupt"); plx_dma_done_int = DMA_DONE_INTERRUPT_ENB; plx_local_dma_int = LOCAL_DMA_1_INT_ENABLE; } else { DPRINTI("auto write & last_dma_flag, disabling dma done interrupt"); plx_dma_done_int = 0; plx_local_dma_int = 0; } /* * map and pin - or copy - user buffer */ if(idr_map_or_copy_buf(unit_p, instance, dma_buf_p, dma_count, idr_input ? READ : WRITE)) { EPRINTI("idr_map_or_copy_failure!"); return -EIO; } if(idr_maplist_to_sg_list(unit_p, instance)) { EPRINTI("idr_maplist_to_sg_list failure!"); idr_unmap_on_error(unit_p, instance); return -EIO; } /* * map the sg list (which may combine contiguous entries * there is no error return, as I am told that the mapping resources are huge */ unit_p->nr_iopbs = pci_map_sg(unit_p->pci_dev_p, unit_p->sg_list_p, unit_p->maplist_nr_pages, idr_input ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); DPRINTI("scatter list mapped, nr_iopbs = 0x%x", unit_p->nr_iopbs); /* * synch iopb memory for cpu before accessing it - this is commented out * since we don't care if it is up to date, since we will overwrite * it and sync for device - might need to use it later if kernel gods * assign some necessary side-effects pci_dma_sync_single_for_cpu(unit_p->pci_dev_p, unit_p->dma_handle, unit_p->nr_iopbs * IOPB_SIZE, PCI_DMA_TODEVICE); */ /* * convert sg list to iopb list for plx dma engine */ if(idr_sg_list_to_iopb_list(unit_p, instance)) { EPRINTI("idr_sg_list_to_iopb_list failure!"); pci_unmap_sg(unit_p->pci_dev_p, unit_p->sg_list_p, unit_p->maplist_nr_pages, idr_input ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); idr_unmap_on_error(unit_p, instance); return -EIO; } /* * synch iopb memory for dma - NOP on a pc - necessary on other * architectures to ensure coherence betweene list and device * synch only as much iopb space as was touched this time */ pci_dma_sync_single_for_device(unit_p->pci_dev_p, unit_p->dma_handle, unit_p->nr_iopbs * IOPB_SIZE, PCI_DMA_TODEVICE); DPRINTI("iopb memory synched for DMA"); /* * program plx dma logic on board - in chaining mode * buffer is already aligned, and count masked * * make sure that any left over dma done interrupt * is cleared */ DPRINTI("programming PLX chip for DMA"); PLX_PUTL(PLX_DMA_CMD_STAT_BOTH, DMA_1_CLEAR_INTERRUPT); PLX_PUTL(PLX_DMA_MODE_1, DMA_BUS_16_BIT | DMA_WAIT_1 | DMA_BURST_ENABLE | DMA_CHAIN_ENABLE | plx_dma_done_int | DMA_LOCAL_ADD_HOLD | DMA_DEMAND_MODE); /* * output, list in pci mem, list pointer */ PLX_PUTL(PLX_DMA_DESC_PTR_1, plx_direction | DMA_CHAIN_IN_PCI_MEM | unit_p->dma_handle); /* * start DMA in two steps - PLX bug */ PLX_PUTL(PLX_DMA_CMD_STAT_BOTH, DMA_1_ENABLE); PLX_PUTL(PLX_DMA_CMD_STAT_BOTH, DMA_1_ENABLE | DMA_1_START); /* * the 9060 drives the local interrupt out true when a dma * interrupt happens * * we have to loop that output back to the local interrupt input * external to the chip to get a dma interrupt to the pci bus */ DPRINTI("disabling cpu ints and enabling board ints"); idr_mutex_lock(&unit_p->mutex); PLX_PUTL(PLX_INT_CSTAT, PCI_INTERRUPT_ENABLE | PCI_LOCAL_INT_ENABLE | LOCAL_INT_OUT_ENABLE | plx_local_dma_int); /* * if automatic and read mode and first_dma_flag on - issue go AFTER starting dma */ if ((!(unit_p->unit_flags & IDR_MANUAL)) && idr_input && (first_dma_flag)) { DPRINTI("automatic & input & first_dma_flag on - issuing GO after starting dma"); IDR_PUTL(IDR_DEVICE_PULSES, unit_p->read_pulse | GO); } /* * set sleeping flag - so we can detect abnormal sleep termination later * (int code will clear sleeping flag) * * board interrupts are already enabled, and processor interrupts disabled, * to avoid race wait will re-enable * * snooze until done or timeout or signal */ unit_p->sleeping = 1; DPRINTI("unit_flags = 0x%x, dma mode = 0x%x, int cstat = 0x%x", unit_p->unit_flags, PLX_GETL(PLX_DMA_MODE_1), PLX_GETL(PLX_INT_CSTAT)); DPRINTI("calling idr_cond_timed_wait_rel, jiffies = %ld, unit_p->dma_time = %d", jiffies, unit_p->dma_time); wait_return = idr_cond_timed_wait_rel(&unit_p->cond, &unit_p->mutex, unit_p->dma_time); /* * leave idr dma enb on for read/write or block end if manual * idr dma must stay on to preserve fifo data between dma blocks * * make sure plx interrupt enables are off and pause dma * * in input mode, plx dma will still be enabled at this point to allow any * data in the plx fifo that was left after a block terminated early by attention * to make it to memory * * if the application uses attention to do early block termination, it may be necessary * to add some delay here to make sure that the (small) plx fifo has drained * * there doesn't seem to be any way to determine whether there is data in the plx fifos * so for now, we will trust to luck! */ /* * spin a while (if necessary) to give DMA a chance to finish * then pause DMA - if still on */ for(i=0; i<100; i++) if(PLX_GETL(PLX_DMA_CMD_STAT_BOTH) & DMA_1_DONE) break; PLX_PUTL(PLX_DMA_CMD_STAT_BOTH, 0); IDR_PUTL(IDR_LATCHED_FUNCTIONS, IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~(END_OF_RANGE_INT_ENB | ATTENTION_INT_ENB)); PLX_PUTL(PLX_INT_CSTAT, 0); idr_mutex_unlock(&unit_p->mutex); /* * if dma is not done (after sig or timeout or short input block), force a * plx dma abort and issue a master clear to flush idr buffers and turn off * the dma enable bit in the idr logic * * abort may take some time to complete, so use delay and * register read (to force write buffer flush) to give it some time */ if (!(PLX_GETL(PLX_DMA_CMD_STAT_BOTH) & DMA_1_DONE)) { DPRINTI("dma not done after idr_cond_timed_wait_rel"); PLX_PUTL(PLX_DMA_CMD_STAT_BOTH, DMA_1_ABORT); /* * get latched functions and mode - so we can restore them after a mclr * * it is not clear whether the 9060 needs dma rq in order to * finish an abort * * if it does, it may transfer a word or two after the mclr, * so we will repeat the mclr later */ udelay(5); temp_latches = IDR_GETL(IDR_LATCHED_FUNCTIONS) & ~IDR_DMA_ENABLE; temp_mode = IDR_GETL(IDR_MODE); IDR_PUTL(IDR_116_PULSES, MASTER_CLEAR); /* * force write buffer to flush - so delay appears on the bus */ read_dump_0 = IDR_GETL(IDR_STATUS); udelay(5); IDR_PUTL(IDR_116_PULSES, MASTER_CLEAR); IDR_PUTL(IDR_LATCHED_FUNCTIONS, temp_latches); IDR_PUTL(IDR_MODE, temp_mode); /* * make sure dma actually says done */ if (!(PLX_GETL(PLX_DMA_CMD_STAT_BOTH) & DMA_1_DONE)) { EPRINTI("dma not done after abort!"); pci_unmap_sg(unit_p->pci_dev_p, unit_p->sg_list_p, unit_p->maplist_nr_pages, idr_input ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); idr_unmap_on_error(unit_p, instance); return -EIO; } } /* * now we can safely make sure that the done interrupt is clear, * (the above is probably not necessary after normal dma done) */ PLX_PUTL(PLX_DMA_CMD_STAT_BOTH, DMA_1_CLEAR_INTERRUPT); /* * unmap the sg list (NOP on pc, release iommu mappings on other machines) * unmap sg wants the original sg list length */ DPRINTI("unmapping sg list after dma"); pci_unmap_sg(unit_p->pci_dev_p, unit_p->sg_list_p, unit_p->maplist_nr_pages, idr_input ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); /* * unmap user buffer, or copy dma buffer to user buffer */ if(idr_unmap_or_copy_buf(unit_p, instance)) { EPRINTI("idr_unmap_or_copy_buf failure!"); return -EIO; } /* * find out why we woke up * * if sleeping is true, we got here via timeout or signal -- do a soft reset of * the plx and idr logic - saving and restoring the latched functions and mode * registers */ if (unit_p->sleeping) { /* * flag some kind of error - in unlikely case that both the following * tests fail!! */ temp = -EIO; unit_p->sleeping = 0; DPRINTI("abnormal return from idr_cond_timed_wait_rel()!"); if (wait_return == IDR_COND_WAIT_TIMEOUT) { /* * timeout is always an error so print message and return error * code to write and flag timeout in unit flags */ EPRINTI("timeout while waiting for interrupt!"); unit_p->unit_flags |= IDR_DVMA_TIMEOUT; temp = -EIO; } if (wait_return == IDR_COND_WAIT_SIGNAL) { /* * flag signal received and print error message */ WPRINTI("signal received while waiting for interrupt"); unit_p->unit_flags |= IDR_SIG_RECEIVED; temp = -EINTR; } /* * save latched functions and mode and do a soft reset, * then restore saved registers */ temp_latches = IDR_GETL(IDR_LATCHED_FUNCTIONS); temp_mode = IDR_GETL(IDR_MODE); plx_soft_reset(unit_p); IDR_PUTL(IDR_LATCHED_FUNCTIONS, temp_latches); IDR_PUTL(IDR_MODE, temp_mode); return temp; } /* if sleeping */ /* * if we get here - just return good status * there is no way to figure a residual count with the hardware at hand * so we don't even try */ return 0; } /* * do a soft reset of the plx chip - also clears the idr logic * * the pci_dev handle, and int_level elements of the unit structure * MUST be set before calling this routine! * * ALSO - THIS ROUTINE MUST NOT BE CALLED FROM THE INTERRUPT SIDE OF THINGS!! * (it calls schedule to do a delay) */ static void plx_soft_reset(struct idr_unit_t *unit_p) { u_long wait_j; /* * soft reset clears the local config registers, which turns off add space 0 accesses * * so we will force an eeprom reload, and wait a while (0.2s) to avoid too many retry * cycles while the eeprom is reloading - we will use delay, not drv_usec_wait, so we * don't tie up the cpu * * do a read dump before the reload to force any write buffer to flush, so our wait * timing is reflected on the bus (hopefully). if we try to access the plx chip * during reload, retry cycles happen, and a short bus timer could cause a panic * * an earlier rev cleared the int line byte in the configuration registers during * soft reset, but that is not supposed to be true anymore * * IT SEEMS THAT IT IS STILL TRUE - SO RESTORE THE INT LINE AFTER SOFT_RESET * * we probably don't have to clear the config reload bit after writing it, * but we will to be sure */ /* * there is really no good way to return an error from here - so just put it on the console * and return without touching anything */ PLX_PUTL(PLX_EEPROM_USER, (PLX_GETL(PLX_EEPROM_USER) | PLX_SOFT_RESET)); PLX_PUTL(PLX_EEPROM_USER, (PLX_GETL(PLX_EEPROM_USER) & ~PLX_SOFT_RESET)); read_dump_0 = PLX_GETL(PLX_INT_CSTAT); PLX_PUTL(PLX_EEPROM_USER, (PLX_GETL(PLX_EEPROM_USER) | CONFIGURATION_RELOAD)); wait_j = jiffies + HZ / 5; while (time_before(jiffies, wait_j)) schedule(); PLX_PUTL(PLX_EEPROM_USER, (PLX_GETL(PLX_EEPROM_USER) & ~CONFIGURATION_RELOAD)); pci_write_config_byte(unit_p->pci_dev_p, PCI_INTERRUPT_LINE, unit_p->int_level); /* * print instance by hand since instance not declared here * and if we declare it compiler will complain when debug not on */ DPRINT("instance %d: soft reset and configuration reload complete", unit_p->instance); /* * soft reset leaves pci master int enable on, so turn it off for safety * don't bother with oring bits - just hammer them all off! */ PLX_PUTL(PLX_INT_CSTAT, 0); /* * restore endian mode default */ PLX_PUTL(PLX_ENDIAN_REG, unit_p->endian_def); /* * disable address space 0 pre-fetch */ PLX_PUTL(PLX_ADD_0_ROM_DESC, PLX_GETL(PLX_ADD_0_ROM_DESC) | ADD_0_PREFETCH_DISABLE); } /* * establish driver and board defaults - some of these will be used to establish initial * configuration on a per-board basis * * there are a ton of these things - to try to stay consistent with solaris driver and conf file * we could probably eliminate one level of defaults (in unit structure) but this way will avoid * some code modification, and let the insmod parameters match the solaris .conf parameters * * the config variables that end in _def may be later modified by ioctl calls on a per board * basis * * examine the variables that may be set during insmod - if not -1, and within permitted range, * use the insmod supplied value - if -1, use the default * * some of the range checks look redundant ( .. >= 0 ..), but I prefer to keep the insmod set * detection separate from the range check, and not assume anything */ static void idr_set_global_defaults(void) { DPRINT("entering idr_set_global_defaults"); idr_speed_def = SPEED_DEF; if (speed_def >= 0) { if ((speed_def >= 0) && (speed_def <= 3)) idr_speed_def = speed_def; else WPRINT("speed_def out of range! using default"); } DPRINT("idr_speed_def = 0x%x", idr_speed_def); idr_dma_time_def = DMA_TIME_DEF; if (dma_time_def >= 0) { if ((dma_time_def >= DMA_TIME_MIN) && (dma_time_def <= DMA_TIME_MAX)) idr_dma_time_def = dma_time_def; else WPRINT("dma_time_def out of range! using default"); } DPRINT("idr_dma_time_def = 0x%x", idr_dma_time_def); idr_attn_time_def = ATTN_TIME_DEF; if (attn_time_def >= 0) { if ((attn_time_def >= ATTN_TIME_MIN) && (attn_time_def <= ATTN_TIME_MAX)) idr_attn_time_def = attn_time_def; else WPRINT("attn_time_def out of range! using default"); } DPRINT("idr_attn_time_def = 0x%x", idr_attn_time_def); idr_rdy_time_def = RDY_TIME_DEF; if (rdy_time_def >= 0) { if ((rdy_time_def >= RDY_TIME_MIN) && (rdy_time_def <= RDY_TIME_MAX)) idr_rdy_time_def = rdy_time_def; else WPRINT("rdy_time_def out of range! using default"); } DPRINT("idr_rdy_time_def = 0x%x", idr_rdy_time_def); /* * the following are a pile of defaults that have legit values of 0 or 1 * we could test by masking with 0xfffffffe, but ==0 || ==1 reads better, and * we don't do this very often */ idr_byte_swap_def = BYTE_SWAP_DEF; if (byte_swap_def >= 0) { if ((byte_swap_def == 0) || (byte_swap_def == 1)) idr_byte_swap_def = byte_swap_def; else WPRINT("byte_swap_def out of range! using default"); } DPRINT("idr_byte_swap_def = 0x%x", idr_byte_swap_def); idr_cycle_pol_def = CYCLE_POL_DEF; if (cycle_pol_def >= 0) { if ((cycle_pol_def == 0) || (cycle_pol_def == 1)) idr_cycle_pol_def = cycle_pol_def; else WPRINT("cycle_pol_def out of range! using default"); } DPRINT("idr_cycle_pol_def = 0x%x", idr_cycle_pol_def); idr_busy_pol_def = BUSY_POL_DEF; if (busy_pol_def >= 0) { if ((busy_pol_def == 0) || (busy_pol_def == 1)) idr_busy_pol_def = busy_pol_def; else WPRINT("busy_pol_def out of range! using default"); } DPRINT("idr_busy_pol_def = 0x%x", idr_busy_pol_def); idr_write_cycle_def = WRITE_CYCLE_DEF; if (write_cycle_def >= 0) { if ((write_cycle_def == 0) || (write_cycle_def == 1)) idr_write_cycle_def = write_cycle_def; else WPRINT("write_cycle_def out of range! using default"); } DPRINT("idr_write_cycle_def = 0x%x", idr_write_cycle_def); idr_read_cycle_def = READ_CYCLE_DEF; if (read_cycle_def >= 0) { if ((read_cycle_def == 0) || (read_cycle_def == 1)) idr_read_cycle_def = read_cycle_def; else WPRINT("read_cycle_def out of range! using default"); } DPRINT("idr_read_cycle_def = 0x%x", idr_read_cycle_def); idr_read_acf2_def = READ_ACF2_DEF; if (read_acf2_def >= 0) { if ((read_acf2_def == 0) || (read_acf2_def == 1)) idr_read_acf2_def = read_acf2_def; else WPRINT("read_acf2_def out of range! using default"); } DPRINT("idr_read_acf2_def = 0x%x", idr_read_acf2_def); idr_open_f3_def = OPEN_F3_DEF; if (open_f3_def >= 0) { if ((open_f3_def == 0) || (open_f3_def == 1)) idr_open_f3_def = open_f3_def; else WPRINT("open_f3_def out of range! using default"); } DPRINT("idr_open_f3_def = 0x%x", idr_open_f3_def); idr_open_f2_def = OPEN_F2_DEF; if (open_f2_def >= 0) { if ((open_f2_def == 0) || (open_f2_def == 1)) idr_open_f2_def = open_f2_def; else WPRINT("open_f2_def out of range! using default"); } DPRINT("idr_open_f2_def = 0x%x", idr_open_f2_def); idr_open_f1_def = OPEN_F1_DEF; if (open_f1_def >= 0) { if ((open_f1_def == 0) || (open_f1_def == 1)) idr_open_f1_def = open_f1_def; else WPRINT("open_f1_def out of range! using default"); } DPRINT("idr_open_f1_def = 0x%x", idr_open_f1_def); idr_write_f3_def = WRITE_F3_DEF; if (write_f3_def >= 0) { if ((write_f3_def == 0) || (write_f3_def == 1)) idr_write_f3_def = write_f3_def; else WPRINT("write_f3_def out of range! using default"); } DPRINT("idr_write_f3_def = 0x%x", idr_write_f3_def); idr_write_f2_def = WRITE_F2_DEF; if (write_f2_def >= 0) { if ((write_f2_def == 0) || (write_f2_def == 1)) idr_write_f2_def = write_f2_def; else WPRINT("write_f2_def out of range! using default"); } DPRINT("idr_write_f2_def = 0x%x", idr_write_f2_def); idr_write_f1_def = WRITE_F1_DEF; if (write_f1_def >= 0) { if ((write_f1_def == 0) || (write_f1_def == 1)) idr_write_f1_def = write_f1_def; else WPRINT("write_f1_def out of range! using default"); } DPRINT("idr_write_f1_def = 0x%x", idr_write_f1_def); idr_read_f3_def = READ_F3_DEF; if (read_f3_def >= 0) { if ((read_f3_def == 0) || (read_f3_def == 1)) idr_read_f3_def = read_f3_def; else WPRINT("read_f3_def out of range! using default"); } DPRINT("idr_read_f3_def = 0x%x", idr_read_f3_def); idr_read_f2_def = READ_F2_DEF; if (read_f2_def >= 0) { if ((read_f2_def == 0) || (read_f2_def == 1)) idr_read_f2_def = read_f2_def; else WPRINT("read_f2_def out of range! using default"); } DPRINT("idr_read_f2_def = 0x%x", idr_read_f2_def); idr_read_f1_def = READ_F1_DEF; if (read_f1_def >= 0) { if ((read_f1_def == 0) || (read_f1_def == 1)) idr_read_f1_def = read_f1_def; else WPRINT("read_f1_def out of range! using default"); } DPRINT("idr_read_f1_def = 0x%x", idr_read_f1_def); /* * set max board number - this will determine how much we kmalloc for the unit structures * we will do a sanity check, and require this number to be a single digit */ idr_max_boards = MAX_BOARDS_DEF; if (max_boards >= 0) { if ((max_boards >= 0) && (max_boards <= 9)) idr_max_boards = max_boards; else WPRINT("max_boards out of range! using default"); } DPRINT("idr_max_boards = %d", idr_max_boards); /* * set max_phys_order and several values * that derive from it * * max buffer pages = 2**max phys order * max bytes per dma xfer = max buffer pages * PAGE_SIZE * max size of scatter/gather list = max buffer pages + 1 * * these calculations must track w/copy buf and user buf map size as well * * size of iopb memory allocated = max sg size * IOPB_SIZE * * we will check for a request less than zero, but not limit the upper end - USER BEWARE! */ idr_max_phys_order = MAX_PHYS_ORDER_DEF; if (max_phys_order >= 0) idr_max_phys_order = max_phys_order; idr_max_buf_pages = (1 << idr_max_phys_order); idr_max_buf_bytes = idr_max_buf_pages * PAGE_SIZE; idr_max_sg_length = idr_max_buf_pages + 1; idr_iopb_mem_size = idr_max_sg_length * IOPB_SIZE; DPRINT("max_phys_order = 0x%x, max_bytes = 0x%x,\n" " max_sg_length = 0x%x, iopb_mem_size = 0x%x", idr_max_phys_order, idr_max_buf_bytes, idr_max_sg_length, idr_iopb_mem_size); } /* * do the per-board initialization * return 0 if successful, error if not */ static int idr_init_one_board(struct idr_unit_t *unit_p, int instance) { u32 temp; u_char c_temp; /* * initialize flags, mutex, and conditional variable */ idr_mutex_init(&unit_p->mutex); idr_cond_init(&unit_p->cond); unit_p->sleeping = 0; unit_p->unit_attached = 0; unit_p->unit_open = 0; spin_lock_init(&unit_p->open_lock); unit_p->unit_flags = 0; DPRINTI("entering routine"); /* * allocate dma resources - iopb list memory, sg list memory, user buffer map list, * and copy buffer if direct user dma not to be used - and set dma mask */ if(idr_dma_alloc(unit_p, instance)) { EPRINTI("idr_dma_alloc error!"); return -EIO; } /* * grind through the config registers to get register base addresses and other values * use the new pci interface, but keep the rest of the old code * * the base address registers contain the bus addresses of our two register sets * - plx and idr unfortunately, the plx register set is smaller than a page, so bios * may align it on an address that isn't a page boundary * * ioremap doesn't tolerate that, so we have to figure out the appropriate (maybe lower) * page boundary and the appropriate size to ask for we will save the mapped base and * the actual virtual pointer to the register set * * I hope linux allows multiple processes to map the same bus page, or we may clobber * someone else - or that the config process doesn't share pages */ /* * make sure that io and mem accesses are enabled * make sure that the pci master enable bit is set * enable device */ if(pci_enable_device(unit_p->pci_dev_p)) { EPRINTI("pci_enable_device error!"); idr_dma_free(unit_p, instance); return -EIO; } pci_set_master(unit_p->pci_dev_p); DPRINTI("enable bit set"); /* * map the board's registers for slave access */ if(idr_map_regs(unit_p, instance)) { EPRINTI("idr_map_regs error!"); idr_dma_free(unit_p, instance); return -EIO; } /* * get (possibly) mapped int level from pci_dev for use in kernel calls, and * the hardware level from the board for use when restoring the level after * an eeprom reload */ unit_p->pci_dev_int_level = unit_p->pci_dev_p->irq; if (pci_read_config_byte (unit_p->pci_dev_p, PCI_INTERRUPT_LINE, (u_char *) &c_temp)) { EPRINTI("error reading pci interrupt line!"); idr_unmap_regs(unit_p, instance); idr_dma_free(unit_p, instance); return -EIO; } unit_p->int_level = c_temp; DPRINTI("board int line = 0x%x, pci_dev int line = 0x%x", unit_p->int_level, unit_p->pci_dev_int_level); /* * save IDs - so app can tell what kind of board we attached */ if (pci_read_config_dword (unit_p->pci_dev_p, PCI_VENDOR_ID, (int *) &temp)) { EPRINTI("error reading pci vendor id!"); idr_unmap_regs(unit_p, instance); idr_dma_free(unit_p, instance); return -EIO; } unit_p->dev_and_vendor_id = temp; DPRINTI("device and vendor id = 0x%08x", temp); if (pci_read_config_byte (unit_p->pci_dev_p, PCI_REVISION_ID, (char *) &temp)) { EPRINTI("error reading revision id!"); idr_unmap_regs(unit_p, instance); idr_dma_free(unit_p, instance); return -EIO; } unit_p->revision_id = temp & 0xff; DPRINTI("revision id = 0x%x", temp & 0xff); /* * set defaults on a per-board basis */ idr_set_board_defaults(unit_p, instance); /* * do a soft reset of the plx chip - which also clears the idr logic * this will also cause an init to be sent to the device */ plx_soft_reset(unit_p); DPRINTI("plx_soft_reset() complete"); /* * get a plx and an idr register and dprint for a sanity check */ DPRINTI("sanity check: plx eeprom reg = 0x%x (s.b. xxxx767e)", PLX_GETL(PLX_EEPROM_USER)); DPRINTI("sanity check: fifo stat reg = 0x%x (s.b. 0x22)", IDR_GETL(IDR_FIFO_STATUS) & 0xff); unit_p->unit_flags = 0; /* * register the interrupt line for this board & link to our interrupt handler * pass our unit pointer to the interrupt code * * we will use our node name as a label for the interrupt - that way /proc/interrupts * will have a unique name per interrupt (per board) rather than all of them being * named idr (we could use this when mknod is invoked) * * we have to keep the name in the unit structure, since request_irq just saves the pointer, * and doesn't copy the string - so by the time /proc/interrupts gets read, the stack has * changed, and the name would be garbage if not kept in "permanent" memory */ (void) sprintf((char *) unit_p->minor_node_name, "idr%d", instance); if (request_irq (unit_p->pci_dev_int_level, idr_intr, IRQF_SHARED, (const char *) unit_p->minor_node_name, (void *) unit_p)) { EPRINTI("error requesting interrupt!"); idr_unmap_regs(unit_p, instance); idr_dma_free(unit_p, instance); return -EIO; } return 0; } /* * sort out and save the defaults on a per-board basis * some of this is probably redundant, but we are trying * to stay with the solaris code as much as possible * * the ranges of any insmod-supplied parameters have already been checked */ static void idr_set_board_defaults(struct idr_unit_t *unit_p, int instance) { DPRINTI("entering routine"); /* * get and save timer default values */ unit_p->dma_time_def = idr_dma_time_def; DPRINTI("dma_time_def = %d", unit_p->dma_time_def); unit_p->attn_time_def = idr_attn_time_def; DPRINTI("attn_time_def = %d", unit_p->attn_time_def); unit_p->rdy_time_def = idr_rdy_time_def; DPRINTI("rdy_time_def = %d", unit_p->rdy_time_def); /* * get the default byte swap property * * in a sparc system, we must tell the plx chip to swap dma bytes, to reverse * the byte swapping that the host always does for 16 bit values * if the byte swap property says to swap bytes, we turn byte swapping OFF in the plx part * * in an x86 system, the default is to NOT swap in hardware, so if the byte * swap proprety says to swap, we swap * */ if (idr_byte_swap_def != 0) { unit_p->endian_def = DMA_1_BIG_ENDIAN; DPRINTI("setting DMA byte order to BIG ENDIAN"); } else { unit_p->endian_def = 0; DPRINTI("setting DMA byte order to LITTLE ENDIAN"); } /* * start assembling the mode register default */ unit_p->mode_reg_def = 0; switch (idr_speed_def) { case 0: unit_p->mode_reg_def = SPEED_0; break; case 1: unit_p->mode_reg_def = SPEED_1; break; case 2: unit_p->mode_reg_def = SPEED_2; break; case 3: unit_p->mode_reg_def = SPEED_3; break; } if (idr_cycle_pol_def == 1) unit_p->mode_reg_def |= CYCLE_POLARITY; if (idr_busy_pol_def == 1) unit_p->mode_reg_def |= BUSY_POLARITY; DPRINTI("mode_reg_def = 0x%x", unit_p->mode_reg_def); /* * assemble read pulse default - ALWAYS INCLUDE GO! */ unit_p->read_pulse_def = GO; if (idr_read_cycle_def == 1) unit_p->read_pulse_def |= SOFT_CYCLE; if (idr_read_acf2_def == 1) unit_p->read_pulse_def |= ACLO_FCN_2; DPRINTI("read_pulse_def = 0x%x", unit_p->read_pulse_def); /* * assemble write pulse default - ALWAYS INCLUDE GO! */ unit_p->write_pulse_def = GO; if (idr_write_cycle_def == 1) unit_p->write_pulse_def |= SOFT_CYCLE; DPRINTI("write_pulse_def = 0x%x", unit_p->write_pulse_def); /* * start compiling the open, read, and write function bit defaults * * there is a separate property for each function bit for each of the three * conditions -- it would be simlpler to combine all 3 bits into one mask, * but it wouldn't read as well, and wouldn't allow using the idr_reg.h * bit definitions */ /* * start with read function bits */ unit_p->read_fcn_def = 0; if (idr_read_f3_def == 1) unit_p->read_fcn_def |= FUNCTION_3; if (idr_read_f2_def == 1) unit_p->read_fcn_def |= FUNCTION_2; if (idr_read_f1_def == 1) unit_p->read_fcn_def |= FUNCTION_1; DPRINTI("read_fcn_def = 0x%x", unit_p->read_fcn_def); /* * now write function bits */ unit_p->write_fcn_def = 0; if (idr_write_f3_def == 1) unit_p->write_fcn_def |= FUNCTION_3; if (idr_write_f2_def == 1) unit_p->write_fcn_def |= FUNCTION_2; if (idr_write_f1_def == 1) unit_p->write_fcn_def |= FUNCTION_1; DPRINTI("write_fcn_def = 0x%x", unit_p->write_fcn_def); /* * now the open function bits, which will be plugged into the latched function * register at open time */ unit_p->latch_reg_def = 0; if (idr_open_f3_def == 1) unit_p->latch_reg_def |= FUNCTION_3; if (idr_open_f2_def == 1) unit_p->latch_reg_def |= FUNCTION_2; if (idr_open_f1_def == 1) unit_p->latch_reg_def |= FUNCTION_1; DPRINTI("latch_reg_def = 0x%x", unit_p->latch_reg_def); } /* * allocate dma resources - iopb list memory, sg list memory, user buffer map list, * and copy buffer if direct user dma not to be used - and set dma mask */ static int idr_dma_alloc(struct idr_unit_t *unit_p, int instance) { int i; DPRINTI("entering routine"); /* * get contiguous pages of kernel memory to contain to iopbs (dma chaining list) * GFP_KERNEL should get us contiguous memory, don't set dma flag so it won't be * forced into low memory */ unit_p->iopb_base_p = kmalloc(idr_iopb_mem_size, GFP_KERNEL); if (!unit_p->iopb_base_p) { EPRINTI("kmalloc failure (iopb memory)!"); return -1; } DPRINTI("iopb memory allocated, virtual address = 0x%p", unit_p->iopb_base_p); /* * check for alignment - we could have asked for more and forced it, * but I don't think the mem caches have any * chunks w/smaller alignments than we need */ if ((unsigned long)(unit_p->iopb_base_p) & (IOPB_SIZE - 1)) { EPRINTI("iopb memory not IOPB_SIZE aligned!"); kfree(unit_p->iopb_base_p); return -1; } /* * inform the kernel what our dma engine can address * (32 bits at this time/with this hardware) */ if (pci_set_dma_mask(unit_p->pci_dev_p, IDR_DMA_MASK)) { EPRINTI("DMA addressing not compatible!"); kfree(unit_p->iopb_base_p); return -1; } /* * get the bus address of iopb memory using the dynamic DMA mapping stuff, * (doesn't amount to much on a PC, but will help w/compatibility on SPARC, * and other arch's w/iommu hardware - like x86_64 * * do a sanity check on our DMA_MASK and the map code - make sure value * returned fits in DMA_MASK (32 bits for this hardware) */ unit_p->dma_handle = pci_map_single(unit_p->pci_dev_p, unit_p->iopb_base_p, idr_iopb_mem_size, PCI_DMA_TODEVICE); if (unit_p->dma_handle > IDR_DMA_MASK) { EPRINTI("dma_handle out of range!"); pci_unmap_single(unit_p->pci_dev_p, unit_p->dma_handle, idr_iopb_mem_size, PCI_DMA_TODEVICE); kfree(unit_p->iopb_base_p); return -1; } DPRINTI("iopb memory mapped, dma_handle = 0x%lx", (unsigned long)unit_p->dma_handle); /* * get space for the scatterlist ... this probably isn't necessary on a pc, since * we should be able to convert the user buff page mappings direcly into bus adds, * and build the iopb list, but to try for compatibility with other architectures, * we will go through a scatterlist on the way to building an iopb list * * the newer architectures may take advantage of IOMMU mapping, others may * implement bounce buffers via the scatterlist * * as of 2.6.24, it is possible to chain scatterlist pages - we will just * ask for more than a page if that's what the user really wants and not * use the chaining feature. if the user's unreasonable demand can't be * met, just let kmalloc barf * * we now have to zero the allocated memory, since the kernel gods have added new * .page and .offset to the scatterlist struct, and if .page AND .address are either * both zero or both non-zero, they BUG()! (maybe not in 2.6...) */ unit_p->sg_list_p = kmalloc(idr_max_sg_length * sizeof(struct scatterlist), GFP_KERNEL); if (unit_p->sg_list_p == NULL) { EPRINTI("can't allocate scatter list (kmalloc error)!"); pci_unmap_single(unit_p->pci_dev_p, unit_p->dma_handle, idr_iopb_mem_size, PCI_DMA_TODEVICE); kfree(unit_p->iopb_base_p); return -1; } memset(unit_p->sg_list_p, 0, idr_max_sg_length * sizeof(struct scatterlist)); DPRINTI("scatter list allocated, sg_list_p = 0x%p", unit_p->sg_list_p); /* * allocate an array of page pointers to hold ptrs to mapped * user pages * same size as max sg list since user bfr alignment may require * an extra page */ if((unit_p->maplist_p = kmalloc(idr_max_sg_length * sizeof(*unit_p->maplist_p), GFP_KERNEL)) == NULL) { EPRINTI("can't allocate maplist!"); kfree(unit_p->sg_list_p); pci_unmap_single(unit_p->pci_dev_p, unit_p->dma_handle, idr_iopb_mem_size, PCI_DMA_TODEVICE); kfree(unit_p->iopb_base_p); return -1; } DPRINTI("maplist allocated, address = 0x%p", unit_p->maplist_p); /* * if a copy buffer is required, allocate it here and stuff the maplist w/its * pages * * we only allocate just enough pages to satisfy the max buffer size, since we will always * copy to the buffer starting at offset = 0, so we don't need an extra page to handle * alignment (like the maplist and sg list do) */ if (IDR_COPY_BUF) { DPRINTI("allocating copy buffer"); unit_p->dma_copy_buf_p = (char *)__get_free_pages(GFP_KERNEL, idr_max_phys_order); if(unit_p->dma_copy_buf_p == NULL) { EPRINTI("can't allocate copy buffer!"); kfree(unit_p->maplist_p); kfree(unit_p->sg_list_p); pci_unmap_single(unit_p->pci_dev_p, unit_p->dma_handle, idr_iopb_mem_size, PCI_DMA_TODEVICE); kfree(unit_p->iopb_base_p); return -1; } DPRINTI("copy buffer allocated, address = 0x%p", unit_p->dma_copy_buf_p); /* * fill maplist array with pointers to buffer page structures * since we are in copy mode, these pointers will never change */ for (i=0; imaplist_p[i] = virt_to_page(unit_p->dma_copy_buf_p + ( i * PAGE_SIZE)); DPRINTI("maplist loaded w/copy buff pages"); } else { DPRINTI("user DMA mode, no copy buffer allocated"); unit_p->dma_copy_buf_p = NULL; } return 0; } /* * free the above */ static void idr_dma_free(struct idr_unit_t *unit_p, int instance) { DPRINTI("entering routine"); if(unit_p->dma_copy_buf_p) free_pages((unsigned long)unit_p->dma_copy_buf_p, idr_max_phys_order); kfree(unit_p->maplist_p); kfree(unit_p->sg_list_p); pci_unmap_single(unit_p->pci_dev_p, unit_p->dma_handle, idr_iopb_mem_size, PCI_DMA_TODEVICE); kfree(unit_p->iopb_base_p); } /* * map the board registers for slave access */ static int idr_map_regs(struct idr_unit_t *unit_p, int instance) { u_long bus_address; u_long bus_base; u_long bus_offset; DPRINTI("entering routine"); bus_address = unit_p->pci_dev_p->resource[0].start; DPRINTI("pci_base_address_0 (plx regs) = 0x%lx", bus_address); bus_address &= PCI_BASE_ADDRESS_MEM_MASK; bus_base = bus_address & ~(PAGE_SIZE - 1); bus_offset = bus_address & (PAGE_SIZE - 1); DPRINTI("plx bus add = 0x%lx, base = 0x%lx, offset = 0x%lx", bus_address, bus_base, bus_offset); unit_p->plx_page_base_p = ioremap(bus_base, PLX_REG_SIZE + bus_offset); unit_p->plx_base_p = unit_p->plx_page_base_p + bus_offset; if (unit_p->plx_page_base_p == NULL) { EPRINTI("can't ioremap plx registers!"); return -1; } DPRINTI("plx mapped base = 0x%p, virt addr = 0x%p", unit_p->plx_page_base_p, unit_p->plx_base_p); bus_address = unit_p->pci_dev_p->resource[2].start; DPRINTI("pci_base_address_2 (idr regs) = 0x%lx", bus_address); bus_address &= PCI_BASE_ADDRESS_MEM_MASK; bus_base = bus_address & ~(PAGE_SIZE - 1); bus_offset = bus_address & (PAGE_SIZE - 1); DPRINTI("idr bus add = 0x%lx, base = 0x%lx, offset = 0x%lx", bus_address, bus_base, bus_offset); unit_p->idr_page_base_p = ioremap(bus_base, IDR_REG_SIZE + bus_offset); unit_p->idr_base_p = unit_p->idr_page_base_p + bus_offset; if (unit_p->idr_page_base_p == NULL) { EPRINTI("can't ioremap idr registers!"); iounmap(unit_p->plx_page_base_p); return -1; } DPRINTI("idr mapped base = 0x%p, virt addr = 0x%p", unit_p->idr_page_base_p, unit_p->idr_base_p); return 0; } /* * unmap the board's registers */ static void idr_unmap_regs(struct idr_unit_t *unit_p, int instance) { DPRINTI("entering routine"); iounmap(unit_p->idr_page_base_p); iounmap(unit_p->plx_page_base_p); } /* * check maplist values for max/min permissible */ static int idr_maplist_check(struct idr_unit_t *unit_p, int instance) { DPRINTI("enterint routine"); if((unit_p->maplist_user_buf_p + unit_p->maplist_length) < unit_p->maplist_user_buf_p) { EPRINTI("buffer add + length overflow!"); return -EINVAL; } if(unit_p->maplist_nr_pages == 0) { EPRINTI("maplist_nr_pages = 0!"); return -EINVAL; } if(unit_p->maplist_nr_pages > idr_max_sg_length) { EPRINTI("maplist_nr_pages too large!"); return -EINVAL; } if(unit_p->maplist_length == 0) { EPRINTI("maplist_length = 0!"); return -EINVAL; } if(unit_p->maplist_length > idr_max_buf_bytes) { EPRINTI("maplist_length too large!"); return -EINVAL; } return 0; } /* * map and pin user buffer or copy user buffer to kernel buffer * maplist_rw_mode must be set before calling this * (might be cleaner to make that a parameter...) * * set the ->maplist_xx items to appropriate values for * either case * * CHECK FOR SANE VALUES in either case */ static int idr_map_or_copy_buf(struct idr_unit_t *unit_p, int instance, char *user_buf_p, int buf_size, int rw_mode) { DPRINTI("user_buf_p = 0x%p, size = 0x%x, rw_mode = 0x%x", user_buf_p, buf_size, rw_mode); unit_p->maplist_rw_mode = rw_mode; unit_p->maplist_user_buf_p = user_buf_p; /* not used in copy mode? */ if(unit_p->dma_copy_buf_p) { /* * we are in copy mode - if OUTPUT copy user data to buffer * set up maplist - we don't need to map since buffer already in kernel * offset always zero when using copy buffer */ unit_p->maplist_offset = 0; unit_p->maplist_length = buf_size; unit_p->maplist_nr_pages = (buf_size + PAGE_SIZE -1)/PAGE_SIZE; if(rw_mode != READ) { DPRINTI("copying user buffer to dma buffer"); if(idr_maplist_check(unit_p, instance)) { EPRINTI("maplist value(s) out of range!"); return -EINVAL; } if(copy_from_user(unit_p->dma_copy_buf_p, user_buf_p, buf_size)) { EPRINTI("copy_from_user error!"); return -EIO; } } } else { /* * we will be mapping and pinning the user buffer for direct DMA */ DPRINTI("mapping and pinning user buffer"); unit_p->maplist_offset = (unsigned long)user_buf_p & ~PAGE_MASK; unit_p->maplist_length = buf_size; unit_p->maplist_nr_pages = (unit_p->maplist_offset + buf_size -1 + ~PAGE_MASK) >> PAGE_SHIFT; if(idr_maplist_check(unit_p, instance)) { EPRINTI("maplist value(s) out of range!"); return -EINVAL; } if(idr_map_user_buf(unit_p, instance)) { EPRINTI("idr_map_user_buf failure!"); return -EIO; } } DPRINTI("buf_p = 0x%p, nr_pages = 0x%x, offset = 0x%x, length = 0x%x", unit_p->maplist_user_buf_p, unit_p->maplist_nr_pages, unit_p->maplist_offset, unit_p->maplist_length); return 0; } /* * unmap user buffer or copy kernel buffer to user buffer */ static int idr_unmap_or_copy_buf(struct idr_unit_t *unit_p, int instance) { DPRINTI("enterint routine"); if(unit_p->dma_copy_buf_p) { /* * copy buffer mode, copy if input operation */ if(unit_p->maplist_rw_mode == READ) { DPRINTI("copying dma data to user buffer"); if(idr_maplist_check(unit_p, instance)) { EPRINTI("maplist value(s) out of range!"); return -EINVAL; } if(copy_to_user(unit_p->maplist_user_buf_p, unit_p->dma_copy_buf_p, unit_p->maplist_length)) { EPRINTI("copy_to_user error!"); return -EIO; } } } else { /* * direct user buffer dma mode, unmap user buffer * maplist values already checked */ DPRINTI("unmapping user buffer"); idr_unmap_user_buf(unit_p, instance); } return 0; } /* * unmap if error requires undoing mapping - if copy mode, do nothing */ static void idr_unmap_on_error(struct idr_unit_t *unit_p, int instance) { DPRINTI("entering routine"); if(!unit_p->dma_copy_buf_p) { DPRINTI("calling idr_unmap_user_buf"); idr_unmap_user_buf(unit_p, instance); } else DPRINTI("copy buf mode, doing nothing"); } /* * map and pin user buffer for direct DMA * * code adapted from st.c */ static int idr_map_user_buf(struct idr_unit_t *unit_p, int instance) { int nr_pages_mapped; int i; DPRINTI("entering routine"); /* * Try to fault in all of the necessary pages * * rw==READ means read from drive, write into memory area * 0 arg = don't force */ down_read(¤t->mm->mmap_sem); nr_pages_mapped = get_user_pages(current, current->mm, (unsigned long)unit_p->maplist_user_buf_p, unit_p->maplist_nr_pages, unit_p->maplist_rw_mode == READ, 0, unit_p->maplist_p, NULL); up_read(¤t->mm->mmap_sem); /* * result == nr pages requested if all pages mapped * or - if error */ if(nr_pages_mapped < unit_p->maplist_nr_pages) { EPRINTI("couldn't map all (any?) pages!"); if(nr_pages_mapped > 0) { for(i=0; i < nr_pages_mapped; i++) put_page(unit_p->maplist_p[i]); } return -EIO; } /* * st.c includes this call here, but I believe * it is included in get_user_pages w/2.6 * * for (i=0; i < nr_pages; i++) * flush_dcache_page(unit_p->maplist_p[i]); */ return 0; } /* * unmap user buffer * * (comment from st.c) * FIXME: cache flush missing for rw==READ * FIXME: call the correct reference counting function */ static void idr_unmap_user_buf(struct idr_unit_t *unit_p, int instance) { int i; DPRINTI("entering routine"); for (i=0; i < unit_p->maplist_nr_pages; i++) { if (unit_p->maplist_rw_mode == READ) SetPageDirty(unit_p->maplist_p[i]); put_page(unit_p->maplist_p[i]); } } /* * convert maplist int sg list */ static int idr_maplist_to_sg_list(struct idr_unit_t *unit_p, int instance) { struct page **maplist; int map_nr_pages; int map_length; int map_offset; int temp_length; int i; DPRINT("entering routine"); /* * do a sanity check on the number of pages - it better not exceed the sg list max size */ if (unit_p->maplist_nr_pages > idr_max_sg_length) { EPRINTI("too many maplist pages!"); return -EIO; } /* * grind through the map list, extracting addresses and lengths for the sg list * don't forget the initial offset, and total length */ maplist = unit_p->maplist_p; map_length = unit_p->maplist_length; map_offset = unit_p->maplist_offset; map_nr_pages = unit_p->maplist_nr_pages; for (i = 0; i < map_nr_pages; i++) { temp_length = (PAGE_SIZE - map_offset) < map_length ? PAGE_SIZE - map_offset : map_length; /* * newer kernels with chained-scatterlist support don't * allow accessing the page element directly * * use macro to set page, offset, and length (in ihcp_var.h) * * this is what it used to look like: * * unit_p->sg_list_p[i].page = maplist[i]; * unit_p->sg_list_p[i].offset = map_offset; * unit_p->sg_list_p[i].length = temp_length; */ IDR_SET_PAGE((unit_p->sg_list_p + i), maplist[i], temp_length, map_offset); DPRINTI("page_ptr = 0x%p, page_offset = 0x%x, page_len = 0x%x", maplist[i], map_offset, temp_length); map_length -= temp_length; map_offset = 0; } return 0; } /* * convert sg list to iopb list for plx dma logic */ static int idr_sg_list_to_iopb_list(struct idr_unit_t *unit_p, int instance) { int num_iopbs; int iopb_number; u32 temp_bus_addr; int temp_length; u32 next_iopb_add; u32 plx_direction; DPRINT("entering routine"); /* * make sure num_iopbs <= kio_pages (we should probably just trust the mapping code) */ num_iopbs = unit_p->nr_iopbs; if (num_iopbs > unit_p->maplist_nr_pages) { EPRINTI("num_iopbs > maplist_nr_pages!"); return -EIO; } plx_direction = unit_p->maplist_rw_mode == READ ? DMA_INPUT : 0; /* * now assemble the scatter list into a form that the PLX chip wants to see, and * build iopb list * use IOPB macros to ease possible later mods to swizzle byte lanes */ for (iopb_number = 0; iopb_number < num_iopbs; iopb_number++) { temp_bus_addr = (u32) sg_dma_address(&(unit_p->sg_list_p[iopb_number])); temp_length = sg_dma_len(&(unit_p->sg_list_p[iopb_number])); /* * buff segment address, seg size, data destination */ IOPB_PUTL((iopb_number * IOPB_SIZE) + IOPB_PCI_ADDRESS, temp_bus_addr); IOPB_PUTL((iopb_number * IOPB_SIZE) + IOPB_TRANSFER_SIZE, temp_length); IOPB_PUTL((iopb_number * IOPB_SIZE) + IOPB_LOCAL_ADDRESS, IDR_DATA_OUT); DPRINTI("iopb number 0x%x, buf seg addr = 0x%x, buf seg length = 0x%x", iopb_number, temp_bus_addr, temp_length); /* * the next descriptor pointer element of the iopb includes the location bit * (pci or local memory), the end of chain bit, the interrupt after terminal * countbit (not used), the direction of transfer bit (0 = output to device), * and the bus add of the next iopb * * if the iopb_number = num_iopbs -1, this is the last one so flag it, and * don't set a next iopb address */ if (iopb_number < (num_iopbs - 1)) { next_iopb_add = DMA_NEXT_ADDRESS_MASK & ((u32)unit_p->dma_handle + ((iopb_number + 1) * IOPB_SIZE)); DPRINTI("not last iopb, next iopb add = 0x%x", next_iopb_add); IOPB_PUTL((iopb_number * IOPB_SIZE) + IOPB_NEXT_IOPB, DMA_CHAIN_IN_PCI_MEM | next_iopb_add | plx_direction); } else { DPRINTI("last iopb, setting end of chain bit"); IOPB_PUTL((iopb_number * IOPB_SIZE) + IOPB_NEXT_IOPB, DMA_CHAIN_IN_PCI_MEM | DMA_END_OF_CHAIN | plx_direction); } } return 0; } /* * mutex and conditional variable routines - were in idr_mutex.c * Kaz Kylheku & wdw */ static void idr_mutex_init(idr_mutex_t * mx) { spin_lock_init(&mx->spin); } static void idr_mutex_lock(idr_mutex_t * mx) { unsigned long flags; spin_lock_irqsave(&mx->spin, flags); mx->flags = flags; } static void idr_mutex_unlock(idr_mutex_t * mx) { unsigned long flags = mx->flags; spin_unlock_irqrestore(&mx->spin, flags); } static void idr_cond_init(idr_cond_t * cv) { init_waitqueue_head(&cv->queue); } static int idr_cond_timed_wait_rel(idr_cond_t * cv, idr_mutex_t * mx, long jiff_delta) { wait_queue_t wait; int ret; long remaining; init_waitqueue_entry(&wait, current); add_wait_queue(&cv->queue, &wait); current->state = TASK_INTERRUPTIBLE; idr_mutex_unlock(mx); remaining = schedule_timeout(jiff_delta); ret = remaining ? signal_pending(current) ? IDR_COND_WAIT_SIGNAL : IDR_COND_WAIT_SUCCESS : IDR_COND_WAIT_TIMEOUT; current->state = TASK_RUNNING; remove_wait_queue(&cv->queue, &wait); idr_mutex_lock(mx); return ret; } static void idr_cond_broadcast(idr_cond_t * cv) { wake_up_interruptible(&cv->queue); } /* * new-style init and cleanup routine invocations */ module_init(idr_init_module); module_exit(idr_cleanup_module);