Esempio n. 1
0
File: cio.c Progetto: AllenDou/linux
/*
 * Use cio_tsch to update the subchannel status and call the interrupt handler
 * if status had been pending. Called with the console_subchannel lock.
 */
static void cio_tsch(struct subchannel *sch)
{
	struct irb *irb;
	int irq_context;

	irb = (struct irb *)&S390_lowcore.irb;
	/* Store interrupt response block to lowcore. */
	if (tsch(sch->schid, irb) != 0)
		/* Not status pending or not operational. */
		return;
	memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
	/* Call interrupt handler with updated status. */
	irq_context = in_interrupt();
	if (!irq_context) {
		local_bh_disable();
		irq_enter();
	}
	if (sch->driver && sch->driver->irq)
		sch->driver->irq(sch);
	else
		kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
	if (!irq_context) {
		irq_exit();
		_local_bh_enable();
	}
}
Esempio n. 2
0
/*
 * Use cio_tsch to update the subchannel status and call the interrupt handler
 * if status had been pending. Called with the subchannel's lock held.
 */
void cio_tsch(struct subchannel *sch)
{
	struct irb *irb;
	int irq_context;

	irb = this_cpu_ptr(&cio_irb);
	/* Store interrupt response block to lowcore. */
	if (tsch(sch->schid, irb) != 0)
		/* Not status pending or not operational. */
		return;
	memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
	/* Call interrupt handler with updated status. */
	irq_context = in_interrupt();
	if (!irq_context) {
		local_bh_disable();
		irq_enter();
	}
	kstat_incr_irq_this_cpu(IO_INTERRUPT);
	if (sch->driver && sch->driver->irq)
		sch->driver->irq(sch);
	else
		inc_irq_stat(IRQIO_CIO);
	if (!irq_context) {
		irq_exit();
		_local_bh_enable();
	}
}
Esempio n. 3
0
static int cio_tpi(void)
{
	struct tpi_info *tpi_info;
	struct subchannel *sch;
	struct irb *irb;
	int irq_context;

	tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id;
	if (tpi(NULL) != 1)
		return 0;
	irb = (struct irb *)&S390_lowcore.irb;
	/* Store interrupt response block to lowcore. */
	if (tsch(tpi_info->schid, irb) != 0)
		/* Not status pending or not operational. */
		return 1;
	sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
	if (!sch)
		return 1;
	irq_context = in_interrupt();
	if (!irq_context)
		local_bh_disable();
	irq_enter();
	spin_lock(sch->lock);
	memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
	if (sch->driver && sch->driver->irq)
		sch->driver->irq(sch);
	spin_unlock(sch->lock);
	irq_exit();
	if (!irq_context)
		_local_bh_enable();
	return 1;
}
Esempio n. 4
0
/*
 * Use tpi to get a pending interrupt, call the interrupt handler and
 * return a pointer to the subchannel structure.
 */
static inline int
cio_tpi(void)
{
	struct tpi_info *tpi_info;
	struct subchannel *sch;
	struct irb *irb;

	tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID;
	if (tpi (NULL) != 1)
		return 0;
	irb = (struct irb *) __LC_IRB;
	/* Store interrupt response block to lowcore. */
	if (tsch (tpi_info->schid, irb) != 0)
		/* Not status pending or not operational. */
		return 1;
	sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
	if (!sch)
		return 1;
	local_bh_disable();
	irq_enter ();
	spin_lock(&sch->lock);
	memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw));
	if (sch->driver && sch->driver->irq)
		sch->driver->irq(&sch->dev);
	spin_unlock(&sch->lock);
	irq_exit ();
	_local_bh_enable();
	return 1;
}
/*
 * Enter an interrupt context.
 */
void irq_enter(void)
{
	rcu_irq_enter();
	if (is_idle_task(current) && !in_interrupt()) {
		/*
		 * Prevent raise_softirq from needlessly waking up ksoftirqd
		 * here, as softirq will be serviced on return from interrupt.
		 */
		local_bh_disable();
		tick_check_idle();
		_local_bh_enable();
	}

	__irq_enter();
}
Esempio n. 6
0
asmlinkage void __do_softirq(void)
{
	struct softirq_action *h;
	__u32 pending;
	int max_restart = MAX_SOFTIRQ_RESTART;
	int cpu;

	pending = local_softirq_pending();
	account_system_vtime(current);

	__local_bh_disable((unsigned long)__builtin_return_address(0));
	trace_softirq_enter();

	cpu = smp_processor_id();
restart:
	/* Reset the pending bitmask before enabling irqs */
	set_softirq_pending(0);

	local_irq_enable();

	h = softirq_vec;

	do {
		if (pending & 1) {
			kstat_incr_softirqs_this_cpu(h - softirq_vec);
			h->action(h);
			rcu_bh_qsctr_inc(cpu);
		}
		h++;
		pending >>= 1;
	} while (pending);

	local_irq_disable();

	pending = local_softirq_pending();
	if (pending && --max_restart)
		goto restart;

	if (pending)
		wakeup_softirqd();

	trace_softirq_exit();

	account_system_vtime(current);
	_local_bh_enable();
}
/*
 * Use cio_tpi to get a pending interrupt and call the interrupt handler.
 * Return non-zero if an interrupt was processed, zero otherwise.
 */
static int cio_tpi(void)
{
	struct tpi_info *tpi_info;
	struct subchannel *sch;
	struct irb *irb;
	int irq_context;

	tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id;
	if (tpi(NULL) != 1)
		return 0;
	kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++;
	if (tpi_info->adapter_IO) {
		do_adapter_IO(tpi_info->isc);
		return 1;
	}
	irb = (struct irb *)&S390_lowcore.irb;
	/* Store interrupt response block to lowcore. */
	if (tsch(tpi_info->schid, irb) != 0) {
		/* Not status pending or not operational. */
		kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
		return 1;
	}
	sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
	if (!sch) {
		kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
		return 1;
	}
	irq_context = in_interrupt();
	if (!irq_context)
		local_bh_disable();
	irq_enter();
	spin_lock(sch->lock);
	memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
	if (sch->driver && sch->driver->irq)
		sch->driver->irq(sch);
	else
		kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
	spin_unlock(sch->lock);
	irq_exit();
	if (!irq_context)
		_local_bh_enable();
	return 1;
}