#include <sys/param.h>

#include <machine/intr_machdep.h>
#include <machine/msi_machdep.h>
#include <machine/msi_var.h>
#include <machine/md_var.h>

#include <machine_base/apic/apicreg.h>
#include <machine_base/apic/lapic.h>

/* MSI address */
#define	MSI_X86_ADDR_DEST		0x000ff000
#define	MSI_X86_ADDR_RH			0x00000008
# define MSI_X86_ADDR_RH_ON		0x00000008
# define MSI_X86_ADDR_RH_OFF		0x00000000
#define	MSI_X86_ADDR_DM			0x00000004
# define MSI_X86_ADDR_DM_PHYSICAL	0x00000000
# define MSI_X86_ADDR_DM_LOGICAL	0x00000004

/* MSI data */
#define	MSI_X86_DATA_TRGRMOD		IOART_TRGRMOD	/* Trigger mode. */
# define MSI_X86_DATA_TRGREDG		IOART_TRGREDG
# define MSI_X86_DATA_TRGRLVL		IOART_TRGRLVL
#define	MSI_X86_DATA_LEVEL		0x00004000	/* Polarity. */
# define MSI_X86_DATA_DEASSERT		0x00000000
# define MSI_X86_DATA_ASSERT		0x00004000
#define	MSI_X86_DATA_DELMOD		IOART_DELMOD	/* Delivery mode. */
# define MSI_X86_DATA_DELFIXED		IOART_DELFIXED
# define MSI_X86_DATA_DELLOPRI		IOART_DELLOPRI
# define MSI_X86_DATA_DELSMI		IOART_DELSMI
# define MSI_X86_DATA_DELNMI		IOART_DELNMI
# define MSI_X86_DATA_DELINIT		IOART_DELINIT
# define MSI_X86_DATA_DELEXINT		IOART_DELEXINT

#define	MSI_X86_ADDR(lapic_id) \
	(MSI_X86_ADDR_BASE | (lapic_id) << 12 | \
	 MSI_X86_ADDR_RH_OFF | MSI_X86_ADDR_DM_PHYSICAL)
#define	MSI_X86_DATA(vector) \
	(MSI_X86_DATA_TRGREDG | MSI_X86_DATA_DELFIXED | (vector))

extern inthand_t
	IDTVEC(msi_intr0),
	IDTVEC(msi_intr1),
	IDTVEC(msi_intr2),
	IDTVEC(msi_intr3),
	IDTVEC(msi_intr4),
	IDTVEC(msi_intr5),
	IDTVEC(msi_intr6),
	IDTVEC(msi_intr7),
	IDTVEC(msi_intr8),
	IDTVEC(msi_intr9),
	IDTVEC(msi_intr10),
	IDTVEC(msi_intr11),
	IDTVEC(msi_intr12),
	IDTVEC(msi_intr13),
	IDTVEC(msi_intr14),
	IDTVEC(msi_intr15),
	IDTVEC(msi_intr16),
	IDTVEC(msi_intr17),
	IDTVEC(msi_intr18),
	IDTVEC(msi_intr19),
	IDTVEC(msi_intr20),
	IDTVEC(msi_intr21),
	IDTVEC(msi_intr22),
	IDTVEC(msi_intr23),
	IDTVEC(msi_intr24),
	IDTVEC(msi_intr25),
	IDTVEC(msi_intr26),
	IDTVEC(msi_intr27),
	IDTVEC(msi_intr28),
	IDTVEC(msi_intr29),
	IDTVEC(msi_intr30),
	IDTVEC(msi_intr31),
	IDTVEC(msi_intr32),
	IDTVEC(msi_intr33),
	IDTVEC(msi_intr34),
	IDTVEC(msi_intr35),
	IDTVEC(msi_intr36),
	IDTVEC(msi_intr37),
	IDTVEC(msi_intr38),
	IDTVEC(msi_intr39),
	IDTVEC(msi_intr40),
	IDTVEC(msi_intr41),
	IDTVEC(msi_intr42),
	IDTVEC(msi_intr43),
	IDTVEC(msi_intr44),
	IDTVEC(msi_intr45),
	IDTVEC(msi_intr46),
	IDTVEC(msi_intr47),
	IDTVEC(msi_intr48),
	IDTVEC(msi_intr49),
	IDTVEC(msi_intr50),
	IDTVEC(msi_intr51),
	IDTVEC(msi_intr52),
	IDTVEC(msi_intr53),
	IDTVEC(msi_intr54),
	IDTVEC(msi_intr55),
	IDTVEC(msi_intr56),
	IDTVEC(msi_intr57),
	IDTVEC(msi_intr58),
	IDTVEC(msi_intr59),
	IDTVEC(msi_intr60),
	IDTVEC(msi_intr61),
	IDTVEC(msi_intr62),
	IDTVEC(msi_intr63),
	IDTVEC(msi_intr64),
	IDTVEC(msi_intr65),
	IDTVEC(msi_intr66),
	IDTVEC(msi_intr67),
	IDTVEC(msi_intr68),
	IDTVEC(msi_intr69),
	IDTVEC(msi_intr70),
	IDTVEC(msi_intr71),
	IDTVEC(msi_intr72),
	IDTVEC(msi_intr73),
	IDTVEC(msi_intr74),
	IDTVEC(msi_intr75),
	IDTVEC(msi_intr76),
	IDTVEC(msi_intr77),
	IDTVEC(msi_intr78),
	IDTVEC(msi_intr79),
	IDTVEC(msi_intr80),
	IDTVEC(msi_intr81),
	IDTVEC(msi_intr82),
	IDTVEC(msi_intr83),
	IDTVEC(msi_intr84),
	IDTVEC(msi_intr85),
	IDTVEC(msi_intr86),
	IDTVEC(msi_intr87),
	IDTVEC(msi_intr88),
	IDTVEC(msi_intr89),
	IDTVEC(msi_intr90),
	IDTVEC(msi_intr91),
	IDTVEC(msi_intr92),
	IDTVEC(msi_intr93),
	IDTVEC(msi_intr94),
	IDTVEC(msi_intr95),
	IDTVEC(msi_intr96),
	IDTVEC(msi_intr97),
	IDTVEC(msi_intr98),
	IDTVEC(msi_intr99),
	IDTVEC(msi_intr100),
	IDTVEC(msi_intr101),
	IDTVEC(msi_intr102),
	IDTVEC(msi_intr103),
	IDTVEC(msi_intr104),
	IDTVEC(msi_intr105),
	IDTVEC(msi_intr106),
	IDTVEC(msi_intr107),
	IDTVEC(msi_intr108),
	IDTVEC(msi_intr109),
	IDTVEC(msi_intr110),
	IDTVEC(msi_intr111),
	IDTVEC(msi_intr112),
	IDTVEC(msi_intr113),
	IDTVEC(msi_intr114),
	IDTVEC(msi_intr115),
	IDTVEC(msi_intr116),
	IDTVEC(msi_intr117),
	IDTVEC(msi_intr118),
	IDTVEC(msi_intr119),
	IDTVEC(msi_intr120),
	IDTVEC(msi_intr121),
	IDTVEC(msi_intr122),
	IDTVEC(msi_intr123),
	IDTVEC(msi_intr124),
	IDTVEC(msi_intr125),
	IDTVEC(msi_intr126),
	IDTVEC(msi_intr127),
	IDTVEC(msi_intr128),
	IDTVEC(msi_intr129),
	IDTVEC(msi_intr130),
	IDTVEC(msi_intr131),
	IDTVEC(msi_intr132),
	IDTVEC(msi_intr133),
	IDTVEC(msi_intr134),
	IDTVEC(msi_intr135),
	IDTVEC(msi_intr136),
	IDTVEC(msi_intr137),
	IDTVEC(msi_intr138),
	IDTVEC(msi_intr139),
	IDTVEC(msi_intr140),
	IDTVEC(msi_intr141),
	IDTVEC(msi_intr142),
	IDTVEC(msi_intr143),
	IDTVEC(msi_intr144),
	IDTVEC(msi_intr145),
	IDTVEC(msi_intr146),
	IDTVEC(msi_intr147),
	IDTVEC(msi_intr148),
	IDTVEC(msi_intr149),
	IDTVEC(msi_intr150),
	IDTVEC(msi_intr151),
	IDTVEC(msi_intr152),
	IDTVEC(msi_intr153),
	IDTVEC(msi_intr154),
	IDTVEC(msi_intr155),
	IDTVEC(msi_intr156),
	IDTVEC(msi_intr157),
	IDTVEC(msi_intr158),
	IDTVEC(msi_intr159),
	IDTVEC(msi_intr160),
	IDTVEC(msi_intr161),
	IDTVEC(msi_intr162),
	IDTVEC(msi_intr163),
	IDTVEC(msi_intr164),
	IDTVEC(msi_intr165),
	IDTVEC(msi_intr166),
	IDTVEC(msi_intr167),
	IDTVEC(msi_intr168),
	IDTVEC(msi_intr169),
	IDTVEC(msi_intr170),
	IDTVEC(msi_intr171),
	IDTVEC(msi_intr172),
	IDTVEC(msi_intr173),
	IDTVEC(msi_intr174),
	IDTVEC(msi_intr175),
	IDTVEC(msi_intr176),
	IDTVEC(msi_intr177),
	IDTVEC(msi_intr178),
	IDTVEC(msi_intr179),
	IDTVEC(msi_intr180),
	IDTVEC(msi_intr181),
	IDTVEC(msi_intr182),
	IDTVEC(msi_intr183),
	IDTVEC(msi_intr184),
	IDTVEC(msi_intr185),
	IDTVEC(msi_intr186),
	IDTVEC(msi_intr187),
	IDTVEC(msi_intr188),
	IDTVEC(msi_intr189),
	IDTVEC(msi_intr190),
	IDTVEC(msi_intr191);

static inthand_t *msi_intr[IDT_HWI_VECTORS] = {
	&IDTVEC(msi_intr0),
	&IDTVEC(msi_intr1),
	&IDTVEC(msi_intr2),
	&IDTVEC(msi_intr3),
	&IDTVEC(msi_intr4),
	&IDTVEC(msi_intr5),
	&IDTVEC(msi_intr6),
	&IDTVEC(msi_intr7),
	&IDTVEC(msi_intr8),
	&IDTVEC(msi_intr9),
	&IDTVEC(msi_intr10),
	&IDTVEC(msi_intr11),
	&IDTVEC(msi_intr12),
	&IDTVEC(msi_intr13),
	&IDTVEC(msi_intr14),
	&IDTVEC(msi_intr15),
	&IDTVEC(msi_intr16),
	&IDTVEC(msi_intr17),
	&IDTVEC(msi_intr18),
	&IDTVEC(msi_intr19),
	&IDTVEC(msi_intr20),
	&IDTVEC(msi_intr21),
	&IDTVEC(msi_intr22),
	&IDTVEC(msi_intr23),
	&IDTVEC(msi_intr24),
	&IDTVEC(msi_intr25),
	&IDTVEC(msi_intr26),
	&IDTVEC(msi_intr27),
	&IDTVEC(msi_intr28),
	&IDTVEC(msi_intr29),
	&IDTVEC(msi_intr30),
	&IDTVEC(msi_intr31),
	&IDTVEC(msi_intr32),
	&IDTVEC(msi_intr33),
	&IDTVEC(msi_intr34),
	&IDTVEC(msi_intr35),
	&IDTVEC(msi_intr36),
	&IDTVEC(msi_intr37),
	&IDTVEC(msi_intr38),
	&IDTVEC(msi_intr39),
	&IDTVEC(msi_intr40),
	&IDTVEC(msi_intr41),
	&IDTVEC(msi_intr42),
	&IDTVEC(msi_intr43),
	&IDTVEC(msi_intr44),
	&IDTVEC(msi_intr45),
	&IDTVEC(msi_intr46),
	&IDTVEC(msi_intr47),
	&IDTVEC(msi_intr48),
	&IDTVEC(msi_intr49),
	&IDTVEC(msi_intr50),
	&IDTVEC(msi_intr51),
	&IDTVEC(msi_intr52),
	&IDTVEC(msi_intr53),
	&IDTVEC(msi_intr54),
	&IDTVEC(msi_intr55),
	&IDTVEC(msi_intr56),
	&IDTVEC(msi_intr57),
	&IDTVEC(msi_intr58),
	&IDTVEC(msi_intr59),
	&IDTVEC(msi_intr60),
	&IDTVEC(msi_intr61),
	&IDTVEC(msi_intr62),
	&IDTVEC(msi_intr63),
	&IDTVEC(msi_intr64),
	&IDTVEC(msi_intr65),
	&IDTVEC(msi_intr66),
	&IDTVEC(msi_intr67),
	&IDTVEC(msi_intr68),
	&IDTVEC(msi_intr69),
	&IDTVEC(msi_intr70),
	&IDTVEC(msi_intr71),
	&IDTVEC(msi_intr72),
	&IDTVEC(msi_intr73),
	&IDTVEC(msi_intr74),
	&IDTVEC(msi_intr75),
	&IDTVEC(msi_intr76),
	&IDTVEC(msi_intr77),
	&IDTVEC(msi_intr78),
	&IDTVEC(msi_intr79),
	&IDTVEC(msi_intr80),
	&IDTVEC(msi_intr81),
	&IDTVEC(msi_intr82),
	&IDTVEC(msi_intr83),
	&IDTVEC(msi_intr84),
	&IDTVEC(msi_intr85),
	&IDTVEC(msi_intr86),
	&IDTVEC(msi_intr87),
	&IDTVEC(msi_intr88),
	&IDTVEC(msi_intr89),
	&IDTVEC(msi_intr90),
	&IDTVEC(msi_intr91),
	&IDTVEC(msi_intr92),
	&IDTVEC(msi_intr93),
	&IDTVEC(msi_intr94),
	&IDTVEC(msi_intr95),
	&IDTVEC(msi_intr96),
	&IDTVEC(msi_intr97),
	&IDTVEC(msi_intr98),
	&IDTVEC(msi_intr99),
	&IDTVEC(msi_intr100),
	&IDTVEC(msi_intr101),
	&IDTVEC(msi_intr102),
	&IDTVEC(msi_intr103),
	&IDTVEC(msi_intr104),
	&IDTVEC(msi_intr105),
	&IDTVEC(msi_intr106),
	&IDTVEC(msi_intr107),
	&IDTVEC(msi_intr108),
	&IDTVEC(msi_intr109),
	&IDTVEC(msi_intr110),
	&IDTVEC(msi_intr111),
	&IDTVEC(msi_intr112),
	&IDTVEC(msi_intr113),
	&IDTVEC(msi_intr114),
	&IDTVEC(msi_intr115),
	&IDTVEC(msi_intr116),
	&IDTVEC(msi_intr117),
	&IDTVEC(msi_intr118),
	&IDTVEC(msi_intr119),
	&IDTVEC(msi_intr120),
	&IDTVEC(msi_intr121),
	&IDTVEC(msi_intr122),
	&IDTVEC(msi_intr123),
	&IDTVEC(msi_intr124),
	&IDTVEC(msi_intr125),
	&IDTVEC(msi_intr126),
	&IDTVEC(msi_intr127),
	&IDTVEC(msi_intr128),
	&IDTVEC(msi_intr129),
	&IDTVEC(msi_intr130),
	&IDTVEC(msi_intr131),
	&IDTVEC(msi_intr132),
	&IDTVEC(msi_intr133),
	&IDTVEC(msi_intr134),
	&IDTVEC(msi_intr135),
	&IDTVEC(msi_intr136),
	&IDTVEC(msi_intr137),
	&IDTVEC(msi_intr138),
	&IDTVEC(msi_intr139),
	&IDTVEC(msi_intr140),
	&IDTVEC(msi_intr141),
	&IDTVEC(msi_intr142),
	&IDTVEC(msi_intr143),
	&IDTVEC(msi_intr144),
	&IDTVEC(msi_intr145),
	&IDTVEC(msi_intr146),
	&IDTVEC(msi_intr147),
	&IDTVEC(msi_intr148),
	&IDTVEC(msi_intr149),
	&IDTVEC(msi_intr150),
	&IDTVEC(msi_intr151),
	&IDTVEC(msi_intr152),
	&IDTVEC(msi_intr153),
	&IDTVEC(msi_intr154),
	&IDTVEC(msi_intr155),
	&IDTVEC(msi_intr156),
	&IDTVEC(msi_intr157),
	&IDTVEC(msi_intr158),
	&IDTVEC(msi_intr159),
	&IDTVEC(msi_intr160),
	&IDTVEC(msi_intr161),
	&IDTVEC(msi_intr162),
	&IDTVEC(msi_intr163),
	&IDTVEC(msi_intr164),
	&IDTVEC(msi_intr165),
	&IDTVEC(msi_intr166),
	&IDTVEC(msi_intr167),
	&IDTVEC(msi_intr168),
	&IDTVEC(msi_intr169),
	&IDTVEC(msi_intr170),
	&IDTVEC(msi_intr171),
	&IDTVEC(msi_intr172),
	&IDTVEC(msi_intr173),
	&IDTVEC(msi_intr174),
	&IDTVEC(msi_intr175),
	&IDTVEC(msi_intr176),
	&IDTVEC(msi_intr177),
	&IDTVEC(msi_intr178),
	&IDTVEC(msi_intr179),
	&IDTVEC(msi_intr180),
	&IDTVEC(msi_intr181),
	&IDTVEC(msi_intr182),
	&IDTVEC(msi_intr183),
	&IDTVEC(msi_intr184),
	&IDTVEC(msi_intr185),
	&IDTVEC(msi_intr186),
	&IDTVEC(msi_intr187),
	&IDTVEC(msi_intr188),
	&IDTVEC(msi_intr189),
	&IDTVEC(msi_intr190),
	&IDTVEC(msi_intr191)
};

void
msi_setup(int intr, int cpuid)
{
	setidt(IDT_OFFSET + intr, msi_intr[intr],
	    SDT_SYSIGT, SEL_KPL, 0, cpuid);
}

void
msi_map(int intr, uint64_t *addr, uint32_t *data, int cpuid)
{
	int vector, lapic_id;

	vector = IDT_OFFSET + intr;
	lapic_id = CPUID_TO_APICID(cpuid);

	*addr = MSI_X86_ADDR(lapic_id);
	*data = MSI_X86_DATA(vector);
}
