Example #1
0
/*
 * 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;
}
Example #2
0
/******************************************************************************
    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;
}