summaryrefslogtreecommitdiff
path: root/sys/dev/pci/puc.c
diff options
context:
space:
mode:
authorJoshua Stein <jcs@cvs.openbsd.org>2018-04-15 15:07:26 +0000
committerJoshua Stein <jcs@cvs.openbsd.org>2018-04-15 15:07:26 +0000
commit7b3722a75dfb4c9076931aac499a2f91133c0d60 (patch)
treedba91b5ce2fdb93be4fe35b7878228e97f68d46c /sys/dev/pci/puc.c
parente4d715a9eb7c4dad4d9d80590f18ca457119f220 (diff)
The Exar XR17V354 has 4 com ports that have a 256-byte FIFO, use a
frequency of 125Mhz, and have a unique sleep register. A custom interrupt handler is setup in puc for these ports so it can check a register which reports which ports triggered the interrupt, rather than having to run comintr for every port every time. ok mlarkin deraadt
Diffstat (limited to 'sys/dev/pci/puc.c')
-rw-r--r--sys/dev/pci/puc.c45
1 files changed, 40 insertions, 5 deletions
diff --git a/sys/dev/pci/puc.c b/sys/dev/pci/puc.c
index ff65cafd26a..bbd05098395 100644
--- a/sys/dev/pci/puc.c
+++ b/sys/dev/pci/puc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: puc.c,v 1.24 2015/03/14 03:38:49 jsg Exp $ */
+/* $OpenBSD: puc.c,v 1.25 2018/04/15 15:07:25 jcs Exp $ */
/* $NetBSD: puc.c,v 1.3 1999/02/06 06:29:54 cgd Exp $ */
/*
@@ -61,6 +61,7 @@
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pucvar.h>
+#include <dev/pci/pcidevs.h>
#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>
@@ -78,6 +79,7 @@ int puc_pci_detach(struct device *, int);
const char *puc_pci_intr_string(struct puc_attach_args *);
void *puc_pci_intr_establish(struct puc_attach_args *, int,
int (*)(void *), void *, char *);
+int puc_pci_xr17v35x_intr(void *arg);
struct cfattach puc_pci_ca = {
sizeof(struct puc_pci_softc), puc_pci_match,
@@ -125,9 +127,20 @@ puc_pci_intr_establish(struct puc_attach_args *paa, int type,
{
struct puc_pci_softc *sc = paa->puc;
struct puc_softc *psc = &sc->sc_psc;
-
- psc->sc_ports[paa->port].intrhand =
- pci_intr_establish(sc->pc, sc->ih, type, func, arg, name);
+
+ if (psc->sc_xr17v35x) {
+ psc->sc_ports[paa->port].real_intrhand = func;
+ psc->sc_ports[paa->port].real_intrhand_arg = arg;
+ if (paa->port == 0)
+ psc->sc_ports[paa->port].intrhand =
+ pci_intr_establish(sc->pc, sc->ih, type,
+ puc_pci_xr17v35x_intr, sc, name);
+ return (psc->sc_ports[paa->port].real_intrhand);
+ } else {
+ psc->sc_ports[paa->port].intrhand =
+ pci_intr_establish(sc->pc, sc->ih, type, func, arg, name);
+ return (psc->sc_ports[paa->port].intrhand);
+ }
return (psc->sc_ports[paa->port].intrhand);
}
@@ -146,6 +159,10 @@ puc_pci_attach(struct device *parent, struct device *self, void *aux)
sc->sc_desc = puc_find_description(PCI_VENDOR(pa->pa_id),
PCI_PRODUCT(pa->pa_id), PCI_VENDOR(subsys), PCI_PRODUCT(subsys));
+ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_EXAR &&
+ PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_EXAR_XR17V354)
+ sc->sc_xr17v35x = 1;
+
puc_print_ports(sc->sc_desc);
for (i = 0; i < PUC_NBARS; i++) {
@@ -319,7 +336,6 @@ puc_find_description(u_int16_t vend, u_int16_t prod,
const char *
puc_port_type_name(int type)
{
-
if (PUC_IS_COM(type))
return "com";
if (PUC_IS_LPT(type))
@@ -348,3 +364,22 @@ puc_print_ports(const struct puc_device_description *desc)
}
printf("\n");
}
+
+int
+puc_pci_xr17v35x_intr(void *arg)
+{
+ struct puc_pci_softc *sc = arg;
+ struct puc_softc *psc = &sc->sc_psc;
+ int ports, i;
+
+ ports = bus_space_read_1(psc->sc_bar_mappings[0].t,
+ psc->sc_bar_mappings[0].h, UART_EXAR_INT0);
+
+ for (i = 0; i < 8; i++) {
+ if ((ports & (1 << i)) && psc->sc_ports[i].real_intrhand)
+ (*(psc->sc_ports[i].real_intrhand))(
+ psc->sc_ports[i].real_intrhand_arg);
+ }
+
+ return (1);
+}