NetBSD-5.0.2/sys/arch/xen/xen/pci_intr_machdep.c

Compare this file to the similar file:
Show the results in this format:

/*      $NetBSD: pci_intr_machdep.c,v 1.7 2008/07/03 15:44:19 drochner Exp $      */

/*
 * Copyright (c) 2005 Manuel Bouyer.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Manuel Bouyer.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pci_intr_machdep.c,v 1.7 2008/07/03 15:44:19 drochner Exp $");

#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>

#include <machine/bus.h>
#include <machine/bus_private.h>

#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>

#include <xen/evtchn.h>

#include "locators.h"
#include "opt_ddb.h"
#include "ioapic.h"
#include "acpi.h"
#include "opt_mpbios.h"
#include "opt_acpi.h"

#if NIOAPIC > 0
#include <machine/i82093var.h>
#include <machine/mpconfig.h>
#include <machine/pic.h>
#endif

#ifdef MPBIOS
#include <machine/mpbiosvar.h>
#endif

#if NACPI > 0
#include <machine/mpacpi.h>
#endif

int
pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
{
	pcireg_t intr;
	int pin;
	int line;

#if NIOAPIC > 0
	int rawpin = pa->pa_rawintrpin;
	pci_chipset_tag_t pc = pa->pa_pc;
	int bus, dev, func;
#endif

#ifndef XEN3
	physdev_op_t physdev_op;
	/* initialise device, to get the real IRQ */
	physdev_op.cmd = PHYSDEVOP_PCI_INITIALISE_DEVICE;
	physdev_op.u.pci_initialise_device.bus = pa->pa_bus;
	physdev_op.u.pci_initialise_device.dev = pa->pa_device;
	physdev_op.u.pci_initialise_device.func = pa->pa_function;
	if (HYPERVISOR_physdev_op(&physdev_op) < 0)
		panic("HYPERVISOR_physdev_op(PHYSDEVOP_PCI_INITIALISE_DEVICE)");
#endif /* !XEN3 */

	intr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_INTERRUPT_REG);
	pin = pa->pa_intrpin;
	pa->pa_intrline = line = PCI_INTERRUPT_LINE(intr);
#if 0 /* XXXX why is it always 0 ? */
	if (pin == 0) {
		/* No IRQ used */
		goto bad;
	}
#endif
	if (pin > PCI_INTERRUPT_PIN_MAX) {
		printf("pci_intr_map: bad interrupt pin %d\n", pin);
		goto bad;
	}
	ihp->pirq = 0;

#if NIOAPIC > 0
	pci_decompose_tag(pc, pa->pa_tag, &bus, &dev, &func);
	if (mp_busses != NULL) {
		if (intr_find_mpmapping(bus, (dev<<2)|(rawpin-1), ihp) == 0) {
			if ((ihp->pirq & 0xff) == 0)
				ihp->pirq |= line;
			goto end;
		}
		/*
		 * No explicit PCI mapping found. This is not fatal,
		 * we'll try the ISA (or possibly EISA) mappings next.
		 */
	}
#endif

	if (line == 0 || line == X86_PCI_INTERRUPT_LINE_NO_CONNECTION) {
		printf("pci_intr_map: no mapping for pin %c (line=%02x)\n",
		    '@' + pin, line);
		goto bad;
	}
#ifdef XEN3
	if (line >= NUM_LEGACY_IRQS) {
		printf("pci_intr_map: bad interrupt line %d\n", line);
		goto bad;
	}
	if (line == 2) {
		printf("pci_intr_map: changed line 2 to line 9\n");
		line = 9;
	}
#if NIOAPIC > 0
	if (mp_busses != NULL) {
		if (intr_find_mpmapping(mp_isa_bus, line, ihp) == 0) {
			if ((ihp->pirq & 0xff) == 0)
				ihp->pirq |= line;
			goto end;
		}
		printf("pci_intr_map: bus %d dev %d func %d pin %d; line %d\n",
		    bus, dev, func, pin, line);
		printf("pci_intr_map: no MP mapping found\n");
	}
#endif /* NIOAPIC */
#endif /* XEN3 */

	ihp->pirq = line;

#if NIOAPIC > 0
end:
#endif
	ihp->evtch = xen_intr_map(&ihp->pirq, IST_LEVEL);
	if (ihp->evtch == -1)
		goto bad;

	return 0;

bad:
	ihp->pirq = -1;
	ihp->evtch = -1;
	return 1;
}

const char
*pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih)
{
	static char buf[64];
#if NIOAPIC > 0
	struct ioapic_softc *pic;
	if (ih.pirq & APIC_INT_VIA_APIC) {
		pic = ioapic_find(APIC_IRQ_APIC(ih.pirq));
		if (pic == NULL) {
			printf("pci_intr_string: bad ioapic %d\n",
			    APIC_IRQ_APIC(ih.pirq));
			return NULL;
		}
		snprintf(buf, 64, "%s pin %d, event channel %d",
		    device_xname(pic->sc_dev), APIC_IRQ_PIN(ih.pirq),
		    ih.evtch);
		return buf;
	}
#endif
	snprintf(buf, 64, "irq %d, event channel %d",
	    ih.pirq, ih.evtch);
	return buf;
}

const struct evcnt*
pci_intr_evcnt(pci_chipset_tag_t pcitag, pci_intr_handle_t intrh)
{
	return NULL;
}

int
pci_intr_setattr(pci_chipset_tag_t pc, pci_intr_handle_t *ih,
		 int attr, uint64_t data)
{

	switch (attr) {
	case PCI_INTR_MPSAFE:
		return 0;
	default:
		return ENODEV;
	}
}

void *
pci_intr_establish(pci_chipset_tag_t pcitag, pci_intr_handle_t intrh,
    int level, int (*func)(void *), void *arg)
{
	char evname[16];
#if NIOAPIC > 0
	struct ioapic_softc *pic;
	if (intrh.pirq & APIC_INT_VIA_APIC) {
		pic = ioapic_find(APIC_IRQ_APIC(intrh.pirq));
		if (pic == NULL) {
			printf("pci_intr_establish: bad ioapic %d\n",
			    APIC_IRQ_APIC(intrh.pirq));
			return NULL;
		}
		snprintf(evname, sizeof(evname), "%s pin %d",
		    device_xname(pic->sc_dev), APIC_IRQ_PIN(intrh.pirq));
	} else
#endif
		snprintf(evname, sizeof(evname), "irq%d", intrh.pirq);

	return (void *)pirq_establish(intrh.pirq & 0xff,
	    intrh.evtch, func, arg, level, evname);
}

void
pci_intr_disestablish(pci_chipset_tag_t pcitag, void *cookie)
{
}