コード例 #1
0
ファイル: islpci_dev.c プロジェクト: 3sOx/asuswrt-merlin
irqreturn_t
islpci_interrupt(int irq, void *config)
{
	u32 reg;
	islpci_private *priv = config;
	struct net_device *ndev = priv->ndev;
	void __iomem *device = priv->device_base;
	int powerstate = ISL38XX_PSM_POWERSAVE_STATE;

	/* lock the interrupt handler */
	spin_lock(&priv->slock);

	/* received an interrupt request on a shared IRQ line
	 * first check whether the device is in sleep mode */
	reg = readl(device + ISL38XX_CTRL_STAT_REG);
	if (reg & ISL38XX_CTRL_STAT_SLEEPMODE)
		/* device is in sleep mode, IRQ was generated by someone else */
	{
#if VERBOSE > SHOW_ERROR_MESSAGES
		DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n");
#endif
		spin_unlock(&priv->slock);
		return IRQ_NONE;
	}


	/* 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);
	reg &= ISL38XX_INT_SOURCES;

	if (reg != 0) {
		if (islpci_get_state(priv) != PRV_STATE_SLEEP)
			powerstate = ISL38XX_PSM_ACTIVE_STATE;

		/* reset the request bits in the Identification register */
		isl38xx_w32_flush(device, reg, ISL38XX_INT_ACK_REG);

#if VERBOSE > SHOW_ERROR_MESSAGES
		DEBUG(SHOW_FUNCTION_CALLS,
		      "IRQ: Identification register 0x%p 0x%x \n", device, 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(priv->control_block->
					  driver_curr_frag[0]),
			      le32_to_cpu(priv->control_block->
					  driver_curr_frag[1]),
			      le32_to_cpu(priv->control_block->
					  driver_curr_frag[2]),
			      le32_to_cpu(priv->control_block->
					  driver_curr_frag[3]),
			      le32_to_cpu(priv->control_block->
					  driver_curr_frag[4]),
			      le32_to_cpu(priv->control_block->
					  driver_curr_frag[5])
			    );

			DEBUG(SHOW_QUEUE_INDEXES,
			      "CB dev Qs: [%i][%i][%i][%i][%i][%i]\n",
			      le32_to_cpu(priv->control_block->
					  device_curr_frag[0]),
			      le32_to_cpu(priv->control_block->
					  device_curr_frag[1]),
			      le32_to_cpu(priv->control_block->
					  device_curr_frag[2]),
			      le32_to_cpu(priv->control_block->
					  device_curr_frag[3]),
			      le32_to_cpu(priv->control_block->
					  device_curr_frag[4]),
			      le32_to_cpu(priv->control_block->
					  device_curr_frag[5])
			    );
#endif

			/* cleanup the data low transmit queue */
			islpci_eth_cleanup_transmit(priv, priv->control_block);

			/* device is in active state, update the
			 * powerstate flag if necessary */
			powerstate = ISL38XX_PSM_ACTIVE_STATE;

			/* check all three queues in priority order
			 * call the PIMFOR receive function until the
			 * queue is empty */
			if (isl38xx_in_queue(priv->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(ndev);

				islpci_mgt_cleanup_transmit(ndev);

				/* Refill slots in receive queue */
				islpci_mgmt_rx_fill(ndev);

				/* no need to trigger the device, next
                                   islpci_mgt_transaction does it */
			}

			while (isl38xx_in_queue(priv->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(priv);
			}

			/* check whether the data transmit queues were full */
			if (priv->data_low_tx_full) {
				/* check whether the transmit is not full anymore */
				if (ISL38XX_CB_TX_QSIZE -
				    isl38xx_in_queue(priv->control_block,
						     ISL38XX_CB_TX_DATA_LQ) >=
				    ISL38XX_MIN_QTHRESHOLD) {
					/* nope, the driver is ready for more network frames */
					netif_wake_queue(priv->ndev);

					/* reset the full flag */
					priv->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
			wake_up(&priv->reset_done);
		}

		if (reg & ISL38XX_INT_IDENT_SLEEP) {
			/* Device intends to move to powersave state */
#if VERBOSE > SHOW_ERROR_MESSAGES
			DEBUG(SHOW_TRACING, "IRQ: Sleep flag \n");
#endif
			isl38xx_handle_sleep_request(priv->control_block,
						     &powerstate,
						     priv->device_base);
		}

		if (reg & ISL38XX_INT_IDENT_WAKEUP) {
			/* Device has been woken up to active state */
#if VERBOSE > SHOW_ERROR_MESSAGES
			DEBUG(SHOW_TRACING, "IRQ: Wakeup flag \n");
#endif

			isl38xx_handle_wakeup(priv->control_block,
					      &powerstate, priv->device_base);
		}
	} else {
#if VERBOSE > SHOW_ERROR_MESSAGES
		DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n");
#endif
		spin_unlock(&priv->slock);
		return IRQ_NONE;
	}

	/* sleep -> ready */
	if (islpci_get_state(priv) == PRV_STATE_SLEEP
	    && powerstate == ISL38XX_PSM_ACTIVE_STATE)
		islpci_set_state(priv, PRV_STATE_READY);

	/* !sleep -> sleep */
	if (islpci_get_state(priv) != PRV_STATE_SLEEP
	    && powerstate == ISL38XX_PSM_POWERSAVE_STATE)
		islpci_set_state(priv, PRV_STATE_SLEEP);

	/* unlock the interrupt handler */
	spin_unlock(&priv->slock);

	return IRQ_HANDLED;
}
コード例 #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;
}