1 /*        $NetBSD: ppb.c,v 1.76 2024/08/29 20:41:49 andvar Exp $      */
2 
3 /*
4  * Copyright (c) 1996, 1998 Christopher G. Demetriou.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Christopher G. Demetriou
17  *        for the NetBSD Project.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: ppb.c,v 1.76 2024/08/29 20:41:49 andvar Exp $");
35 
36 #ifdef _KERNEL_OPT
37 #include "opt_ppb.h"
38 #endif
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/device.h>
44 #include <sys/evcnt.h>
45 
46 #include <dev/pci/pcireg.h>
47 #include <dev/pci/pcivar.h>
48 #include <dev/pci/ppbreg.h>
49 #include <dev/pci/ppbvar.h>
50 #include <dev/pci/pcidevs.h>
51 
52 #define   PCIE_SLCSR_ENABLE_MASK                                                \
53           (PCIE_SLCSR_ABE | PCIE_SLCSR_PFE | PCIE_SLCSR_MSE |         \
54            PCIE_SLCSR_PDE | PCIE_SLCSR_CCE | PCIE_SLCSR_HPE |         \
55            PCIE_SLCSR_DLLSCE)
56 
57 #define   PCIE_SLCSR_STATCHG_MASK                                               \
58           (PCIE_SLCSR_ABP | PCIE_SLCSR_PFD | PCIE_SLCSR_MSC |         \
59            PCIE_SLCSR_PDC | PCIE_SLCSR_CC | PCIE_SLCSR_LACS)
60 
61 static const char pcie_linkspeed_strings[6][5] = {
62           "1.25", "2.5", "5.0", "8.0", "16.0", "32.0",
63 };
64 
65 int       ppb_printevent = 0; /* Print event type if the value is not 0 */
66 
67 static int          ppbmatch(device_t, cfdata_t, void *);
68 static void         ppbattach(device_t, device_t, void *);
69 static int          ppbdetach(device_t, int);
70 static void         ppbchilddet(device_t, device_t);
71 #ifdef PPB_USEINTR
72 static int          ppb_intr(void *);
73 #endif
74 static bool         ppb_resume(device_t, const pmf_qual_t *);
75 static bool         ppb_suspend(device_t, const pmf_qual_t *);
76 
77 CFATTACH_DECL3_NEW(ppb, sizeof(struct ppb_softc),
78     ppbmatch, ppbattach, ppbdetach, NULL, NULL, ppbchilddet,
79     DVF_DETACH_SHUTDOWN);
80 
81 static int
ppbmatch(device_t parent,cfdata_t match,void * aux)82 ppbmatch(device_t parent, cfdata_t match, void *aux)
83 {
84           struct pci_attach_args *pa = aux;
85 
86           /*
87            * Check the ID register to see that it's a PCI bridge.
88            * If it is, we assume that we can deal with it; it _should_
89            * work in a standardized way...
90            */
91           if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
92               PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_PCI)
93                     return 1;
94 
95 #ifdef __powerpc__
96           if (PCI_CLASS(pa->pa_class) == PCI_CLASS_PROCESSOR &&
97               PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_PROCESSOR_POWERPC) {
98                     pcireg_t bhlc = pci_conf_read(pa->pa_pc, pa->pa_tag,
99                         PCI_BHLC_REG);
100                     if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_FREESCALE
101                         && PCI_HDRTYPE(bhlc) == PCI_HDRTYPE_RC)
102                     return 1;
103           }
104 #endif
105 
106 #ifdef _MIPS_PADDR_T_64BIT
107           /* The LDT HB acts just like a PPB.  */
108           if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SIBYTE
109               && PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SIBYTE_BCM1250_LDTHB)
110                     return 1;
111 #endif
112 
113           return 0;
114 }
115 
116 static void
ppb_print_pcie(device_t self)117 ppb_print_pcie(device_t self)
118 {
119           struct ppb_softc *sc = device_private(self);
120           pcireg_t reg;
121           int off, capversion, devtype;
122 
123           if (!pci_get_capability(sc->sc_pc, sc->sc_tag, PCI_CAP_PCIEXPRESS,
124                                         &off, &reg))
125                     return; /* Not a PCIe device */
126 
127           capversion = PCIE_XCAP_VER(reg);
128           devtype = PCIE_XCAP_TYPE(reg);
129           aprint_normal_dev(self, "PCI Express capability version ");
130           switch (capversion) {
131           case PCIE_XCAP_VER_1:
132                     aprint_normal("1");
133                     break;
134           case PCIE_XCAP_VER_2:
135                     aprint_normal("2");
136                     break;
137           default:
138                     aprint_normal_dev(self, "unsupported (%d)\n", capversion);
139                     return;
140           }
141           aprint_normal(" <");
142           switch (devtype) {
143           case PCIE_XCAP_TYPE_PCIE_DEV:
144                     aprint_normal("PCI-E Endpoint device");
145                     break;
146           case PCIE_XCAP_TYPE_PCI_DEV:
147                     aprint_normal("Legacy PCI-E Endpoint device");
148                     break;
149           case PCIE_XCAP_TYPE_RP:
150                     aprint_normal("Root Port of PCI-E Root Complex");
151                     break;
152           case PCIE_XCAP_TYPE_UP:
153                     aprint_normal("Upstream Port of PCI-E Switch");
154                     break;
155           case PCIE_XCAP_TYPE_DOWN:
156                     aprint_normal("Downstream Port of PCI-E Switch");
157                     break;
158           case PCIE_XCAP_TYPE_PCIE2PCI:
159                     aprint_normal("PCI-E to PCI/PCI-X Bridge");
160                     break;
161           case PCIE_XCAP_TYPE_PCI2PCIE:
162                     aprint_normal("PCI/PCI-X to PCI-E Bridge");
163                     break;
164           default:
165                     aprint_normal("Device/Port Type %x", devtype);
166                     break;
167           }
168 
169           switch (devtype) {
170           case PCIE_XCAP_TYPE_RP:
171           case PCIE_XCAP_TYPE_DOWN:
172           case PCIE_XCAP_TYPE_PCI2PCIE:
173                     reg = pci_conf_read(sc->sc_pc, sc->sc_tag, off + PCIE_LCAP);
174                     u_int mlw = __SHIFTOUT(reg, PCIE_LCAP_MAX_WIDTH);
175                     u_int mls = __SHIFTOUT(reg, PCIE_LCAP_MAX_SPEED);
176 
177                     if (mls < __arraycount(pcie_linkspeed_strings)) {
178                               aprint_normal("> x%d @ %sGT/s\n",
179                                   mlw, pcie_linkspeed_strings[mls]);
180                     } else {
181                               aprint_normal("> x%d @ %d.%dGT/s\n",
182                                   mlw, (mls * 25) / 10, (mls * 25) % 10);
183                     }
184 
185                     reg = pci_conf_read(sc->sc_pc, sc->sc_tag, off + PCIE_LCSR);
186                     if (reg & PCIE_LCSR_DLACTIVE) {         /* DLLA */
187                               u_int lw = __SHIFTOUT(reg, PCIE_LCSR_NLW);
188                               u_int ls = __SHIFTOUT(reg, PCIE_LCSR_LINKSPEED);
189 
190                               if (lw != mlw || ls != mls) {
191                                         if (ls < __arraycount(pcie_linkspeed_strings)) {
192                                                   aprint_normal_dev(self,
193                                                       "link is x%d @ %sGT/s\n",
194                                                       lw, pcie_linkspeed_strings[ls]);
195                                         } else {
196                                                   aprint_normal_dev(self,
197                                                       "link is x%d @ %d.%dGT/s\n",
198                                                       lw, (ls * 25) / 10, (ls * 25) % 10);
199                                         }
200                               }
201                     }
202                     break;
203           default:
204                     aprint_normal(">\n");
205                     break;
206           }
207 }
208 
209 static void
ppbattach(device_t parent,device_t self,void * aux)210 ppbattach(device_t parent, device_t self, void *aux)
211 {
212           struct ppb_softc *sc = device_private(self);
213           struct pci_attach_args *pa = aux;
214           pci_chipset_tag_t pc = pa->pa_pc;
215           struct pcibus_attach_args pba;
216 #ifdef PPB_USEINTR
217           char const *intrstr;
218           char intrbuf[PCI_INTRSTR_LEN];
219 #endif
220           pcireg_t busdata, reg;
221           bool second_configured = false;
222 
223           pci_aprint_devinfo(pa, NULL);
224 
225           sc->sc_pc = pc;
226           sc->sc_tag = pa->pa_tag;
227           sc->sc_dev = self;
228 
229           busdata = pci_conf_read(pc, pa->pa_tag, PCI_BRIDGE_BUS_REG);
230 
231           if (PCI_BRIDGE_BUS_NUM_SECONDARY(busdata) == 0) {
232                     aprint_normal_dev(self, "not configured by system firmware\n");
233                     return;
234           }
235 
236           ppb_print_pcie(self);
237 
238 #if 0
239           /*
240            * XXX can't do this, because we're not given our bus number
241            * (we shouldn't need it), and because we've no way to
242            * decompose our tag.
243            */
244           /* sanity check. */
245           if (pa->pa_bus != PCI_BRIDGE_BUS_NUM_PRIMARY(busdata))
246                     panic("ppbattach: bus in tag (%d) != bus in reg (%d)",
247                         pa->pa_bus, PCI_BRIDGE_BUS_NUM_PRIMARY(busdata));
248 #endif
249 
250           /* Check for PCI Express capabilities and setup hotplug support. */
251           if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PCIEXPRESS,
252               &sc->sc_pciecapoff, &reg) && (reg & PCIE_XCAP_SI)) {
253                     /*
254                      * First, disable all interrupts because BIOS might
255                      * enable them.
256                      */
257                     reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
258                         sc->sc_pciecapoff + PCIE_SLCSR);
259                     if (reg & PCIE_SLCSR_ENABLE_MASK) {
260                               reg &= ~PCIE_SLCSR_ENABLE_MASK;
261                               pci_conf_write(sc->sc_pc, sc->sc_tag,
262                                   sc->sc_pciecapoff + PCIE_SLCSR, reg);
263                     }
264 #ifdef PPB_USEINTR
265 #if 0 /* notyet */
266                     /*
267                      * XXX Initialize workqueue or something else for
268                      * HotPlug support.
269                      */
270 #endif
271                     if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0) == 0)
272                               sc->sc_intrhand = pci_intr_establish_xname(pc,
273                                   sc->sc_pihp[0], IPL_BIO, ppb_intr, sc,
274                                   device_xname(sc->sc_dev));
275 #endif
276           }
277 
278 #ifdef PPB_USEINTR
279           if (sc->sc_intrhand != NULL) {
280                     pcireg_t slcap, slcsr, val;
281 
282                     intrstr = pci_intr_string(pc, sc->sc_pihp[0], intrbuf,
283                         sizeof(intrbuf));
284                     aprint_normal_dev(self, "interrupting at %s\n", intrstr);
285 
286                     /* Clear any pending events */
287                     slcsr = pci_conf_read(pc, pa->pa_tag,
288                         sc->sc_pciecapoff + PCIE_SLCSR);
289                     pci_conf_write(pc, pa->pa_tag,
290                         sc->sc_pciecapoff + PCIE_SLCSR, slcsr);
291 
292                     /* Enable interrupt. */
293                     val = 0;
294                     slcap = pci_conf_read(pc, pa->pa_tag,
295                         sc->sc_pciecapoff + PCIE_SLCAP);
296                     if (slcap & PCIE_SLCAP_ABP)
297                               val |= PCIE_SLCSR_ABE;
298                     if (slcap & PCIE_SLCAP_PCP)
299                               val |= PCIE_SLCSR_PFE;
300                     if (slcap & PCIE_SLCAP_MSP)
301                               val |= PCIE_SLCSR_MSE;
302 #if 0
303                     /*
304                      * XXX Disable for a while because setting
305                      * PCIE_SLCSR_CCE makes break device access on
306                      * some environment.
307                      */
308                     if ((slcap & PCIE_SLCAP_NCCS) == 0)
309                               val |= PCIE_SLCSR_CCE;
310 #endif
311                     /* Attention indicator off by default */
312                     if (slcap & PCIE_SLCAP_AIP) {
313                               val |= __SHIFTIN(PCIE_SLCSR_IND_OFF,
314                                   PCIE_SLCSR_AIC);
315                     }
316                     /* Power indicator */
317                     if (slcap & PCIE_SLCAP_PIP) {
318                               /*
319                                * Indicator off:
320                                *  a) card not present
321                                *  b) power fault
322                                *  c) MRL sensor off
323                                */
324                               if (((slcsr & PCIE_SLCSR_PDS) == 0)
325                                   || ((slcsr & PCIE_SLCSR_PFD) != 0)
326                                   || (((slcap & PCIE_SLCAP_MSP) != 0)
327                                         && ((slcsr & PCIE_SLCSR_MS) != 0)))
328                                         val |= __SHIFTIN(PCIE_SLCSR_IND_OFF,
329                                             PCIE_SLCSR_PIC);
330                               else
331                                         val |= __SHIFTIN(PCIE_SLCSR_IND_ON,
332                                             PCIE_SLCSR_PIC);
333                     }
334 
335                     val |= PCIE_SLCSR_DLLSCE | PCIE_SLCSR_HPE | PCIE_SLCSR_PDE;
336                     slcsr = val;
337                     pci_conf_write(pc, pa->pa_tag,
338                         sc->sc_pciecapoff + PCIE_SLCSR, slcsr);
339 
340                     /* Attach event counters */
341                     evcnt_attach_dynamic(&sc->sc_ev_intr, EVCNT_TYPE_INTR, NULL,
342                         device_xname(sc->sc_dev), "Interrupt");
343                     evcnt_attach_dynamic(&sc->sc_ev_abp, EVCNT_TYPE_MISC, NULL,
344                         device_xname(sc->sc_dev), "Attention Button Pressed");
345                     evcnt_attach_dynamic(&sc->sc_ev_pfd, EVCNT_TYPE_MISC, NULL,
346                         device_xname(sc->sc_dev), "Power Fault Detected");
347                     evcnt_attach_dynamic(&sc->sc_ev_msc, EVCNT_TYPE_MISC, NULL,
348                         device_xname(sc->sc_dev), "MRL Sensor Changed");
349                     evcnt_attach_dynamic(&sc->sc_ev_pdc, EVCNT_TYPE_MISC, NULL,
350                         device_xname(sc->sc_dev), "Presence Detect Changed");
351                     evcnt_attach_dynamic(&sc->sc_ev_cc, EVCNT_TYPE_MISC, NULL,
352                         device_xname(sc->sc_dev), "Command Completed");
353                     evcnt_attach_dynamic(&sc->sc_ev_lacs, EVCNT_TYPE_MISC, NULL,
354                         device_xname(sc->sc_dev), "Data Link Layer State Changed");
355           }
356 #endif /* PPB_USEINTR */
357 
358           /* Configuration test */
359           if (PCI_BRIDGE_BUS_NUM_SECONDARY(busdata) != 0) {
360                     uint32_t base, limit;
361 
362                     /* I/O region test */
363                     reg = pci_conf_read(pc, pa->pa_tag, PCI_BRIDGE_STATIO_REG);
364                     base = PCI_BRIDGE_STATIO_IOBASE_ADDR(reg);
365                     limit = PCI_BRIDGE_STATIO_IOLIMIT_ADDR(reg);
366                     if (PCI_BRIDGE_IO_32BITS(reg)) {
367                               reg = pci_conf_read(pc, pa->pa_tag,
368                                   PCI_BRIDGE_IOHIGH_REG);
369                               base |= __SHIFTOUT(reg, PCI_BRIDGE_IOHIGH_BASE) << 16;
370                               limit |= __SHIFTOUT(reg, PCI_BRIDGE_IOHIGH_LIMIT) <<16;
371                     }
372                     if (base < limit) {
373                               second_configured = true;
374                               goto configure;
375                     }
376 
377                     /* Non-prefetchable memory region test */
378                     reg = pci_conf_read(pc, pa->pa_tag, PCI_BRIDGE_MEMORY_REG);
379                     base = PCI_BRIDGE_MEMORY_BASE_ADDR(reg);
380                     limit = PCI_BRIDGE_MEMORY_LIMIT_ADDR(reg);
381                     if (base < limit) {
382                               second_configured = true;
383                               goto configure;
384                     }
385 
386                     /* Prefetchable memory region test */
387                     reg = pci_conf_read(pc, pa->pa_tag,
388                         PCI_BRIDGE_PREFETCHMEM_REG);
389                     base = PCI_BRIDGE_PREFETCHMEM_BASE_ADDR(reg);
390                     limit = PCI_BRIDGE_PREFETCHMEM_LIMIT_ADDR(reg);
391 
392                     if (PCI_BRIDGE_PREFETCHMEM_64BITS(reg)) {
393                               reg = pci_conf_read(pc, pa->pa_tag,
394                                   PCI_BRIDGE_IOHIGH_REG);
395                               base |= (uint64_t)pci_conf_read(pc, pa->pa_tag,
396                                   PCI_BRIDGE_PREFETCHBASEUP32_REG) << 32;
397                               limit |= (uint64_t)pci_conf_read(pc, pa->pa_tag,
398                                   PCI_BRIDGE_PREFETCHLIMITUP32_REG) << 32;
399                     }
400                     if (base < limit) {
401                               second_configured = true;
402                               goto configure;
403                     }
404           }
405 
406 configure:
407           /*
408            * If the secondary bus is configured and the bus mastering is not
409            * enabled, enable it.
410            */
411           if (second_configured) {
412                     reg = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
413                     if ((reg & PCI_COMMAND_MASTER_ENABLE) == 0)
414                               pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
415                                   reg | PCI_COMMAND_MASTER_ENABLE);
416           }
417 
418           if (!pmf_device_register(self, ppb_suspend, ppb_resume))
419                     aprint_error_dev(self, "couldn't establish power handler\n");
420 
421           /*
422            * Attach the PCI bus that hangs off of it.
423            *
424            * XXX Don't pass-through Memory Read Multiple.  Should we?
425            * XXX Consult the spec...
426            */
427           pba.pba_iot = pa->pa_iot;
428           pba.pba_memt = pa->pa_memt;
429           pba.pba_dmat = pa->pa_dmat;
430           pba.pba_dmat64 = pa->pa_dmat64;
431           pba.pba_pc = pc;
432           pba.pba_flags = pa->pa_flags & ~PCI_FLAGS_MRM_OKAY;
433           pba.pba_bus = PCI_BRIDGE_BUS_NUM_SECONDARY(busdata);
434           pba.pba_sub = PCI_BRIDGE_BUS_NUM_SUBORDINATE(busdata);
435           pba.pba_bridgetag = &sc->sc_tag;
436           pba.pba_intrswiz = pa->pa_intrswiz;
437           pba.pba_intrtag = pa->pa_intrtag;
438 
439           config_found(self, &pba, pcibusprint,
440               /*
441                * Forward along the device handle for the bridge to the
442                * downstream bus.
443                */
444               CFARGS(.devhandle = device_handle(self)));
445 }
446 
447 static int
ppbdetach(device_t self,int flags)448 ppbdetach(device_t self, int flags)
449 {
450 #ifdef PPB_USEINTR
451           struct ppb_softc *sc = device_private(self);
452           pcireg_t slcsr;
453 #endif
454           int rc;
455 
456           if ((rc = config_detach_children(self, flags)) != 0)
457                     return rc;
458 
459 #ifdef PPB_USEINTR
460           if (sc->sc_intrhand != NULL) {
461                     /* Detach event counters */
462                     evcnt_detach(&sc->sc_ev_intr);
463                     evcnt_detach(&sc->sc_ev_abp);
464                     evcnt_detach(&sc->sc_ev_pfd);
465                     evcnt_detach(&sc->sc_ev_msc);
466                     evcnt_detach(&sc->sc_ev_pdc);
467                     evcnt_detach(&sc->sc_ev_cc);
468                     evcnt_detach(&sc->sc_ev_lacs);
469 
470                     /* Clear any pending events and disable interrupt */
471                     slcsr = pci_conf_read(sc->sc_pc, sc->sc_tag,
472                         sc->sc_pciecapoff + PCIE_SLCSR);
473                     slcsr &= ~PCIE_SLCSR_ENABLE_MASK;
474                     pci_conf_write(sc->sc_pc, sc->sc_tag,
475                         sc->sc_pciecapoff + PCIE_SLCSR, slcsr);
476 
477                     /* Disestablish the interrupt handler */
478                     pci_intr_disestablish(sc->sc_pc, sc->sc_intrhand);
479                     pci_intr_release(sc->sc_pc, sc->sc_pihp, 1);
480           }
481 #endif
482 
483           pmf_device_deregister(self);
484           return 0;
485 }
486 
487 static bool
ppb_resume(device_t dv,const pmf_qual_t * qual)488 ppb_resume(device_t dv, const pmf_qual_t *qual)
489 {
490           struct ppb_softc *sc = device_private(dv);
491           int off;
492           pcireg_t val;
493 
494         for (off = 0x40; off <= 0xff; off += 4) {
495                     val = pci_conf_read(sc->sc_pc, sc->sc_tag, off);
496                     if (val != sc->sc_pciconfext[(off - 0x40) / 4])
497                               pci_conf_write(sc->sc_pc, sc->sc_tag, off,
498                                   sc->sc_pciconfext[(off - 0x40)/4]);
499           }
500 
501           return true;
502 }
503 
504 static bool
ppb_suspend(device_t dv,const pmf_qual_t * qual)505 ppb_suspend(device_t dv, const pmf_qual_t *qual)
506 {
507           struct ppb_softc *sc = device_private(dv);
508           int off;
509 
510           for (off = 0x40; off <= 0xff; off += 4)
511                     sc->sc_pciconfext[(off - 0x40) / 4] =
512                         pci_conf_read(sc->sc_pc, sc->sc_tag, off);
513 
514           return true;
515 }
516 
517 static void
ppbchilddet(device_t self,device_t child)518 ppbchilddet(device_t self, device_t child)
519 {
520           /* we keep no references to child devices, so do nothing */
521 }
522 
523 #ifdef PPB_USEINTR
524 static int
ppb_intr(void * arg)525 ppb_intr(void *arg)
526 {
527           struct ppb_softc *sc = arg;
528           device_t dev = sc->sc_dev;
529           pcireg_t reg;
530 
531           reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
532               sc->sc_pciecapoff + PCIE_SLCSR);
533 
534           /*
535            * Not me. This check is only required for INTx.
536            * ppb_intr() would be split into ppb_intr_legacy() and ppb_intr_msi()
537            */
538           if ((reg & PCIE_SLCSR_STATCHG_MASK) == 0)
539                     return 0;
540 
541           /* Clear interrupts. */
542           pci_conf_write(sc->sc_pc, sc->sc_tag,
543               sc->sc_pciecapoff + PCIE_SLCSR, reg);
544 
545           sc->sc_ev_intr.ev_count++;
546 
547           /* Attention Button Pressed */
548           if (reg & PCIE_SLCSR_ABP) {
549                     sc->sc_ev_abp.ev_count++;
550                     if (ppb_printevent)
551                               device_printf(dev, "Attention Button Pressed\n");
552           }
553 
554           /* Power Fault Detected */
555           if (reg & PCIE_SLCSR_PFD) {
556                     sc->sc_ev_pfd.ev_count++;
557                     if (ppb_printevent)
558                               device_printf(dev, "Power Fault Detected\n");
559           }
560 
561           /* MRL Sensor Changed */
562           if (reg & PCIE_SLCSR_MSC) {
563                     sc->sc_ev_msc.ev_count++;
564                     if (ppb_printevent)
565                               device_printf(dev, "MRL Sensor Changed\n");
566           }
567 
568           /* Presence Detect Changed */
569           if (reg & PCIE_SLCSR_PDC) {
570                     sc->sc_ev_pdc.ev_count++;
571                     if (ppb_printevent)
572                               device_printf(dev, "Presence Detect Changed\n");
573                     if (reg & PCIE_SLCSR_PDS) {
574                               /* XXX Insert */
575                     } else {
576                               /* XXX Remove */
577                     }
578           }
579 
580           /* Command Completed */
581           if (reg & PCIE_SLCSR_CC) {
582                     sc->sc_ev_cc.ev_count++;
583                     if (ppb_printevent)
584                               device_printf(dev, "Command Completed\n");
585           }
586 
587           /* Data Link Layer State Changed */
588           if (reg & PCIE_SLCSR_LACS) {
589                     sc->sc_ev_lacs.ev_count++;
590                     if (ppb_printevent)
591                               device_printf(dev, "Data Link Layer State Changed\n");
592           }
593 
594           return 1;
595 }
596 #endif /* PPB_USEINTR */
597