1/*	$OpenBSD: aapic.c,v 1.7 2022/02/21 11:03:39 mpi Exp $	*/
2/* 	$NetBSD: aapic.c,v 1.3 2005/01/13 23:40:01 fvdl Exp $	*/
3
4/*
5 * The AMD 8131 IO APIC can hang the box when an APIC IRQ is masked.
6 */
7#include <sys/param.h>
8#include <sys/systm.h>
9#include <sys/device.h>
10
11#include <dev/pci/pcireg.h>
12#include <dev/pci/pcivar.h>
13#include <dev/pci/pcidevs.h>
14
15#include "ioapic.h"
16
17#if NIOAPIC > 0
18extern int nioapics;
19#endif
20
21#define AMD8131_PCIX_MISC	0x40
22#define AMD8131_NIOAMODE	0x00000001
23
24#define AMD8131_IOAPIC_CTL	0x44
25#define AMD8131_IOAEN		0x00000002
26
27int	aapic_match(struct device *, void *, void *);
28void	aapic_attach(struct device *, struct device *, void *);
29
30struct aapic_softc {
31	struct device sc_dev;
32};
33
34const struct cfattach aapic_ca = {
35	sizeof(struct aapic_softc), aapic_match, aapic_attach
36};
37
38struct cfdriver aapic_cd = {
39	0, "aapic", DV_DULL
40};
41
42int
43aapic_match(struct device *parent, void *match, void *aux)
44{
45	struct pci_attach_args *pa = aux;
46
47	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD &&
48	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_8131_PCIX_IOAPIC)
49		return (1);
50
51	return (0);
52}
53
54void
55aapic_attach(struct device *parent, struct device *self, void *aux)
56{
57	struct pci_attach_args *pa = aux;
58	int bus, dev, func;
59	pcitag_t tag;
60	pcireg_t reg;
61
62	printf("\n");
63
64#if NIOAPIC > 0
65	if (nioapics == 0)
66		return;
67#else
68	return;
69#endif
70
71	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMD8131_IOAPIC_CTL);
72	reg |= AMD8131_IOAEN;
73	pci_conf_write(pa->pa_pc, pa->pa_tag, AMD8131_IOAPIC_CTL, reg);
74
75	pci_decompose_tag(pa->pa_pc, pa->pa_tag, &bus, &dev, &func);
76	func = 0;
77	tag = pci_make_tag(pa->pa_pc, bus, dev, func);
78	reg = pci_conf_read(pa->pa_pc, tag, AMD8131_PCIX_MISC);
79	reg &= ~AMD8131_NIOAMODE;
80	pci_conf_write(pa->pa_pc, tag, AMD8131_PCIX_MISC, reg);
81}
82