irq.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 544 行 · 第 1/2 页
C
544 行
/****************************************************************************** * irq.c * * Interrupt distribution and delivery logic. * * Copyright (c) 2006, K A Fraser, XenSource Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 <xen/config.h>#include <xen/types.h>#include <xen/event.h>#include <xen/sched.h>#include <asm/hvm/domain.h>#include <asm/hvm/support.h>static void __hvm_pci_intx_assert( struct domain *d, unsigned int device, unsigned int intx){ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; unsigned int gsi, link, isa_irq; ASSERT((device <= 31) && (intx <= 3)); if ( __test_and_set_bit(device*4 + intx, &hvm_irq->pci_intx.i) ) return; gsi = hvm_pci_intx_gsi(device, intx); if ( hvm_irq->gsi_assert_count[gsi]++ == 0 ) vioapic_irq_positive_edge(d, gsi); link = hvm_pci_intx_link(device, intx); isa_irq = hvm_irq->pci_link.route[link]; if ( (hvm_irq->pci_link_assert_count[link]++ == 0) && isa_irq && (hvm_irq->gsi_assert_count[isa_irq]++ == 0) ) { vioapic_irq_positive_edge(d, isa_irq); vpic_irq_positive_edge(d, isa_irq); }}void hvm_pci_intx_assert( struct domain *d, unsigned int device, unsigned int intx){ spin_lock(&d->arch.hvm_domain.irq_lock); __hvm_pci_intx_assert(d, device, intx); spin_unlock(&d->arch.hvm_domain.irq_lock);}static void __hvm_pci_intx_deassert( struct domain *d, unsigned int device, unsigned int intx){ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; unsigned int gsi, link, isa_irq; ASSERT((device <= 31) && (intx <= 3)); if ( !__test_and_clear_bit(device*4 + intx, &hvm_irq->pci_intx.i) ) return; gsi = hvm_pci_intx_gsi(device, intx); --hvm_irq->gsi_assert_count[gsi]; link = hvm_pci_intx_link(device, intx); isa_irq = hvm_irq->pci_link.route[link]; if ( (--hvm_irq->pci_link_assert_count[link] == 0) && isa_irq && (--hvm_irq->gsi_assert_count[isa_irq] == 0) ) vpic_irq_negative_edge(d, isa_irq);}void hvm_pci_intx_deassert( struct domain *d, unsigned int device, unsigned int intx){ spin_lock(&d->arch.hvm_domain.irq_lock); __hvm_pci_intx_deassert(d, device, intx); spin_unlock(&d->arch.hvm_domain.irq_lock);}void hvm_isa_irq_assert( struct domain *d, unsigned int isa_irq){ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; unsigned int gsi = hvm_isa_irq_to_gsi(isa_irq); ASSERT(isa_irq <= 15); spin_lock(&d->arch.hvm_domain.irq_lock); if ( !__test_and_set_bit(isa_irq, &hvm_irq->isa_irq.i) && (hvm_irq->gsi_assert_count[gsi]++ == 0) ) { vioapic_irq_positive_edge(d, gsi); vpic_irq_positive_edge(d, isa_irq); } spin_unlock(&d->arch.hvm_domain.irq_lock);}void hvm_isa_irq_deassert( struct domain *d, unsigned int isa_irq){ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; unsigned int gsi = hvm_isa_irq_to_gsi(isa_irq); ASSERT(isa_irq <= 15); spin_lock(&d->arch.hvm_domain.irq_lock); if ( __test_and_clear_bit(isa_irq, &hvm_irq->isa_irq.i) && (--hvm_irq->gsi_assert_count[gsi] == 0) ) vpic_irq_negative_edge(d, isa_irq); spin_unlock(&d->arch.hvm_domain.irq_lock);}static void hvm_set_callback_irq_level(struct vcpu *v){ struct domain *d = v->domain; struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; unsigned int gsi, pdev, pintx, asserted; ASSERT(v->vcpu_id == 0); spin_lock(&d->arch.hvm_domain.irq_lock); /* NB. Do not check the evtchn_upcall_mask. It is not used in HVM mode. */ asserted = !!vcpu_info(v, evtchn_upcall_pending); if ( hvm_irq->callback_via_asserted == asserted ) goto out; hvm_irq->callback_via_asserted = asserted; /* Callback status has changed. Update the callback via. */ switch ( hvm_irq->callback_via_type ) { case HVMIRQ_callback_gsi: gsi = hvm_irq->callback_via.gsi; if ( asserted && (hvm_irq->gsi_assert_count[gsi]++ == 0) ) { vioapic_irq_positive_edge(d, gsi); if ( gsi <= 15 ) vpic_irq_positive_edge(d, gsi); } else if ( !asserted && (--hvm_irq->gsi_assert_count[gsi] == 0) ) { if ( gsi <= 15 ) vpic_irq_negative_edge(d, gsi); } break; case HVMIRQ_callback_pci_intx: pdev = hvm_irq->callback_via.pci.dev; pintx = hvm_irq->callback_via.pci.intx; if ( asserted ) __hvm_pci_intx_assert(d, pdev, pintx); else __hvm_pci_intx_deassert(d, pdev, pintx); default: break; } out: spin_unlock(&d->arch.hvm_domain.irq_lock);}void hvm_maybe_deassert_evtchn_irq(void){ struct domain *d = current->domain; struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; if ( hvm_irq->callback_via_asserted && !vcpu_info(d->vcpu[0], evtchn_upcall_pending) ) hvm_set_callback_irq_level(d->vcpu[0]);}void hvm_assert_evtchn_irq(struct vcpu *v){ if ( v->vcpu_id == 0 ) hvm_set_callback_irq_level(v);}void hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq){ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; u8 old_isa_irq; int i; ASSERT((link <= 3) && (isa_irq <= 15)); spin_lock(&d->arch.hvm_domain.irq_lock); old_isa_irq = hvm_irq->pci_link.route[link]; if ( old_isa_irq == isa_irq ) goto out; hvm_irq->pci_link.route[link] = isa_irq; /* PCI pass-through fixup. */ if ( hvm_irq->dpci ) { if ( old_isa_irq ) clear_bit(old_isa_irq, &hvm_irq->dpci->isairq_map); for ( i = 0; i < NR_LINK; i++ ) if ( hvm_irq->dpci->link_cnt[i] && hvm_irq->pci_link.route[i] ) set_bit(hvm_irq->pci_link.route[i], &hvm_irq->dpci->isairq_map); } if ( hvm_irq->pci_link_assert_count[link] == 0 ) goto out; if ( old_isa_irq && (--hvm_irq->gsi_assert_count[old_isa_irq] == 0) ) vpic_irq_negative_edge(d, old_isa_irq); if ( isa_irq && (hvm_irq->gsi_assert_count[isa_irq]++ == 0) ) { vioapic_irq_positive_edge(d, isa_irq); vpic_irq_positive_edge(d, isa_irq); } out: spin_unlock(&d->arch.hvm_domain.irq_lock); dprintk(XENLOG_G_INFO, "Dom%u PCI link %u changed %u -> %u\n", d->domain_id, link, old_isa_irq, isa_irq);}void hvm_set_callback_via(struct domain *d, uint64_t via){ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; unsigned int gsi=0, pdev=0, pintx=0; uint8_t via_type; via_type = (uint8_t)(via >> 56) + 1; if ( ((via_type == HVMIRQ_callback_gsi) && (via == 0)) || (via_type > HVMIRQ_callback_pci_intx) ) via_type = HVMIRQ_callback_none; spin_lock(&d->arch.hvm_domain.irq_lock); /* Tear down old callback via. */ if ( hvm_irq->callback_via_asserted ) { switch ( hvm_irq->callback_via_type ) { case HVMIRQ_callback_gsi: gsi = hvm_irq->callback_via.gsi; if ( (--hvm_irq->gsi_assert_count[gsi] == 0) && (gsi <= 15) ) vpic_irq_negative_edge(d, gsi); break; case HVMIRQ_callback_pci_intx: pdev = hvm_irq->callback_via.pci.dev; pintx = hvm_irq->callback_via.pci.intx; __hvm_pci_intx_deassert(d, pdev, pintx); break; default: break; } } /* Set up new callback via. */ switch ( hvm_irq->callback_via_type = via_type )
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?