Home | History | Annotate | Line # | Download | only in acpi
acpi_pci_machdep.c revision 1.2
      1 /* $NetBSD: acpi_pci_machdep.c,v 1.2 2018/10/19 11:40:27 jmcneill Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2018 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jared McNeill <jmcneill (at) invisible.ca>.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: acpi_pci_machdep.c,v 1.2 2018/10/19 11:40:27 jmcneill Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/bus.h>
     37 #include <sys/device.h>
     38 #include <sys/intr.h>
     39 #include <sys/systm.h>
     40 #include <sys/kernel.h>
     41 #include <sys/extent.h>
     42 #include <sys/queue.h>
     43 #include <sys/mutex.h>
     44 #include <sys/kmem.h>
     45 
     46 #include <machine/cpu.h>
     47 
     48 #include <arm/cpufunc.h>
     49 
     50 #include <dev/pci/pcireg.h>
     51 #include <dev/pci/pcivar.h>
     52 #include <dev/pci/pciconf.h>
     53 
     54 #include <dev/acpi/acpivar.h>
     55 #include <dev/acpi/acpi_mcfg.h>
     56 #include <dev/acpi/acpi_pci.h>
     57 
     58 #include <arm/acpi/acpi_pci_machdep.h>
     59 
     60 #define	IH_INDEX_MASK			0x0000ffff
     61 #define	IH_MPSAFE			0x80000000
     62 
     63 struct acpi_pci_prt {
     64 	u_int				prt_bus;
     65 	ACPI_HANDLE			prt_handle;
     66 	TAILQ_ENTRY(acpi_pci_prt)	prt_list;
     67 };
     68 
     69 static TAILQ_HEAD(, acpi_pci_prt) acpi_pci_irq_routes =
     70     TAILQ_HEAD_INITIALIZER(acpi_pci_irq_routes);
     71 
     72 static void	acpi_pci_md_attach_hook(device_t, device_t,
     73 				       struct pcibus_attach_args *);
     74 static int	acpi_pci_md_bus_maxdevs(void *, int);
     75 static pcitag_t	acpi_pci_md_make_tag(void *, int, int, int);
     76 static void	acpi_pci_md_decompose_tag(void *, pcitag_t, int *, int *, int *);
     77 static pcireg_t	acpi_pci_md_conf_read(void *, pcitag_t, int);
     78 static void	acpi_pci_md_conf_write(void *, pcitag_t, int, pcireg_t);
     79 static int	acpi_pci_md_conf_hook(void *, int, int, int, pcireg_t);
     80 static void	acpi_pci_md_conf_interrupt(void *, int, int, int, int, int *);
     81 
     82 static int	acpi_pci_md_intr_map(const struct pci_attach_args *,
     83 				    pci_intr_handle_t *);
     84 static const char *acpi_pci_md_intr_string(void *, pci_intr_handle_t,
     85 					  char *, size_t);
     86 static const struct evcnt *acpi_pci_md_intr_evcnt(void *, pci_intr_handle_t);
     87 static int	acpi_pci_md_intr_setattr(void *, pci_intr_handle_t *, int,
     88 					uint64_t);
     89 static void *	acpi_pci_md_intr_establish(void *, pci_intr_handle_t,
     90 					 int, int (*)(void *), void *);
     91 static void	acpi_pci_md_intr_disestablish(void *, void *);
     92 
     93 struct arm32_pci_chipset arm_acpi_pci_chipset = {
     94 	.pc_attach_hook = acpi_pci_md_attach_hook,
     95 	.pc_bus_maxdevs = acpi_pci_md_bus_maxdevs,
     96 	.pc_make_tag = acpi_pci_md_make_tag,
     97 	.pc_decompose_tag = acpi_pci_md_decompose_tag,
     98 	.pc_conf_read = acpi_pci_md_conf_read,
     99 	.pc_conf_write = acpi_pci_md_conf_write,
    100 	.pc_conf_hook = acpi_pci_md_conf_hook,
    101 	.pc_conf_interrupt = acpi_pci_md_conf_interrupt,
    102 
    103 	.pc_intr_map = acpi_pci_md_intr_map,
    104 	.pc_intr_string = acpi_pci_md_intr_string,
    105 	.pc_intr_evcnt = acpi_pci_md_intr_evcnt,
    106 	.pc_intr_setattr = acpi_pci_md_intr_setattr,
    107 	.pc_intr_establish = acpi_pci_md_intr_establish,
    108 	.pc_intr_disestablish = acpi_pci_md_intr_disestablish,
    109 };
    110 
    111 static ACPI_STATUS
    112 acpi_pci_md_pci_link(ACPI_HANDLE handle, int bus)
    113 {
    114 	ACPI_PCI_ROUTING_TABLE *prt;
    115 	ACPI_HANDLE linksrc;
    116 	ACPI_BUFFER buf;
    117 	ACPI_STATUS rv;
    118 	void *linkdev;
    119 
    120 	rv = acpi_get(handle, &buf, AcpiGetIrqRoutingTable);
    121 	if (ACPI_FAILURE(rv))
    122 		return rv;
    123 
    124 	for (char *p = buf.Pointer; ; p += prt->Length) {
    125 		prt = (ACPI_PCI_ROUTING_TABLE *)p;
    126 		if (prt->Length == 0)
    127 			break;
    128 
    129 		const u_int dev = ACPI_HIWORD(prt->Address);
    130 		if (prt->Source[0] != 0) {
    131 			aprint_debug("ACPI: %s dev %u INT%c on lnkdev %s\n",
    132 			    acpi_name(handle), dev, 'A' + (prt->Pin & 3), prt->Source);
    133 			rv = AcpiGetHandle(ACPI_ROOT_OBJECT, prt->Source, &linksrc);
    134 			if (ACPI_FAILURE(rv)) {
    135 				aprint_debug("ACPI: AcpiGetHandle failed for '%s': %s\n",
    136 				    prt->Source, AcpiFormatException(rv));
    137 				continue;
    138 			}
    139 
    140 			linkdev = acpi_pci_link_devbyhandle(linksrc);
    141 			acpi_pci_link_add_reference(linkdev, 0, bus, dev, prt->Pin & 3);
    142 		} else {
    143 			aprint_debug("ACPI: %s dev %u INT%c on globint %d\n",
    144 			    acpi_name(handle), dev, 'A' + (prt->Pin & 3), prt->SourceIndex);
    145 		}
    146 	}
    147 
    148 	return AE_OK;
    149 }
    150 
    151 static void
    152 acpi_pci_md_attach_hook(device_t parent, device_t self,
    153     struct pcibus_attach_args *pba)
    154 {
    155 	struct acpi_pci_context *ap = pba->pba_pc->pc_conf_v;
    156 	struct acpi_pci_prt *prt, *prtp;
    157 	struct acpi_devnode *ad;
    158 	ACPI_HANDLE handle;
    159 	int seg, bus, dev, func;
    160 
    161 	seg = ap->ap_seg;
    162 	handle = NULL;
    163 
    164 	if (pba->pba_bridgetag) {
    165 		/*
    166 		 * Find the PCI address of our parent bridge and look for the
    167 		 * corresponding ACPI device node. If there is no node for this
    168 		 * bus, use the parent bridge routing information.
    169 		 */
    170 		acpi_pci_md_decompose_tag(NULL, *pba->pba_bridgetag, &bus, &dev, &func);
    171 		ad = acpi_pcidev_find(seg, bus, dev, func);
    172 		if (ad != NULL) {
    173 			handle = ad->ad_handle;
    174 		} else {
    175 			/* No routes defined for this bus, copy from parent */
    176 			TAILQ_FOREACH(prtp, &acpi_pci_irq_routes, prt_list)
    177 				if (prtp->prt_bus == bus) {
    178 					handle = prtp->prt_handle;
    179 					break;
    180 				}
    181 		}
    182 	} else {
    183 		/*
    184 		 * Lookup the ACPI device node for the root bus.
    185 		 */
    186 		ad = acpi_pciroot_find(seg, 0);
    187 		if (ad != NULL)
    188 			handle = ad->ad_handle;
    189 	}
    190 
    191 	if (ad != NULL) {
    192 		/*
    193 		 * This is a new ACPI managed bus. Add PCI link references.
    194 		 */
    195 		acpi_pci_md_pci_link(ad->ad_handle, pba->pba_bus);
    196 	}
    197 
    198 	if (handle != NULL) {
    199 		prt = kmem_alloc(sizeof(*prt), KM_SLEEP);
    200 		prt->prt_bus = pba->pba_bus;
    201 		prt->prt_handle = handle;
    202 		TAILQ_INSERT_TAIL(&acpi_pci_irq_routes, prt, prt_list);
    203 	}
    204 
    205 	acpimcfg_map_bus(self, pba->pba_pc, pba->pba_bus);
    206 }
    207 
    208 static int
    209 acpi_pci_md_bus_maxdevs(void *v, int busno)
    210 {
    211 	return 32;
    212 }
    213 
    214 static pcitag_t
    215 acpi_pci_md_make_tag(void *v, int b, int d, int f)
    216 {
    217 	return (b << 16) | (d << 11) | (f << 8);
    218 }
    219 
    220 static void
    221 acpi_pci_md_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp)
    222 {
    223 	if (bp)
    224 		*bp = (tag >> 16) & 0xff;
    225 	if (dp)
    226 		*dp = (tag >> 11) & 0x1f;
    227 	if (fp)
    228 		*fp = (tag >> 8) & 0x7;
    229 }
    230 
    231 static pcireg_t
    232 acpi_pci_md_conf_read(void *v, pcitag_t tag, int offset)
    233 {
    234 	struct acpi_pci_context * const ap = v;
    235 	pcireg_t val;
    236 
    237 	if (offset < 0 || offset >= PCI_EXTCONF_SIZE)
    238 		return (pcireg_t) -1;
    239 
    240 	acpimcfg_conf_read(&ap->ap_pc, tag, offset, &val);
    241 
    242 	return val;
    243 }
    244 
    245 static void
    246 acpi_pci_md_conf_write(void *v, pcitag_t tag, int offset, pcireg_t val)
    247 {
    248 	struct acpi_pci_context * const ap = v;
    249 
    250 	if (offset < 0 || offset >= PCI_EXTCONF_SIZE)
    251 		return;
    252 
    253 	acpimcfg_conf_write(&ap->ap_pc, tag, offset, val);
    254 }
    255 
    256 static int
    257 acpi_pci_md_conf_hook(void *v, int b, int d, int f, pcireg_t id)
    258 {
    259 	return PCI_CONF_DEFAULT;
    260 }
    261 
    262 static void
    263 acpi_pci_md_conf_interrupt(void *v, int bus, int dev, int ipin, int sqiz, int *ilinep)
    264 {
    265 }
    266 
    267 static struct acpi_pci_prt *
    268 acpi_pci_md_intr_find_prt(u_int bus)
    269 {
    270 	struct acpi_pci_prt *prt, *prtp;
    271 
    272 	prt = NULL;
    273 	TAILQ_FOREACH(prtp, &acpi_pci_irq_routes, prt_list)
    274 		if (prtp->prt_bus == bus) {
    275 			prt = prtp;
    276 			break;
    277 		}
    278 
    279 	return prt;
    280 }
    281 
    282 static int
    283 acpi_pci_md_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ih)
    284 {
    285 	struct acpi_pci_prt *prt;
    286 	ACPI_PCI_ROUTING_TABLE *tab;
    287 	int line, pol, trig, error;
    288 	ACPI_HANDLE linksrc;
    289 	ACPI_BUFFER buf;
    290 	void *linkdev;
    291 
    292 	if (pa->pa_intrpin == PCI_INTERRUPT_PIN_NONE)
    293 		return EINVAL;
    294 
    295 	prt = acpi_pci_md_intr_find_prt(pa->pa_bus);
    296 	if (prt == NULL)
    297 		return ENXIO;
    298 
    299 	if (ACPI_FAILURE(acpi_get(prt->prt_handle, &buf, AcpiGetIrqRoutingTable)))
    300 		return EIO;
    301 
    302 	error = ENOENT;
    303 	for (char *p = buf.Pointer; ; p += tab->Length) {
    304 		tab = (ACPI_PCI_ROUTING_TABLE *)p;
    305 		if (tab->Length == 0)
    306 			break;
    307 
    308 		if (pa->pa_device == ACPI_HIWORD(tab->Address) &&
    309 		    (pa->pa_intrpin - 1) == (tab->Pin & 3)) {
    310 			if (tab->Source[0] != 0) {
    311 				if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, tab->Source, &linksrc)))
    312 					goto done;
    313 				linkdev = acpi_pci_link_devbyhandle(linksrc);
    314 				*ih = acpi_pci_link_route_interrupt(linkdev, tab->SourceIndex,
    315 				    &line, &pol, &trig);
    316 				error = 0;
    317 				goto done;
    318 			} else {
    319 				*ih = tab->SourceIndex;
    320 				error = 0;
    321 				goto done;
    322 			}
    323 		}
    324 	}
    325 
    326 done:
    327 	ACPI_FREE(buf.Pointer);
    328 	return error;
    329 }
    330 
    331 static const char *
    332 acpi_pci_md_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
    333 {
    334 	snprintf(buf, len, "irq %d", (int)(ih & IH_INDEX_MASK));
    335 	return buf;
    336 }
    337 
    338 static const struct evcnt *
    339 acpi_pci_md_intr_evcnt(void *v, pci_intr_handle_t ih)
    340 {
    341 	return NULL;
    342 }
    343 
    344 static int
    345 acpi_pci_md_intr_setattr(void *v, pci_intr_handle_t *ih, int attr, uint64_t data)
    346 {
    347 	switch (attr) {
    348 	case PCI_INTR_MPSAFE:
    349 		if (data)
    350 			*ih |= IH_MPSAFE;
    351 		else
    352 			*ih &= ~IH_MPSAFE;
    353 		return 0;
    354 	default:
    355 		return ENODEV;
    356 	}
    357 }
    358 
    359 static void *
    360 acpi_pci_md_intr_establish(void *v, pci_intr_handle_t ih, int ipl,
    361     int (*callback)(void *), void *arg)
    362 {
    363 	const int irq = ih & IH_INDEX_MASK;
    364 	const int mpsafe = (ih & IH_MPSAFE) ? IST_MPSAFE : 0;
    365 
    366 	return intr_establish(irq, ipl, IST_LEVEL | mpsafe, callback, arg);
    367 }
    368 
    369 static void
    370 acpi_pci_md_intr_disestablish(void *v, void *vih)
    371 {
    372 	intr_disestablish(vih);
    373 }
    374