⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 interrupt.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  PS3 interrupt routines. * *  Copyright (C) 2006 Sony Computer Entertainment Inc. *  Copyright 2006 Sony Corp. * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; version 2 of the License. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include <linux/kernel.h>#include <linux/module.h>#include <linux/irq.h>#include <asm/machdep.h>#include <asm/udbg.h>#include <asm/lv1call.h>#include <asm/smp.h>#include "platform.h"#if defined(DEBUG)#define DBG udbg_printf#else#define DBG pr_debug#endif/** * struct ps3_bmp - a per cpu irq status and mask bitmap structure * @status: 256 bit status bitmap indexed by plug * @unused_1: * @mask: 256 bit mask bitmap indexed by plug * @unused_2: * @lock: * @ipi_debug_brk_mask: * * The HV mantains per SMT thread mappings of HV outlet to HV plug on * behalf of the guest.  These mappings are implemented as 256 bit guest * supplied bitmaps indexed by plug number.  The addresses of the bitmaps * are registered with the HV through lv1_configure_irq_state_bitmap(). * The HV requires that the 512 bits of status + mask not cross a page * boundary.  PS3_BMP_MINALIGN is used to define this minimal 64 byte * alignment. * * The HV supports 256 plugs per thread, assigned as {0..255}, for a total * of 512 plugs supported on a processor.  To simplify the logic this * implementation equates HV plug value to Linux virq value, constrains each * interrupt to have a system wide unique plug number, and limits the range * of the plug values to map into the first dword of the bitmaps.  This * gives a usable range of plug values of  {NUM_ISA_INTERRUPTS..63}.  Note * that there is no constraint on how many in this set an individual thread * can acquire. */#define PS3_BMP_MINALIGN 64struct ps3_bmp {	struct {		u64 status;		u64 unused_1[3];		u64 mask;		u64 unused_2[3];	};	u64 ipi_debug_brk_mask;	spinlock_t lock;};/** * struct ps3_private - a per cpu data structure * @bmp: ps3_bmp structure * @ppe_id: HV logical_ppe_id * @thread_id: HV thread_id */struct ps3_private {	struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN)));	u64 ppe_id;	u64 thread_id;};static DEFINE_PER_CPU(struct ps3_private, ps3_private);/** * ps3_chip_mask - Set an interrupt mask bit in ps3_bmp. * @virq: The assigned Linux virq. * * Sets ps3_bmp.mask and calls lv1_did_update_interrupt_mask(). */static void ps3_chip_mask(unsigned int virq){	struct ps3_private *pd = get_irq_chip_data(virq);	unsigned long flags;	pr_debug("%s:%d: thread_id %lu, virq %d\n", __func__, __LINE__,		pd->thread_id, virq);	local_irq_save(flags);	clear_bit(63 - virq, &pd->bmp.mask);	lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);	local_irq_restore(flags);}/** * ps3_chip_unmask - Clear an interrupt mask bit in ps3_bmp. * @virq: The assigned Linux virq. * * Clears ps3_bmp.mask and calls lv1_did_update_interrupt_mask(). */static void ps3_chip_unmask(unsigned int virq){	struct ps3_private *pd = get_irq_chip_data(virq);	unsigned long flags;	pr_debug("%s:%d: thread_id %lu, virq %d\n", __func__, __LINE__,		pd->thread_id, virq);	local_irq_save(flags);	set_bit(63 - virq, &pd->bmp.mask);	lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);	local_irq_restore(flags);}/** * ps3_chip_eoi - HV end-of-interrupt. * @virq: The assigned Linux virq. * * Calls lv1_end_of_interrupt_ext(). */static void ps3_chip_eoi(unsigned int virq){	const struct ps3_private *pd = get_irq_chip_data(virq);	lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, virq);}/** * ps3_irq_chip - Represents the ps3_bmp as a Linux struct irq_chip. */static struct irq_chip ps3_irq_chip = {	.typename = "ps3",	.mask = ps3_chip_mask,	.unmask = ps3_chip_unmask,	.eoi = ps3_chip_eoi,};/** * ps3_virq_setup - virq related setup. * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be * serviced on. * @outlet: The HV outlet from the various create outlet routines. * @virq: The assigned Linux virq. * * Calls irq_create_mapping() to get a virq and sets the chip data to * ps3_private data. */int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,	unsigned int *virq){	int result;	struct ps3_private *pd;	/* This defines the default interrupt distribution policy. */	if (cpu == PS3_BINDING_CPU_ANY)		cpu = 0;	pd = &per_cpu(ps3_private, cpu);	*virq = irq_create_mapping(NULL, outlet);	if (*virq == NO_IRQ) {		pr_debug("%s:%d: irq_create_mapping failed: outlet %lu\n",			__func__, __LINE__, outlet);		result = -ENOMEM;		goto fail_create;	}	pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,		outlet, cpu, *virq);	result = set_irq_chip_data(*virq, pd);	if (result) {		pr_debug("%s:%d: set_irq_chip_data failed\n",			__func__, __LINE__);		goto fail_set;	}	ps3_chip_mask(*virq);	return result;fail_set:	irq_dispose_mapping(*virq);fail_create:	return result;}/** * ps3_virq_destroy - virq related teardown. * @virq: The assigned Linux virq. * * Clears chip data and calls irq_dispose_mapping() for the virq. */int ps3_virq_destroy(unsigned int virq){	const struct ps3_private *pd = get_irq_chip_data(virq);	pr_debug("%s:%d: ppe_id %lu, thread_id %lu, virq %u\n", __func__,		__LINE__, pd->ppe_id, pd->thread_id, virq);	set_irq_chip_data(virq, NULL);	irq_dispose_mapping(virq);	pr_debug("%s:%d <-\n", __func__, __LINE__);	return 0;}/** * ps3_irq_plug_setup - Generic outlet and virq related setup. * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be * serviced on. * @outlet: The HV outlet from the various create outlet routines. * @virq: The assigned Linux virq. * * Sets up virq and connects the irq plug. */int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,	unsigned int *virq){	int result;	struct ps3_private *pd;	result = ps3_virq_setup(cpu, outlet, virq);	if (result) {		pr_debug("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__);		goto fail_setup;	}	pd = get_irq_chip_data(*virq);	/* Binds outlet to cpu + virq. */	result = lv1_connect_irq_plug_ext(pd->ppe_id, pd->thread_id, *virq,		outlet, 0);	if (result) {		pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",		__func__, __LINE__, ps3_result(result));		result = -EPERM;		goto fail_connect;	}	return result;fail_connect:	ps3_virq_destroy(*virq);fail_setup:	return result;}EXPORT_SYMBOL_GPL(ps3_irq_plug_setup);/** * ps3_irq_plug_destroy - Generic outlet and virq related teardown. * @virq: The assigned Linux virq. * * Disconnects the irq plug and tears down virq. * Do not call for system bus event interrupts setup with * ps3_sb_event_receive_port_setup(). */int ps3_irq_plug_destroy(unsigned int virq){	int result;	const struct ps3_private *pd = get_irq_chip_data(virq);	pr_debug("%s:%d: ppe_id %lu, thread_id %lu, virq %u\n", __func__,		__LINE__, pd->ppe_id, pd->thread_id, virq);	ps3_chip_mask(virq);	result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq);	if (result)		pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",		__func__, __LINE__, ps3_result(result));	ps3_virq_destroy(virq);	return result;}EXPORT_SYMBOL_GPL(ps3_irq_plug_destroy);/** * ps3_event_receive_port_setup - Setup an event receive port. * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be * serviced on. * @virq: The assigned Linux virq. * * The virq can be used with lv1_connect_interrupt_event_receive_port() to * arrange to receive interrupts from system-bus devices, or with * ps3_send_event_locally() to signal events. */int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq){	int result;	unsigned long outlet;	result = lv1_construct_event_receive_port(&outlet);	if (result) {		pr_debug("%s:%d: lv1_construct_event_receive_port failed: %s\n",			__func__, __LINE__, ps3_result(result));		*virq = NO_IRQ;		return result;	}	result = ps3_irq_plug_setup(cpu, outlet, virq);	BUG_ON(result);	return result;}EXPORT_SYMBOL_GPL(ps3_event_receive_port_setup);/** * ps3_event_receive_port_destroy - Destroy an event receive port. * @virq: The assigned Linux virq. * * Since ps3_event_receive_port_destroy destroys the receive port outlet, * SB devices need to call disconnect_interrupt_event_receive_port() before * this. */int ps3_event_receive_port_destroy(unsigned int virq){	int result;	pr_debug(" -> %s:%d virq %u\n", __func__, __LINE__, virq);	ps3_chip_mask(virq);	result = lv1_destruct_event_receive_port(virq_to_hw(virq));	if (result)		pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n",			__func__, __LINE__, ps3_result(result));	/*	 * Don't call ps3_virq_destroy() here since ps3_smp_cleanup_cpu()	 * calls from interrupt context (smp_call_function) when kexecing.	 */	pr_debug(" <- %s:%d\n", __func__, __LINE__);	return result;}int ps3_send_event_locally(unsigned int virq){	return lv1_send_event_locally(virq_to_hw(virq));}/** * ps3_sb_event_receive_port_setup - Setup a system bus event receive port. * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be * serviced on. * @dev: The system bus device instance. * @virq: The assigned Linux virq. * * An event irq represents a virtual device interrupt.  The interrupt_id * coresponds to the software interrupt number.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -