Home | History | Annotate | Line # | Download | only in pci
msipic.c revision 1.11.6.1
      1  1.11.6.1  christos /*	$NetBSD: msipic.c,v 1.11.6.1 2019/06/10 22:06:53 christos Exp $	*/
      2       1.1  knakahar 
      3       1.1  knakahar /*
      4       1.1  knakahar  * Copyright (c) 2015 Internet Initiative Japan Inc.
      5       1.1  knakahar  * All rights reserved.
      6       1.1  knakahar  *
      7       1.1  knakahar  * Redistribution and use in source and binary forms, with or without
      8       1.1  knakahar  * modification, are permitted provided that the following conditions
      9       1.1  knakahar  * are met:
     10       1.1  knakahar  * 1. Redistributions of source code must retain the above copyright
     11       1.1  knakahar  *    notice, this list of conditions and the following disclaimer.
     12       1.1  knakahar  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1  knakahar  *    notice, this list of conditions and the following disclaimer in the
     14       1.1  knakahar  *    documentation and/or other materials provided with the distribution.
     15       1.1  knakahar  *
     16       1.1  knakahar  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17       1.1  knakahar  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18       1.1  knakahar  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19       1.1  knakahar  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20       1.1  knakahar  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21       1.1  knakahar  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22       1.1  knakahar  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23       1.1  knakahar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24       1.1  knakahar  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25       1.1  knakahar  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26       1.1  knakahar  * POSSIBILITY OF SUCH DAMAGE.
     27       1.1  knakahar  */
     28       1.1  knakahar 
     29       1.1  knakahar #include <sys/cdefs.h>
     30  1.11.6.1  christos __KERNEL_RCSID(0, "$NetBSD: msipic.c,v 1.11.6.1 2019/06/10 22:06:53 christos Exp $");
     31       1.5   msaitoh 
     32       1.5   msaitoh #include "opt_intrdebug.h"
     33       1.1  knakahar 
     34       1.1  knakahar #include <sys/types.h>
     35       1.1  knakahar #include <sys/param.h>
     36       1.1  knakahar #include <sys/systm.h>
     37       1.1  knakahar #include <sys/errno.h>
     38       1.1  knakahar #include <sys/kmem.h>
     39       1.1  knakahar #include <sys/mutex.h>
     40       1.1  knakahar 
     41       1.1  knakahar #include <dev/pci/pcivar.h>
     42       1.1  knakahar 
     43       1.1  knakahar #include <machine/i82489reg.h>
     44       1.9    nonaka #include <machine/i82489var.h>
     45       1.1  knakahar #include <machine/i82093reg.h>
     46       1.1  knakahar #include <machine/i82093var.h>
     47       1.1  knakahar #include <machine/pic.h>
     48       1.1  knakahar #include <machine/lock.h>
     49       1.1  knakahar 
     50       1.1  knakahar #include <x86/pci/msipic.h>
     51       1.1  knakahar 
     52       1.1  knakahar #ifdef INTRDEBUG
     53       1.1  knakahar #define MSIPICDEBUG
     54       1.1  knakahar #endif
     55       1.1  knakahar 
     56       1.1  knakahar #ifdef MSIPICDEBUG
     57       1.1  knakahar #define DPRINTF(msg) printf msg
     58       1.1  knakahar #else
     59       1.1  knakahar #define DPRINTF(msg)
     60       1.1  knakahar #endif
     61       1.1  knakahar 
     62       1.1  knakahar #define BUS_SPACE_WRITE_FLUSH(pc, tag) (void)bus_space_read_4(pc, tag, 0)
     63       1.1  knakahar 
     64       1.1  knakahar #define MSIPICNAMEBUF 16
     65       1.1  knakahar 
     66       1.1  knakahar /*
     67       1.1  knakahar  * A Pseudo pic for single MSI/MSI-X device.
     68       1.1  knakahar  * The pic and MSI/MSI-X device are distinbuished by "devid". The "devid"
     69       1.1  knakahar  * is managed by below "dev_seqs".
     70       1.1  knakahar  */
     71       1.1  knakahar struct msipic {
     72       1.1  knakahar 	int mp_bus;
     73       1.1  knakahar 	int mp_dev;
     74       1.1  knakahar 	int mp_fun;
     75       1.1  knakahar 
     76       1.1  knakahar 	int mp_devid; /* The device id for the MSI/MSI-X device. */
     77       1.1  knakahar 	int mp_veccnt; /* The number of MSI/MSI-X vectors. */
     78       1.1  knakahar 
     79       1.1  knakahar 	char mp_pic_name[MSIPICNAMEBUF]; /* The MSI/MSI-X device's name. */
     80       1.1  knakahar 
     81       1.1  knakahar 	struct pci_attach_args mp_pa;
     82       1.1  knakahar 	bus_space_tag_t mp_bstag;
     83       1.1  knakahar 	bus_space_handle_t mp_bshandle;
     84       1.1  knakahar 	bus_size_t mp_bssize;
     85       1.1  knakahar 	struct pic *mp_pic;
     86       1.1  knakahar 
     87       1.1  knakahar 	LIST_ENTRY(msipic) mp_list;
     88       1.1  knakahar };
     89       1.1  knakahar 
     90       1.1  knakahar static kmutex_t msipic_list_lock;
     91       1.1  knakahar 
     92       1.1  knakahar static LIST_HEAD(, msipic) msipic_list =
     93       1.1  knakahar 	LIST_HEAD_INITIALIZER(msipic_list);
     94       1.1  knakahar 
     95       1.1  knakahar /*
     96       1.1  knakahar  * This struct managements "devid" to use the same "devid" for the device
     97  1.11.6.1  christos  * re-attached. If the device's bus number and device number and function
     98       1.1  knakahar  * number are equal, it is assumed re-attached.
     99       1.1  knakahar  */
    100       1.1  knakahar struct dev_last_used_seq {
    101       1.1  knakahar 	bool ds_using;
    102       1.1  knakahar 	int ds_bus;
    103       1.1  knakahar 	int ds_dev;
    104       1.1  knakahar 	int ds_fun;
    105       1.1  knakahar };
    106       1.1  knakahar /* The number of MSI/MSI-X devices supported by system. */
    107       1.1  knakahar #define NUM_MSI_DEVS 256
    108       1.1  knakahar /* Record devids to use the same devid when the device is re-attached. */
    109       1.1  knakahar static struct dev_last_used_seq dev_seqs[NUM_MSI_DEVS];
    110       1.1  knakahar 
    111       1.4  knakahar static int msipic_allocate_common_msi_devid(const struct pci_attach_args *);
    112       1.1  knakahar static void msipic_release_common_msi_devid(int);
    113       1.1  knakahar 
    114       1.1  knakahar static struct pic *msipic_find_msi_pic_locked(int);
    115       1.4  knakahar static struct pic *msipic_construct_common_msi_pic(const struct pci_attach_args *,
    116       1.1  knakahar 						   struct pic *);
    117       1.1  knakahar static void msipic_destruct_common_msi_pic(struct pic *);
    118       1.1  knakahar 
    119       1.1  knakahar static void msi_set_msictl_enablebit(struct pic *, int, int);
    120       1.1  knakahar static void msi_hwmask(struct pic *, int);
    121       1.1  knakahar static void msi_hwunmask(struct pic *, int);
    122       1.1  knakahar static void msi_addroute(struct pic *, struct cpu_info *, int, int, int);
    123       1.1  knakahar static void msi_delroute(struct pic *, struct cpu_info *, int, int, int);
    124       1.1  knakahar 
    125       1.1  knakahar static void msix_set_vecctl_mask(struct pic *, int, int);
    126       1.1  knakahar static void msix_hwmask(struct pic *, int);
    127       1.1  knakahar static void msix_hwunmask(struct pic *, int);
    128       1.1  knakahar static void msix_addroute(struct pic *, struct cpu_info *, int, int, int);
    129       1.1  knakahar static void msix_delroute(struct pic *, struct cpu_info *, int, int, int);
    130       1.1  knakahar 
    131       1.1  knakahar /*
    132       1.1  knakahar  * Return new "devid" for the device attached first.
    133       1.1  knakahar  * Return the same "devid" for the device re-attached after dettached once.
    134       1.1  knakahar  * Return -1 if the number of attached MSI/MSI-X devices is over NUM_MSI_DEVS.
    135       1.1  knakahar  */
    136       1.1  knakahar static int
    137       1.4  knakahar msipic_allocate_common_msi_devid(const struct pci_attach_args *pa)
    138       1.1  knakahar {
    139       1.1  knakahar 	pci_chipset_tag_t pc;
    140       1.1  knakahar 	pcitag_t tag;
    141       1.1  knakahar 	int bus, dev, fun, i;
    142       1.1  knakahar 
    143       1.1  knakahar 	KASSERT(mutex_owned(&msipic_list_lock));
    144       1.1  knakahar 
    145       1.1  knakahar 	pc = pa->pa_pc;
    146       1.1  knakahar 	tag = pa->pa_tag;
    147       1.1  knakahar 	pci_decompose_tag(pc, tag, &bus, &dev, &fun);
    148       1.1  knakahar 
    149       1.1  knakahar 	/* if the device was once attached, use same devid */
    150       1.1  knakahar 	for (i = 0; i < NUM_MSI_DEVS; i++) {
    151       1.1  knakahar 		/* skip host bridge */
    152       1.1  knakahar 		if (dev_seqs[i].ds_bus == 0
    153       1.1  knakahar 		    && dev_seqs[i].ds_dev == 0
    154       1.1  knakahar 		    && dev_seqs[i].ds_fun == 0)
    155       1.1  knakahar 			break;
    156       1.1  knakahar 
    157       1.1  knakahar 		if (dev_seqs[i].ds_bus == bus
    158       1.1  knakahar 		    && dev_seqs[i].ds_dev == dev
    159       1.1  knakahar 		    && dev_seqs[i].ds_fun == fun) {
    160       1.1  knakahar 			dev_seqs[i].ds_using = true;
    161       1.1  knakahar 			return i;
    162       1.1  knakahar 		}
    163       1.1  knakahar 	}
    164       1.1  knakahar 
    165       1.1  knakahar 	for (i = 0; i < NUM_MSI_DEVS; i++) {
    166       1.1  knakahar 		if (dev_seqs[i].ds_using == 0) {
    167       1.1  knakahar 			dev_seqs[i].ds_using = true;
    168       1.1  knakahar 			dev_seqs[i].ds_bus = bus;
    169       1.1  knakahar 			dev_seqs[i].ds_dev = dev;
    170       1.1  knakahar 			dev_seqs[i].ds_fun = fun;
    171       1.1  knakahar 			return i;
    172       1.1  knakahar 		}
    173       1.1  knakahar 	}
    174       1.1  knakahar 
    175       1.1  knakahar 	DPRINTF(("too many MSI devices.\n"));
    176       1.1  knakahar 	return -1;
    177       1.1  knakahar }
    178       1.1  knakahar 
    179       1.1  knakahar /*
    180       1.1  knakahar  * Set the "devid" unused, but keep reserving the "devid" to reuse when
    181       1.1  knakahar  * the device is re-attached.
    182       1.1  knakahar  */
    183       1.1  knakahar static void
    184       1.1  knakahar msipic_release_common_msi_devid(int devid)
    185       1.1  knakahar {
    186       1.1  knakahar 
    187       1.1  knakahar 	KASSERT(mutex_owned(&msipic_list_lock));
    188       1.1  knakahar 
    189       1.1  knakahar 	if (devid < 0 || NUM_MSI_DEVS <= devid) {
    190       1.1  knakahar 		DPRINTF(("%s: invalid devid.\n", __func__));
    191       1.1  knakahar 		return;
    192       1.1  knakahar 	}
    193       1.1  knakahar 
    194       1.1  knakahar 	dev_seqs[devid].ds_using = false;
    195       1.1  knakahar 	/* Keep ds_* to reuse the same devid for the same device. */
    196       1.1  knakahar }
    197       1.1  knakahar 
    198       1.1  knakahar static struct pic *
    199       1.1  knakahar msipic_find_msi_pic_locked(int devid)
    200       1.1  knakahar {
    201       1.1  knakahar 	struct msipic *mpp;
    202       1.1  knakahar 
    203       1.1  knakahar 	KASSERT(mutex_owned(&msipic_list_lock));
    204       1.1  knakahar 
    205       1.1  knakahar 	LIST_FOREACH(mpp, &msipic_list, mp_list) {
    206       1.1  knakahar 		if(mpp->mp_devid == devid)
    207       1.1  knakahar 			return mpp->mp_pic;
    208       1.1  knakahar 	}
    209       1.1  knakahar 	return NULL;
    210       1.1  knakahar }
    211       1.1  knakahar 
    212       1.1  knakahar /*
    213       1.1  knakahar  * Return the msi_pic whose device is already registered.
    214       1.1  knakahar  * If the device is not registered yet, return NULL.
    215       1.1  knakahar  */
    216       1.1  knakahar struct pic *
    217       1.1  knakahar msipic_find_msi_pic(int devid)
    218       1.1  knakahar {
    219       1.1  knakahar 	struct pic *msipic;
    220       1.1  knakahar 
    221       1.1  knakahar 	mutex_enter(&msipic_list_lock);
    222       1.1  knakahar 	msipic = msipic_find_msi_pic_locked(devid);
    223       1.1  knakahar 	mutex_exit(&msipic_list_lock);
    224       1.1  knakahar 
    225       1.1  knakahar 	return msipic;
    226       1.1  knakahar }
    227       1.1  knakahar 
    228       1.1  knakahar /*
    229       1.1  knakahar  * A common construct process of MSI and MSI-X.
    230       1.1  knakahar  */
    231       1.1  knakahar static struct pic *
    232       1.4  knakahar msipic_construct_common_msi_pic(const struct pci_attach_args *pa,
    233       1.1  knakahar     struct pic *pic_tmpl)
    234       1.1  knakahar {
    235       1.1  knakahar 	struct pic *pic;
    236       1.1  knakahar 	struct msipic *msipic;
    237       1.1  knakahar 	int devid;
    238       1.1  knakahar 
    239       1.1  knakahar 	pic = kmem_alloc(sizeof(*pic), KM_SLEEP);
    240       1.1  knakahar 	msipic = kmem_zalloc(sizeof(*msipic), KM_SLEEP);
    241       1.1  knakahar 
    242       1.1  knakahar 	mutex_enter(&msipic_list_lock);
    243       1.1  knakahar 
    244       1.1  knakahar 	devid = msipic_allocate_common_msi_devid(pa);
    245       1.1  knakahar 	if (devid == -1) {
    246       1.1  knakahar 		mutex_exit(&msipic_list_lock);
    247       1.1  knakahar 		kmem_free(pic, sizeof(*pic));
    248       1.1  knakahar 		kmem_free(msipic, sizeof(*msipic));
    249       1.1  knakahar 		return NULL;
    250       1.1  knakahar 	}
    251       1.1  knakahar 
    252       1.1  knakahar 	memcpy(pic, pic_tmpl, sizeof(*pic));
    253       1.9    nonaka 	pic->pic_edge_stubs = x2apic_mode ? x2apic_edge_stubs : ioapic_edge_stubs,
    254       1.1  knakahar 	pic->pic_msipic = msipic;
    255       1.1  knakahar 	msipic->mp_pic = pic;
    256       1.1  knakahar 	pci_decompose_tag(pa->pa_pc, pa->pa_tag,
    257       1.1  knakahar 	    &msipic->mp_bus, &msipic->mp_dev, &msipic->mp_fun);
    258       1.1  knakahar 	memcpy(&msipic->mp_pa, pa, sizeof(msipic->mp_pa));
    259       1.1  knakahar 	msipic->mp_devid = devid;
    260       1.1  knakahar 	/*
    261       1.1  knakahar 	 * pci_msi{,x}_alloc() must be called only once in the device driver.
    262       1.1  knakahar 	 */
    263       1.1  knakahar 	KASSERT(msipic_find_msi_pic_locked(msipic->mp_devid) == NULL);
    264       1.1  knakahar 
    265       1.1  knakahar 	LIST_INSERT_HEAD(&msipic_list, msipic, mp_list);
    266       1.1  knakahar 
    267       1.1  knakahar 	mutex_exit(&msipic_list_lock);
    268       1.1  knakahar 
    269       1.1  knakahar 	return pic;
    270       1.1  knakahar }
    271       1.1  knakahar 
    272       1.1  knakahar static void
    273       1.1  knakahar msipic_destruct_common_msi_pic(struct pic *msi_pic)
    274       1.1  knakahar {
    275       1.1  knakahar 	struct msipic *msipic;
    276       1.1  knakahar 
    277       1.1  knakahar 	if (msi_pic == NULL)
    278       1.1  knakahar 		return;
    279       1.1  knakahar 
    280       1.1  knakahar 	msipic = msi_pic->pic_msipic;
    281       1.1  knakahar 	mutex_enter(&msipic_list_lock);
    282       1.1  knakahar 	LIST_REMOVE(msipic, mp_list);
    283       1.1  knakahar 	msipic_release_common_msi_devid(msipic->mp_devid);
    284       1.1  knakahar 	mutex_exit(&msipic_list_lock);
    285       1.1  knakahar 
    286       1.1  knakahar 	kmem_free(msipic, sizeof(*msipic));
    287       1.1  knakahar 	kmem_free(msi_pic, sizeof(*msi_pic));
    288       1.1  knakahar }
    289       1.1  knakahar 
    290       1.1  knakahar /*
    291       1.1  knakahar  * The pic is MSI/MSI-X pic or not.
    292       1.1  knakahar  */
    293       1.1  knakahar bool
    294       1.1  knakahar msipic_is_msi_pic(struct pic *pic)
    295       1.1  knakahar {
    296       1.1  knakahar 
    297       1.1  knakahar 	return (pic->pic_msipic != NULL);
    298       1.1  knakahar }
    299       1.1  knakahar 
    300       1.1  knakahar /*
    301       1.1  knakahar  * Return the MSI/MSI-X devid which is unique for each devices.
    302       1.1  knakahar  */
    303       1.1  knakahar int
    304       1.1  knakahar msipic_get_devid(struct pic *pic)
    305       1.1  knakahar {
    306       1.1  knakahar 
    307       1.1  knakahar 	KASSERT(msipic_is_msi_pic(pic));
    308       1.1  knakahar 
    309       1.1  knakahar 	return pic->pic_msipic->mp_devid;
    310       1.1  knakahar }
    311       1.1  knakahar 
    312       1.1  knakahar #define MSI_MSICTL_ENABLE 1
    313       1.1  knakahar #define MSI_MSICTL_DISABLE 0
    314       1.1  knakahar static void
    315       1.1  knakahar msi_set_msictl_enablebit(struct pic *pic, int msi_vec, int flag)
    316       1.1  knakahar {
    317       1.1  knakahar 	pci_chipset_tag_t pc;
    318       1.1  knakahar 	struct pci_attach_args *pa;
    319       1.1  knakahar 	pcitag_t tag;
    320       1.1  knakahar 	pcireg_t ctl;
    321       1.3    martin 	int off, err __diagused;
    322       1.1  knakahar 
    323       1.1  knakahar 	pc = NULL;
    324       1.1  knakahar 	pa = &pic->pic_msipic->mp_pa;
    325       1.1  knakahar 	tag = pa->pa_tag;
    326       1.3    martin 	err = pci_get_capability(pc, tag, PCI_CAP_MSI, &off, NULL);
    327       1.3    martin 	KASSERT(err != 0);
    328       1.1  knakahar 
    329       1.1  knakahar 	/*
    330       1.1  knakahar 	 * MSI can establish only one vector at once.
    331       1.1  knakahar 	 * So, use whole device mask bit instead of a vector mask bit.
    332       1.1  knakahar 	 */
    333       1.1  knakahar 	ctl = pci_conf_read(pc, tag, off + PCI_MSI_CTL);
    334       1.1  knakahar 	if (flag == MSI_MSICTL_ENABLE)
    335       1.1  knakahar 		ctl |= PCI_MSI_CTL_MSI_ENABLE;
    336       1.1  knakahar 	else
    337       1.1  knakahar 		ctl &= ~PCI_MSI_CTL_MSI_ENABLE;
    338       1.1  knakahar 
    339       1.1  knakahar 	pci_conf_write(pc, tag, off, ctl);
    340       1.1  knakahar }
    341       1.1  knakahar 
    342       1.1  knakahar static void
    343       1.1  knakahar msi_hwmask(struct pic *pic, int msi_vec)
    344       1.1  knakahar {
    345       1.1  knakahar 
    346       1.1  knakahar 	msi_set_msictl_enablebit(pic, msi_vec, MSI_MSICTL_DISABLE);
    347       1.1  knakahar }
    348       1.1  knakahar 
    349       1.1  knakahar /*
    350       1.1  knakahar  * Do not use pic->hwunmask() immediately after pic->delroute().
    351       1.1  knakahar  * It is required to use pic->addroute() before pic->hwunmask().
    352       1.1  knakahar  */
    353       1.1  knakahar static void
    354       1.1  knakahar msi_hwunmask(struct pic *pic, int msi_vec)
    355       1.1  knakahar {
    356       1.1  knakahar 
    357       1.1  knakahar 	msi_set_msictl_enablebit(pic, msi_vec, MSI_MSICTL_ENABLE);
    358       1.1  knakahar }
    359       1.1  knakahar 
    360       1.1  knakahar static void
    361       1.1  knakahar msi_addroute(struct pic *pic, struct cpu_info *ci,
    362       1.1  knakahar 	     int unused, int idt_vec, int type)
    363       1.1  knakahar {
    364       1.1  knakahar 	pci_chipset_tag_t pc;
    365       1.1  knakahar 	struct pci_attach_args *pa;
    366       1.1  knakahar 	pcitag_t tag;
    367       1.1  knakahar 	pcireg_t addr, data, ctl;
    368       1.3    martin 	int off, err __diagused;
    369       1.1  knakahar 
    370       1.1  knakahar 	pc = NULL;
    371       1.1  knakahar 	pa = &pic->pic_msipic->mp_pa;
    372       1.1  knakahar 	tag = pa->pa_tag;
    373       1.3    martin 	err = pci_get_capability(pc, tag, PCI_CAP_MSI, &off, NULL);
    374       1.3    martin 	KASSERT(err != 0);
    375       1.1  knakahar 
    376       1.1  knakahar 	/*
    377       1.1  knakahar 	 * See Intel 64 and IA-32 Architectures Software Developer's Manual
    378       1.1  knakahar 	 * Volume 3 10.11 Message Signalled Interrupts.
    379       1.1  knakahar 	 */
    380       1.1  knakahar 	/*
    381       1.1  knakahar 	 * "cpuid" for MSI address is local APIC ID. In NetBSD, the ID is
    382       1.1  knakahar 	 * the same as ci->ci_cpuid.
    383       1.1  knakahar 	 */
    384       1.1  knakahar 	addr = LAPIC_MSIADDR_BASE | __SHIFTIN(ci->ci_cpuid,
    385       1.1  knakahar 	    LAPIC_MSIADDR_DSTID_MASK);
    386       1.1  knakahar 	/* If trigger mode is edge, it don't care level for trigger mode. */
    387       1.1  knakahar 	data = __SHIFTIN(idt_vec, LAPIC_MSIDATA_VECTOR_MASK)
    388       1.1  knakahar 		| LAPIC_MSIDATA_TRGMODE_EDGE | LAPIC_MSIDATA_DM_FIXED;
    389       1.1  knakahar 
    390       1.1  knakahar 	ctl = pci_conf_read(pc, tag, off + PCI_MSI_CTL);
    391       1.1  knakahar 	if (ctl & PCI_MSI_CTL_64BIT_ADDR) {
    392       1.1  knakahar 		pci_conf_write(pc, tag, off + PCI_MSI_MADDR64_LO, addr);
    393       1.1  knakahar 		pci_conf_write(pc, tag, off + PCI_MSI_MADDR64_HI, 0);
    394       1.1  knakahar 		pci_conf_write(pc, tag, off + PCI_MSI_MDATA64, data);
    395       1.1  knakahar 	} else {
    396       1.1  knakahar 		pci_conf_write(pc, tag, off + PCI_MSI_MADDR, addr);
    397       1.1  knakahar 		pci_conf_write(pc, tag, off + PCI_MSI_MDATA, data);
    398       1.1  knakahar 	}
    399       1.1  knakahar 	ctl |= PCI_MSI_CTL_MSI_ENABLE;
    400       1.1  knakahar 	pci_conf_write(pc, tag, off + PCI_MSI_CTL, ctl);
    401       1.1  knakahar }
    402       1.1  knakahar 
    403       1.1  knakahar /*
    404       1.1  knakahar  * Do not use pic->hwunmask() immediately after pic->delroute().
    405       1.1  knakahar  * It is required to use pic->addroute() before pic->hwunmask().
    406       1.1  knakahar  */
    407       1.1  knakahar static void
    408       1.1  knakahar msi_delroute(struct pic *pic, struct cpu_info *ci,
    409       1.1  knakahar 	     int msi_vec, int idt_vec, int type)
    410       1.1  knakahar {
    411       1.1  knakahar 
    412       1.1  knakahar 	msi_hwmask(pic, msi_vec);
    413       1.1  knakahar }
    414       1.1  knakahar 
    415       1.1  knakahar /*
    416       1.1  knakahar  * Template for MSI pic.
    417       1.1  knakahar  * .pic_msipic is set later in construct_msi_pic().
    418       1.1  knakahar  */
    419       1.1  knakahar static struct pic msi_pic_tmpl = {
    420       1.1  knakahar 	.pic_type = PIC_MSI,
    421       1.1  knakahar 	.pic_vecbase = 0,
    422       1.1  knakahar 	.pic_apicid = 0,
    423       1.1  knakahar 	.pic_lock = __SIMPLELOCK_UNLOCKED, /* not used for msi_pic */
    424       1.1  knakahar 	.pic_hwmask = msi_hwmask,
    425       1.1  knakahar 	.pic_hwunmask = msi_hwunmask,
    426       1.1  knakahar 	.pic_addroute = msi_addroute,
    427       1.1  knakahar 	.pic_delroute = msi_delroute,
    428       1.1  knakahar };
    429       1.1  knakahar 
    430       1.1  knakahar /*
    431       1.1  knakahar  * Create pseudo pic for a MSI device.
    432       1.1  knakahar  */
    433       1.1  knakahar struct pic *
    434       1.4  knakahar msipic_construct_msi_pic(const struct pci_attach_args *pa)
    435       1.1  knakahar {
    436       1.1  knakahar 	struct pic *msi_pic;
    437       1.1  knakahar 	char pic_name_buf[MSIPICNAMEBUF];
    438       1.1  knakahar 
    439       1.1  knakahar 	msi_pic = msipic_construct_common_msi_pic(pa, &msi_pic_tmpl);
    440       1.1  knakahar 	if (msi_pic == NULL) {
    441       1.1  knakahar 		DPRINTF(("cannot allocate MSI pic.\n"));
    442       1.1  knakahar 		return NULL;
    443       1.1  knakahar 	}
    444       1.1  knakahar 
    445       1.1  knakahar 	memset(pic_name_buf, 0, MSIPICNAMEBUF);
    446       1.1  knakahar 	snprintf(pic_name_buf, MSIPICNAMEBUF, "msi%d",
    447       1.1  knakahar 	    msi_pic->pic_msipic->mp_devid);
    448       1.1  knakahar 	strncpy(msi_pic->pic_msipic->mp_pic_name, pic_name_buf,
    449       1.1  knakahar 	    MSIPICNAMEBUF - 1);
    450       1.1  knakahar 	msi_pic->pic_name = msi_pic->pic_msipic->mp_pic_name;
    451       1.1  knakahar 
    452       1.1  knakahar 	return msi_pic;
    453       1.1  knakahar }
    454       1.1  knakahar 
    455       1.1  knakahar /*
    456       1.1  knakahar  * Delete pseudo pic for a MSI device.
    457       1.1  knakahar  */
    458       1.1  knakahar void
    459       1.1  knakahar msipic_destruct_msi_pic(struct pic *msi_pic)
    460       1.1  knakahar {
    461       1.1  knakahar 
    462       1.1  knakahar 	msipic_destruct_common_msi_pic(msi_pic);
    463       1.1  knakahar }
    464       1.1  knakahar 
    465       1.1  knakahar #define MSIX_VECCTL_HWMASK 1
    466       1.1  knakahar #define MSIX_VECCTL_HWUNMASK 0
    467       1.1  knakahar static void
    468       1.1  knakahar msix_set_vecctl_mask(struct pic *pic, int msix_vec, int flag)
    469       1.1  knakahar {
    470       1.1  knakahar 	bus_space_tag_t bstag;
    471       1.1  knakahar 	bus_space_handle_t bshandle;
    472       1.1  knakahar 	uint64_t entry_base;
    473       1.1  knakahar 	uint32_t vecctl;
    474       1.1  knakahar 
    475       1.1  knakahar 	if (msix_vec < 0) {
    476       1.1  knakahar 		DPRINTF(("%s: invalid MSI-X table index, devid=%d vecid=%d",
    477       1.2  knakahar 			__func__, msipic_get_devid(pic), msix_vec));
    478       1.1  knakahar 		return;
    479       1.1  knakahar 	}
    480       1.1  knakahar 
    481       1.1  knakahar 	entry_base = PCI_MSIX_TABLE_ENTRY_SIZE * msix_vec;
    482       1.1  knakahar 
    483       1.1  knakahar 	bstag = pic->pic_msipic->mp_bstag;
    484       1.1  knakahar 	bshandle = pic->pic_msipic->mp_bshandle;
    485       1.1  knakahar 	vecctl = bus_space_read_4(bstag, bshandle,
    486       1.1  knakahar 	    entry_base + PCI_MSIX_TABLE_ENTRY_VECTCTL);
    487       1.1  knakahar 	if (flag == MSIX_VECCTL_HWMASK)
    488       1.8   msaitoh 		vecctl |= PCI_MSIX_VECTCTL_MASK;
    489       1.1  knakahar 	else
    490       1.8   msaitoh 		vecctl &= ~PCI_MSIX_VECTCTL_MASK;
    491       1.1  knakahar 
    492       1.1  knakahar 	bus_space_write_4(bstag, bshandle,
    493       1.1  knakahar 	    entry_base + PCI_MSIX_TABLE_ENTRY_VECTCTL, vecctl);
    494       1.1  knakahar 	BUS_SPACE_WRITE_FLUSH(bstag, bshandle);
    495       1.1  knakahar }
    496       1.1  knakahar 
    497       1.1  knakahar static void
    498       1.1  knakahar msix_hwmask(struct pic *pic, int msix_vec)
    499       1.1  knakahar {
    500       1.1  knakahar 
    501       1.1  knakahar 	msix_set_vecctl_mask(pic, msix_vec, MSIX_VECCTL_HWMASK);
    502       1.1  knakahar }
    503       1.1  knakahar 
    504       1.1  knakahar /*
    505       1.1  knakahar  * Do not use pic->hwunmask() immediately after pic->delroute().
    506       1.1  knakahar  * It is required to use pic->addroute() before pic->hwunmask().
    507       1.1  knakahar  */
    508       1.1  knakahar static void
    509       1.1  knakahar msix_hwunmask(struct pic *pic, int msix_vec)
    510       1.1  knakahar {
    511       1.1  knakahar 
    512       1.1  knakahar 	msix_set_vecctl_mask(pic, msix_vec, MSIX_VECCTL_HWUNMASK);
    513       1.1  knakahar }
    514       1.1  knakahar 
    515       1.1  knakahar static void
    516       1.1  knakahar msix_addroute(struct pic *pic, struct cpu_info *ci,
    517       1.1  knakahar 	     int msix_vec, int idt_vec, int type)
    518       1.1  knakahar {
    519       1.1  knakahar 	pci_chipset_tag_t pc;
    520       1.1  knakahar 	struct pci_attach_args *pa;
    521       1.1  knakahar 	pcitag_t tag;
    522       1.1  knakahar 	bus_space_tag_t bstag;
    523       1.1  knakahar 	bus_space_handle_t bshandle;
    524       1.1  knakahar 	uint64_t entry_base;
    525       1.1  knakahar 	pcireg_t addr, data, ctl;
    526       1.3    martin 	int off, err __diagused;
    527       1.1  knakahar 
    528       1.1  knakahar 	if (msix_vec < 0) {
    529       1.1  knakahar 		DPRINTF(("%s: invalid MSI-X table index, devid=%d vecid=%d",
    530       1.2  knakahar 			__func__, msipic_get_devid(pic), msix_vec));
    531       1.1  knakahar 		return;
    532       1.1  knakahar 	}
    533       1.1  knakahar 
    534       1.1  knakahar 	pa = &pic->pic_msipic->mp_pa;
    535       1.1  knakahar 	pc = pa->pa_pc;
    536       1.1  knakahar 	tag = pa->pa_tag;
    537       1.3    martin 	err = pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, NULL);
    538       1.3    martin 	KASSERT(err != 0);
    539       1.1  knakahar 
    540       1.1  knakahar 	entry_base = PCI_MSIX_TABLE_ENTRY_SIZE * msix_vec;
    541       1.1  knakahar 
    542       1.1  knakahar 	/*
    543       1.1  knakahar 	 * See Intel 64 and IA-32 Architectures Software Developer's Manual
    544       1.1  knakahar 	 * Volume 3 10.11 Message Signalled Interrupts.
    545       1.1  knakahar 	 */
    546       1.1  knakahar 	/*
    547       1.1  knakahar 	 * "cpuid" for MSI-X address is local APIC ID. In NetBSD, the ID is
    548       1.1  knakahar 	 * the same as ci->ci_cpuid.
    549       1.1  knakahar 	 */
    550       1.1  knakahar 	addr = LAPIC_MSIADDR_BASE | __SHIFTIN(ci->ci_cpuid,
    551       1.1  knakahar 	    LAPIC_MSIADDR_DSTID_MASK);
    552       1.1  knakahar 	/* If trigger mode is edge, it don't care level for trigger mode. */
    553       1.1  knakahar 	data = __SHIFTIN(idt_vec, LAPIC_MSIDATA_VECTOR_MASK)
    554       1.1  knakahar 		| LAPIC_MSIDATA_TRGMODE_EDGE | LAPIC_MSIDATA_DM_FIXED;
    555       1.1  knakahar 
    556       1.1  knakahar 	bstag = pic->pic_msipic->mp_bstag;
    557       1.1  knakahar 	bshandle = pic->pic_msipic->mp_bshandle;
    558       1.1  knakahar 	bus_space_write_4(bstag, bshandle,
    559       1.1  knakahar 	    entry_base + PCI_MSIX_TABLE_ENTRY_ADDR_LO, addr);
    560       1.1  knakahar 	bus_space_write_4(bstag, bshandle,
    561       1.1  knakahar 	    entry_base + PCI_MSIX_TABLE_ENTRY_ADDR_HI, 0);
    562       1.1  knakahar 	bus_space_write_4(bstag, bshandle,
    563       1.1  knakahar 	    entry_base + PCI_MSIX_TABLE_ENTRY_DATA, data);
    564       1.1  knakahar 	bus_space_write_4(bstag, bshandle,
    565       1.1  knakahar 	    entry_base + PCI_MSIX_TABLE_ENTRY_VECTCTL, 0);
    566       1.1  knakahar 	BUS_SPACE_WRITE_FLUSH(bstag, bshandle);
    567       1.1  knakahar 
    568       1.1  knakahar 	ctl = pci_conf_read(pc, tag, off + PCI_MSIX_CTL);
    569       1.1  knakahar 	ctl |= PCI_MSIX_CTL_ENABLE;
    570       1.1  knakahar 	pci_conf_write(pc, tag, off + PCI_MSIX_CTL, ctl);
    571       1.1  knakahar }
    572       1.1  knakahar 
    573       1.1  knakahar /*
    574       1.1  knakahar  * Do not use pic->hwunmask() immediately after pic->delroute().
    575       1.1  knakahar  * It is required to use pic->addroute() before pic->hwunmask().
    576       1.1  knakahar  */
    577       1.1  knakahar static void
    578       1.1  knakahar msix_delroute(struct pic *pic, struct cpu_info *ci,
    579       1.1  knakahar 	     int msix_vec, int vec, int type)
    580       1.1  knakahar {
    581       1.1  knakahar 
    582       1.1  knakahar 	msix_hwmask(pic, msix_vec);
    583       1.1  knakahar }
    584       1.1  knakahar 
    585       1.1  knakahar /*
    586       1.1  knakahar  * Template for MSI-X pic.
    587       1.1  knakahar  * .pic_msipic is set later in construct_msix_pic().
    588       1.1  knakahar  */
    589       1.1  knakahar static struct pic msix_pic_tmpl = {
    590       1.1  knakahar 	.pic_type = PIC_MSIX,
    591       1.1  knakahar 	.pic_vecbase = 0,
    592       1.1  knakahar 	.pic_apicid = 0,
    593       1.1  knakahar 	.pic_lock = __SIMPLELOCK_UNLOCKED, /* not used for msix_pic */
    594       1.1  knakahar 	.pic_hwmask = msix_hwmask,
    595       1.1  knakahar 	.pic_hwunmask = msix_hwunmask,
    596       1.1  knakahar 	.pic_addroute = msix_addroute,
    597       1.1  knakahar 	.pic_delroute = msix_delroute,
    598       1.1  knakahar };
    599       1.1  knakahar 
    600       1.1  knakahar struct pic *
    601       1.4  knakahar msipic_construct_msix_pic(const struct pci_attach_args *pa)
    602       1.1  knakahar {
    603       1.1  knakahar 	struct pic *msix_pic;
    604       1.1  knakahar 	pci_chipset_tag_t pc;
    605       1.1  knakahar 	pcitag_t tag;
    606       1.1  knakahar 	pcireg_t tbl;
    607       1.1  knakahar 	bus_space_tag_t bstag;
    608       1.1  knakahar 	bus_space_handle_t bshandle;
    609       1.1  knakahar 	bus_size_t bssize;
    610       1.1  knakahar 	size_t table_size;
    611       1.1  knakahar 	uint32_t table_offset;
    612       1.1  knakahar 	u_int memtype;
    613       1.7   msaitoh 	bus_addr_t memaddr;
    614       1.7   msaitoh 	int flags;
    615       1.1  knakahar 	int bir, bar, err, off, table_nentry;
    616       1.1  knakahar 	char pic_name_buf[MSIPICNAMEBUF];
    617       1.1  knakahar 
    618       1.6   msaitoh 	table_nentry = pci_msix_count(pa->pa_pc, pa->pa_tag);
    619       1.1  knakahar 	if (table_nentry == 0) {
    620       1.1  knakahar 		DPRINTF(("MSI-X table entry is 0.\n"));
    621       1.1  knakahar 		return NULL;
    622       1.1  knakahar 	}
    623       1.1  knakahar 
    624       1.1  knakahar 	pc = pa->pa_pc;
    625       1.1  knakahar 	tag = pa->pa_tag;
    626       1.1  knakahar 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, NULL) == 0) {
    627       1.1  knakahar 		DPRINTF(("%s: no msix capability", __func__));
    628       1.1  knakahar 		return NULL;
    629       1.1  knakahar 	}
    630       1.1  knakahar 
    631       1.1  knakahar 	msix_pic = msipic_construct_common_msi_pic(pa, &msix_pic_tmpl);
    632       1.1  knakahar 	if (msix_pic == NULL) {
    633       1.1  knakahar 		DPRINTF(("cannot allocate MSI-X pic.\n"));
    634       1.1  knakahar 		return NULL;
    635       1.1  knakahar 	}
    636       1.1  knakahar 
    637       1.1  knakahar 	memset(pic_name_buf, 0, MSIPICNAMEBUF);
    638       1.1  knakahar 	snprintf(pic_name_buf, MSIPICNAMEBUF, "msix%d",
    639       1.1  knakahar 	    msix_pic->pic_msipic->mp_devid);
    640       1.1  knakahar 	strncpy(msix_pic->pic_msipic->mp_pic_name, pic_name_buf,
    641       1.1  knakahar 	    MSIPICNAMEBUF - 1);
    642       1.1  knakahar 	msix_pic->pic_name = msix_pic->pic_msipic->mp_pic_name;
    643       1.1  knakahar 
    644       1.1  knakahar 	tbl = pci_conf_read(pc, tag, off + PCI_MSIX_TBLOFFSET);
    645       1.1  knakahar 	table_offset = tbl & PCI_MSIX_TBLOFFSET_MASK;
    646       1.1  knakahar 	bir = tbl & PCI_MSIX_PBABIR_MASK;
    647       1.1  knakahar 	switch(bir) {
    648       1.1  knakahar 	case 0:
    649       1.1  knakahar 		bar = PCI_BAR0;
    650       1.1  knakahar 		break;
    651       1.1  knakahar 	case 1:
    652       1.1  knakahar 		bar = PCI_BAR1;
    653       1.1  knakahar 		break;
    654       1.1  knakahar 	case 2:
    655       1.1  knakahar 		bar = PCI_BAR2;
    656       1.1  knakahar 		break;
    657       1.1  knakahar 	case 3:
    658       1.1  knakahar 		bar = PCI_BAR3;
    659       1.1  knakahar 		break;
    660       1.1  knakahar 	case 4:
    661       1.1  knakahar 		bar = PCI_BAR4;
    662       1.1  knakahar 		break;
    663       1.1  knakahar 	case 5:
    664       1.1  knakahar 		bar = PCI_BAR5;
    665       1.1  knakahar 		break;
    666       1.1  knakahar 	default:
    667       1.1  knakahar 		aprint_error("detect an illegal device! The device use reserved BIR values.\n");
    668       1.1  knakahar 		msipic_destruct_common_msi_pic(msix_pic);
    669       1.1  knakahar 		return NULL;
    670       1.1  knakahar 	}
    671       1.1  knakahar 	memtype = pci_mapreg_type(pc, tag, bar);
    672       1.1  knakahar 	 /*
    673       1.1  knakahar 	  * PCI_MSIX_TABLE_ENTRY_SIZE consists below
    674       1.1  knakahar 	  *     - Vector Control (32bit)
    675       1.1  knakahar 	  *     - Message Data (32bit)
    676       1.1  knakahar 	  *     - Message Upper Address (32bit)
    677       1.1  knakahar 	  *     - Message Lower Address (32bit)
    678       1.1  knakahar 	  */
    679       1.1  knakahar 	table_size = table_nentry * PCI_MSIX_TABLE_ENTRY_SIZE;
    680       1.7   msaitoh #if 0
    681       1.1  knakahar 	err = pci_mapreg_submap(pa, bar, memtype, BUS_SPACE_MAP_LINEAR,
    682       1.1  knakahar 	    roundup(table_size, PAGE_SIZE), table_offset,
    683       1.1  knakahar 	    &bstag, &bshandle, NULL, &bssize);
    684       1.7   msaitoh #else
    685       1.7   msaitoh 	/*
    686       1.7   msaitoh 	 * Workaround for PCI prefetchable bit. Some chips (e.g. Intel 82599)
    687       1.7   msaitoh 	 * report SERR and MSI-X doesn't work. This problem might not be the
    688       1.7   msaitoh 	 * driver's bug but our PCI common part or VMs' bug. Until we find a
    689       1.7   msaitoh 	 * real reason, we ignore the prefetchable bit.
    690       1.7   msaitoh 	 */
    691       1.7   msaitoh 	if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, bar, memtype,
    692       1.7   msaitoh 		&memaddr, NULL, &flags) != 0) {
    693       1.7   msaitoh 		DPRINTF(("cannot get a map info.\n"));
    694       1.7   msaitoh 		msipic_destruct_common_msi_pic(msix_pic);
    695       1.7   msaitoh 		return NULL;
    696       1.7   msaitoh 	}
    697       1.7   msaitoh 	if ((flags & BUS_SPACE_MAP_PREFETCHABLE) != 0) {
    698       1.7   msaitoh 		DPRINTF(( "clear prefetchable bit\n"));
    699       1.7   msaitoh 		flags &= ~BUS_SPACE_MAP_PREFETCHABLE;
    700       1.7   msaitoh 	}
    701       1.7   msaitoh 	bssize = roundup(table_size, PAGE_SIZE);
    702       1.7   msaitoh 	err = bus_space_map(pa->pa_memt, memaddr + table_offset, bssize, flags,
    703       1.7   msaitoh 	    &bshandle);
    704       1.7   msaitoh 	bstag = pa->pa_memt;
    705       1.7   msaitoh #endif
    706       1.1  knakahar 	if (err) {
    707       1.1  knakahar 		DPRINTF(("cannot map msix table.\n"));
    708       1.1  knakahar 		msipic_destruct_common_msi_pic(msix_pic);
    709       1.1  knakahar 		return NULL;
    710       1.1  knakahar 	}
    711       1.1  knakahar 	msix_pic->pic_msipic->mp_bstag = bstag;
    712       1.1  knakahar 	msix_pic->pic_msipic->mp_bshandle = bshandle;
    713       1.1  knakahar 	msix_pic->pic_msipic->mp_bssize = bssize;
    714       1.1  knakahar 
    715       1.1  knakahar 	return msix_pic;
    716       1.1  knakahar }
    717       1.1  knakahar 
    718       1.1  knakahar /*
    719       1.1  knakahar  * Delete pseudo pic for a MSI-X device.
    720       1.1  knakahar  */
    721       1.1  knakahar void
    722       1.1  knakahar msipic_destruct_msix_pic(struct pic *msix_pic)
    723       1.1  knakahar {
    724       1.1  knakahar 	struct msipic *msipic;
    725       1.1  knakahar 
    726       1.1  knakahar 	KASSERT(msipic_is_msi_pic(msix_pic));
    727       1.1  knakahar 	KASSERT(msix_pic->pic_type == PIC_MSIX);
    728       1.1  knakahar 
    729       1.1  knakahar 	msipic = msix_pic->pic_msipic;
    730       1.1  knakahar 	bus_space_unmap(msipic->mp_bstag, msipic->mp_bshandle,
    731       1.1  knakahar 	    msipic->mp_bssize);
    732       1.1  knakahar 
    733       1.1  knakahar 	msipic_destruct_common_msi_pic(msix_pic);
    734       1.1  knakahar }
    735       1.1  knakahar 
    736       1.1  knakahar /*
    737       1.1  knakahar  * Set the number of MSI vectors for pseudo MSI pic.
    738       1.1  knakahar  */
    739       1.1  knakahar int
    740       1.1  knakahar msipic_set_msi_vectors(struct pic *msi_pic, pci_intr_handle_t *pihs,
    741       1.1  knakahar     int count)
    742       1.1  knakahar {
    743       1.1  knakahar 
    744       1.1  knakahar 	KASSERT(msipic_is_msi_pic(msi_pic));
    745       1.1  knakahar 
    746       1.1  knakahar 	msi_pic->pic_msipic->mp_veccnt = count;
    747       1.1  knakahar 	return 0;
    748       1.1  knakahar }
    749       1.1  knakahar 
    750       1.1  knakahar /*
    751       1.1  knakahar  * Initialize the system to use MSI/MSI-X.
    752       1.1  knakahar  */
    753       1.1  knakahar void
    754       1.1  knakahar msipic_init(void)
    755       1.1  knakahar {
    756       1.1  knakahar 
    757       1.1  knakahar 	mutex_init(&msipic_list_lock, MUTEX_DEFAULT, IPL_NONE);
    758       1.1  knakahar }
    759