/* * Perform one request-response transaction to the device. */ int islpci_mgt_transaction(struct net_device *ndev, int operation, unsigned long oid, void *senddata, int sendlen, struct islpci_mgmtframe **recvframe) { islpci_private *priv = netdev_priv(ndev); const long wait_cycle_jiffies = msecs_to_jiffies(ISL38XX_WAIT_CYCLE * 10); long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies; int err; DEFINE_WAIT(wait); *recvframe = NULL; if (mutex_lock_interruptible(&priv->mgmt_lock)) return -ERESTARTSYS; prepare_to_wait(&priv->mgmt_wqueue, &wait, TASK_UNINTERRUPTIBLE); err = islpci_mgt_transmit(ndev, operation, oid, senddata, sendlen); if (err) goto out; err = -ETIMEDOUT; while (timeout_left > 0) { int timeleft; struct islpci_mgmtframe *frame; timeleft = schedule_timeout_uninterruptible(wait_cycle_jiffies); frame = xchg(&priv->mgmt_received, NULL); if (frame) { if (frame->header->oid == oid) { *recvframe = frame; err = 0; goto out; } else { // printk(KERN_DEBUG // "%s: expecting oid 0x%x, received 0x%x.\n", // ndev->name, (unsigned int) oid, ; kfree(frame); frame = NULL; } } if (timeleft == 0) { // printk(KERN_DEBUG // "%s: timeout waiting for mgmt response %lu, " // "triggering device\n", ; islpci_trigger(priv); } timeout_left += timeleft - wait_cycle_jiffies; } // printk(KERN_WARNING "%s: timeout waiting for mgmt response\n", ; /* TODO: we should reset the device here */ out: finish_wait(&priv->mgmt_wqueue, &wait); mutex_unlock(&priv->mgmt_lock); return err; }
/****************************************************************************** Device Interrupt Handler ******************************************************************************/ void islpci_interrupt(int irq, void *config, struct pt_regs *regs) { u32 reg; islpci_private *private_config = config; void *device = private_config->device_id; u16 status; // received an interrupt request on a shared IRQ line // first check whether the device is in sleep mode if( reg = readl( device + ISL38XX_CTRL_STAT_REG), reg & ISL38XX_CTRL_STAT_SLEEPMODE ) // device is in sleep mode, IRQ was generated by someone else return; // lock the interrupt handler spin_lock( &private_config->slock ); #ifdef CONFIG_ARCH_ISL3893 // check the interrupt source on the host registers reg = (u32) uPCI->ARMIntReg; reg &= (u32) uPCI->ARMIntEnReg; // pci_unmap_single( private_config->pci_device, private_config->control_block, // sizeof(struct isl38xx_cb), PCI_DMA_FROMDEVICE ); flush_cache_all(); #else // check whether there is any source of interrupt on the device reg = readl(device + ISL38XX_INT_IDENT_REG); // also check the contents of the Interrupt Enable Register, because this // will filter out interrupt sources from other devices on the same irq ! reg &= readl(device + ISL38XX_INT_EN_REG); #endif if (reg &= ISL38XX_INT_SOURCES, reg != 0) { #ifdef CONFIG_ARCH_ISL3893 // write the acknowledge register on the host uPCI->ARMIntAckReg = reg; #else // reset the request bits in the Identification register writel(reg, device + ISL38XX_INT_ACK_REG); #endif #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_FUNCTION_CALLS, "IRQ: Identification register value 0x%x \n", reg ); #endif // check for each bit in the register separately if (reg & ISL38XX_INT_IDENT_UPDATE) { #if VERBOSE > SHOW_ERROR_MESSAGES // Queue has been updated DEBUG(SHOW_TRACING, "IRQ: Update flag \n"); DEBUG(SHOW_QUEUE_INDEXES, "CB drv Qs: [%i][%i][%i][%i][%i][%i]\n", le32_to_cpu(private_config->control_block->driver_curr_frag[0]), le32_to_cpu(private_config->control_block->driver_curr_frag[1]), le32_to_cpu(private_config->control_block->driver_curr_frag[2]), le32_to_cpu(private_config->control_block->driver_curr_frag[3]), le32_to_cpu(private_config->control_block->driver_curr_frag[4]), le32_to_cpu(private_config->control_block->driver_curr_frag[5]) ); DEBUG(SHOW_QUEUE_INDEXES, "CB dev Qs: [%i][%i][%i][%i][%i][%i]\n", le32_to_cpu(private_config->control_block->device_curr_frag[0]), le32_to_cpu(private_config->control_block->device_curr_frag[1]), le32_to_cpu(private_config->control_block->device_curr_frag[2]), le32_to_cpu(private_config->control_block->device_curr_frag[3]), le32_to_cpu(private_config->control_block->device_curr_frag[4]), le32_to_cpu(private_config->control_block->device_curr_frag[5]) ); #endif // device is in active state, update the powerstate flag private_config->powerstate = ISL38XX_PSM_ACTIVE_STATE; // check all three queues in priority order // call the PIMFOR receive function until the queue is empty while (isl38xx_in_queue(private_config->control_block, ISL38XX_CB_RX_MGMTQ) != 0) { #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "Received frame in Management Queue\n"); #endif islpci_mgt_receive(private_config); // call the pimfor transmit function for processing the next // management frame in the shadow queue islpci_mgt_transmit( private_config ); } while (isl38xx_in_queue(private_config->control_block, ISL38XX_CB_RX_DATA_LQ) != 0) { #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "Received frame in Data Low Queue \n"); #endif islpci_eth_receive(private_config); } // check whether the data transmit queues were full if (private_config->data_low_tx_full) { // check whether the transmit is not full anymore if( ISL38XX_CB_TX_QSIZE - isl38xx_in_queue( private_config->control_block, ISL38XX_CB_TX_DATA_LQ ) >= ISL38XX_MIN_QTHRESHOLD ) { // nope, the driver is ready for more network frames netif_wake_queue(private_config->my_module); // reset the full flag private_config->data_low_tx_full = 0; } } } if (reg & ISL38XX_INT_IDENT_INIT) { // Device has been initialized #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "IRQ: Init flag, device initialized \n"); #endif // perform card initlialization by sending objects islpci_mgt_initialize( private_config ); } if (reg & ISL38XX_INT_IDENT_SLEEP) { // Device intends to move to powersave state #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_ANYTHING, "IRQ: Sleep flag \n"); #endif isl38xx_handle_sleep_request( private_config->control_block, &private_config->powerstate, private_config->remapped_device_base ); } if (reg & ISL38XX_INT_IDENT_WAKEUP) { // Device has been woken up to active state #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_ANYTHING, "IRQ: Wakeup flag \n"); #endif isl38xx_handle_wakeup( private_config->control_block, &private_config->powerstate, private_config->remapped_device_base ); } } // unlock the interrupt handler spin_unlock( &private_config->slock ); return; }