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 + -
显示快捷键?