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

📄 viosapic.c

📁 xen 3.2.2 源码
💻 C
字号:
/* *  Copyright (C) 2001  MandrakeSoft S.A. * *    MandrakeSoft S.A. *    43, rue d'Aboukir *    75002 Paris - France *    http://www.linux-mandrake.com/ *    http://www.mandrakesoft.com/ * *  This library is free software; you can redistribute it and/or *  modify it under the terms of the GNU Lesser General Public *  License as published by the Free Software Foundation; either *  version 2 of the License, or (at your option) any later version. * *  This library 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 *  Lesser General Public License for more details. * *  You should have received a copy of the GNU Lesser General Public *  License along with this library; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA * *  Yunhong Jiang <yunhong.jiang@intel.com> *  Ported to xen by using virtual IRQ line. *  *  Copyright (C) 2007 VA Linux Systems Japan K.K. *  Isaku Yamahata <yamahata at valinux co jp> *  SMP support *  xen save/restore support */#include <xen/config.h>#include <xen/types.h>#include <xen/mm.h>#include <xen/xmalloc.h>#include <xen/lib.h>#include <xen/errno.h>#include <public/hvm/ioreq.h>#include <asm/vlsapic.h>#include <asm/viosapic.h>#include <asm/current.h>#include <asm/event.h>#include <asm/hvm/support.h>#include <public/hvm/save.h>static void viosapic_deliver(struct viosapic *viosapic, int irq){    uint16_t dest = viosapic->redirtbl[irq].dest_id;    uint8_t delivery_mode = viosapic->redirtbl[irq].delivery_mode;    uint8_t vector = viosapic->redirtbl[irq].vector;    struct vcpu *v;    ASSERT(spin_is_locked(&viosapic->lock));    switch ( delivery_mode )    {    case SAPIC_FIXED:    {        v = vlsapic_lid_to_vcpu(viosapic_domain(viosapic), dest);        vlsapic_set_irq(v, vector);        vcpu_kick(v);        break;    }    case SAPIC_LOWEST_PRIORITY:    {        v = vlsapic_lid_to_vcpu(viosapic_domain(viosapic), dest);        if (viosapic->lowest_vcpu)            v = viosapic->lowest_vcpu;        vlsapic_set_irq(v, vector);        vcpu_kick(v);        break;    }    case SAPIC_PMI:    case SAPIC_NMI:    case SAPIC_INIT:    case SAPIC_EXTINT:    default:        gdprintk(XENLOG_WARNING, "Unsupported delivery mode %d\n",                 delivery_mode);        break;    }}static int iosapic_get_highest_irq(struct viosapic *viosapic){    uint64_t irqs = viosapic->irr & ~viosapic->isr ;       if (irqs)        return ia64_fls(irqs);    return -1;}/* XXX If level interrupt, use vector->irq table for performance */static int get_redir_num(struct viosapic *viosapic, int vector){    int i;    ASSERT(spin_is_locked(&viosapic->lock));    for ( i = 0; i < VIOSAPIC_NUM_PINS; i++ )        if ( viosapic->redirtbl[i].vector == vector )            return i;    return -1;}static void service_iosapic(struct viosapic *viosapic){    int irq;    while ( (irq = iosapic_get_highest_irq(viosapic)) != -1 )    {        if ( viosapic->redirtbl[irq].trig_mode == SAPIC_LEVEL )            viosapic->isr |= (1UL << irq);        viosapic_deliver(viosapic, irq);        viosapic->irr &= ~(1UL << irq);    }}static void viosapic_update_EOI(struct viosapic *viosapic, int vector){    int redir_num;    spin_lock(&viosapic->lock);    if ( (redir_num = get_redir_num(viosapic, vector)) == -1 )    {        spin_unlock(&viosapic->lock);        gdprintk(XENLOG_WARNING, "Can't find redir item for %d EOI\n", vector);        return;    }    if ( !test_and_clear_bit(redir_num, &viosapic->isr) )    {        spin_unlock(&viosapic->lock);        if ( viosapic->redirtbl[redir_num].trig_mode == SAPIC_LEVEL )            gdprintk(XENLOG_WARNING, "redir %d not set for %d EOI\n",                     redir_num, vector);        return;    }    service_iosapic(viosapic);    spin_unlock(&viosapic->lock);}static unsigned long viosapic_read_indirect(struct viosapic *viosapic,                                            unsigned long addr,                                            unsigned long length){    unsigned long result = 0;    switch ( viosapic->ioregsel )    {    case VIOSAPIC_VERSION:        result = ((((VIOSAPIC_NUM_PINS - 1) & 0xff) << 16)                  | (VIOSAPIC_VERSION_ID & 0xff));        break;    default:    {        /* ioregsel might be written at the same time. copy it before use. */        uint32_t ioregsel = viosapic->ioregsel;        uint32_t redir_index;        uint64_t redir_content;        redir_index = (ioregsel - 0x10) >> 1;        if ( redir_index >= VIOSAPIC_NUM_PINS )        {            gdprintk(XENLOG_WARNING, "viosapic_read_indirect:undefined "                     "ioregsel %x\n", ioregsel);            break;        }        redir_content = viosapic->redirtbl[redir_index].bits;        result = (ioregsel & 0x1) ?                 (redir_content >> 32) & 0xffffffff :                 redir_content & 0xffffffff;        break;    }    }    return result;}unsigned long viosapic_read(struct vcpu *v,                            unsigned long addr,                            unsigned long length){    struct viosapic *viosapic = vcpu_viosapic(v);    uint32_t result;    addr &= 0xff;    switch ( addr )    {    case VIOSAPIC_REG_SELECT:        result = viosapic->ioregsel;        break;    case VIOSAPIC_WINDOW:        result = viosapic_read_indirect(viosapic, addr, length);        break;    default:        result = 0;        break;    }    return result;}static void viosapic_write_indirect(struct viosapic *viosapic,                                    unsigned long addr,                                    unsigned long length,                                    unsigned long val){    switch ( viosapic->ioregsel )    {    case VIOSAPIC_VERSION:        /* Writes are ignored. */        break;    default:    {        /* ioregsel might be written at the same time. copy it before use. */        uint32_t ioregsel = viosapic->ioregsel;        uint32_t redir_index;        uint64_t redir_content;        redir_index = (ioregsel - 0x10) >> 1;        if ( redir_index >= VIOSAPIC_NUM_PINS )        {            gdprintk(XENLOG_WARNING, "viosapic_write_indirect "                     "error register %x\n", viosapic->ioregsel);            break;        }        spin_lock(&viosapic->lock);        redir_content = viosapic->redirtbl[redir_index].bits;        if ( ioregsel & 0x1 )        {            redir_content = (((uint64_t)val & 0xffffffff) << 32) |                            (redir_content & 0xffffffff);        }        else        {            redir_content = ((redir_content >> 32) << 32) |                            (val & 0xffffffff);        }        viosapic->redirtbl[redir_index].bits = redir_content;        spin_unlock(&viosapic->lock);        break;    }    } /* switch */}void viosapic_write(struct vcpu *v,                      unsigned long addr,                      unsigned long length,                      unsigned long val){    struct viosapic *viosapic = vcpu_viosapic(v);    addr &= 0xff;    switch ( addr )    {    case VIOSAPIC_REG_SELECT:        viosapic->ioregsel = val;        break;    case VIOSAPIC_WINDOW:        viosapic_write_indirect(viosapic, addr, length, val);        break;    case VIOSAPIC_EOI:        viosapic_update_EOI(viosapic, val);        break;    default:        break;    }}static void viosapic_reset(struct viosapic *viosapic){    int i;    memset(viosapic, 0, sizeof(*viosapic));    for ( i = 0; i < VIOSAPIC_NUM_PINS; i++ )    {        viosapic->redirtbl[i].mask = 0x1;    }    spin_lock_init(&viosapic->lock);}void viosapic_set_irq(struct domain *d, int irq, int level){    struct viosapic *viosapic = domain_viosapic(d);    uint64_t bit;    spin_lock(&viosapic->lock);    if ( (irq < 0) || (irq >= VIOSAPIC_NUM_PINS) )        goto out;    if ( viosapic->redirtbl[irq].mask )        goto out;    bit = 1UL << irq;    if ( viosapic->redirtbl[irq].trig_mode == SAPIC_LEVEL )    {        if ( level )            viosapic->irr |= bit;        else            viosapic->irr &= ~bit;    }    else    {        if ( level )            /* XXX No irr clear for edge interrupt */            viosapic->irr |= bit;    }    service_iosapic(viosapic);out:        spin_unlock(&viosapic->lock);}#define hvm_pci_intx_gsi(dev, intx)  \    (((((dev) << 2) + ((dev) >> 3) + (intx)) & 31) + 16)        void viosapic_set_pci_irq(struct domain *d, int device, int intx, int level){    int irq;    irq = hvm_pci_intx_gsi(device, intx);    viosapic_set_irq(d, irq, level);}void viosapic_init(struct domain *d){    struct viosapic *viosapic = domain_viosapic(d);    viosapic_reset(viosapic);    viosapic->lowest_vcpu = NULL;        viosapic->base_address = VIOSAPIC_DEFAULT_BASE_ADDRESS;}#define VIOSAPIC_INVALID_VCPU_ID (-1UL)static int viosapic_save(struct domain *d, hvm_domain_context_t *h){    struct viosapic *viosapic = domain_viosapic(d);    struct hvm_hw_ia64_viosapic viosapic_save;    int i;    memset(&viosapic_save, 0, sizeof(viosapic_save));        spin_lock(&viosapic->lock);    viosapic_save.irr = viosapic->irr;    viosapic_save.isr = viosapic->isr;    viosapic_save.ioregsel = viosapic->ioregsel;    if (viosapic->lowest_vcpu != NULL)        viosapic_save.lowest_vcpu_id = viosapic->lowest_vcpu->vcpu_id;    else        viosapic_save.lowest_vcpu_id = VIOSAPIC_INVALID_VCPU_ID;    viosapic_save.base_address = viosapic->base_address;    for (i = 0; i < VIOSAPIC_NUM_PINS; i++)        viosapic_save.redirtbl[i] = viosapic->redirtbl[i];    spin_unlock(&viosapic->lock);    return hvm_save_entry(VIOSAPIC, 0, h, &viosapic_save);}static int viosapic_load(struct domain *d, hvm_domain_context_t *h){    struct viosapic *viosapic = domain_viosapic(d);    struct hvm_hw_ia64_viosapic viosapic_load;    struct vcpu *lowest_vcpu;    int i;    if (hvm_load_entry(VIOSAPIC, h, &viosapic_load))        return -EINVAL;    lowest_vcpu = NULL;    if (viosapic_load.lowest_vcpu_id < MAX_VIRT_CPUS)        lowest_vcpu = d->vcpu[viosapic_load.lowest_vcpu_id];    else if (viosapic_load.lowest_vcpu_id != VIOSAPIC_INVALID_VCPU_ID)        return -EINVAL;    if (viosapic_load.base_address != VIOSAPIC_DEFAULT_BASE_ADDRESS)        return -EINVAL;    spin_lock(&viosapic->lock);    viosapic->irr = viosapic_load.irr;    viosapic->isr = viosapic_load.isr;    viosapic->ioregsel = viosapic_load.ioregsel;    viosapic->lowest_vcpu = lowest_vcpu;    viosapic->base_address = viosapic_load.base_address;    for (i = 0; i < VIOSAPIC_NUM_PINS; i++)        viosapic->redirtbl[i] = viosapic_load.redirtbl[i];    service_iosapic(viosapic);//XXX    spin_unlock(&viosapic->lock);    return 0;}HVM_REGISTER_SAVE_RESTORE(VIOSAPIC, viosapic_save, viosapic_load,                          1, HVMSR_PER_DOM);

⌨️ 快捷键说明

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