Expand the MSI support to cover most of the remaining bge(4) chipsets with the
authorbrad <brad@openbsd.org>
Mon, 30 Dec 2013 18:47:45 +0000 (18:47 +0000)
committerbrad <brad@openbsd.org>
Mon, 30 Dec 2013 18:47:45 +0000 (18:47 +0000)
exception being the BCM5714 family for now.

Tested on a variety of newer chipsets.

ok sthen@

sys/dev/pci/if_bge.c
sys/dev/pci/if_bgereg.h

index 199f30f..4c002f9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_bge.c,v 1.345 2013/12/28 03:34:54 deraadt Exp $    */
+/*     $OpenBSD: if_bge.c,v 1.346 2013/12/30 18:47:45 brad Exp $       */
 
 /*
  * Copyright (c) 2001 Wind River Systems
 #define ETHER_MIN_NOPAD                (ETHER_MIN_LEN - ETHER_CRC_LEN) /* i.e., 60 */
 
 const struct bge_revision * bge_lookup_rev(u_int32_t);
+int bge_can_use_msi(struct bge_softc *);
 int bge_probe(struct device *, void *, void *);
 void bge_attach(struct device *, struct device *, void *);
 int bge_activate(struct device *, int);
@@ -2435,6 +2436,32 @@ bge_lookup_rev(u_int32_t chipid)
        return (NULL);
 }
 
+int
+bge_can_use_msi(struct bge_softc *sc)
+{
+       int can_use_msi = 0;
+
+       switch (BGE_ASICREV(sc->bge_chipid)) {
+       case BGE_ASICREV_BCM5714_A0:
+       case BGE_ASICREV_BCM5714:
+               /*
+                * Apparently, MSI doesn't work when these chips are
+                * configured in single-port mode.
+                */
+               break;
+       case BGE_ASICREV_BCM5750:
+               if (BGE_CHIPREV(sc->bge_chipid) != BGE_CHIPREV_5750_AX &&
+                   BGE_CHIPREV(sc->bge_chipid) != BGE_CHIPREV_5750_BX)
+                       can_use_msi = 1;
+               break;
+       default:
+               if (BGE_IS_575X_PLUS(sc))
+                       can_use_msi = 1;
+       }
+
+       return (can_use_msi);
+}
+
 /*
  * Probe for a Broadcom chip. Check the PCI vendor and device IDs
  * against our list and return its name if we find a match. Note
@@ -2744,14 +2771,28 @@ bge_attach(struct device *parent, struct device *self, void *aux)
            BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM57780)
                sc->bge_flags |= BGE_CPMU_PRESENT;
 
+       if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSI,
+           &sc->bge_msicap, NULL)) {
+               if (bge_can_use_msi(sc) == 0)
+                       pa->pa_flags &= ~PCI_FLAGS_MSI_ENABLED;
+       }
+
        DPRINTFN(5, ("pci_intr_map\n"));
-       if (BGE_IS_5717_PLUS(sc) && pci_intr_map_msi(pa, &ih) == 0)
-               sc->bge_flags |= BGE_TAGGED_STATUS;
+       if (pci_intr_map_msi(pa, &ih) == 0)
+               sc->bge_flags |= BGE_MSI;
        else if (pci_intr_map(pa, &ih)) {
                printf(": couldn't map interrupt\n");
                goto fail_1;
        }
 
+       /*
+        * All controllers except BCM5700 supports tagged status but
+        * we use tagged status only for MSI case on BCM5717. Otherwise
+        * MSI on BCM5717 does not work.
+        */
+       if (BGE_IS_5717_PLUS(sc) && sc->bge_flags & BGE_MSI)
+               sc->bge_flags |= BGE_TAGGED_STATUS;
+
        DPRINTFN(5, ("pci_intr_string\n"));
        intrstr = pci_intr_string(pc, ih);
 
@@ -2945,12 +2986,9 @@ bge_attach(struct device *parent, struct device *self, void *aux)
        }
 
        /* Take advantage of single-shot MSI. */
-       if ((BGE_IS_5717_PLUS(sc) && sc->bge_flags & BGE_TAGGED_STATUS)) {
-               reg = CSR_READ_4(sc, BGE_MSI_MODE);
-               reg &= ~BGE_MSIMODE_ONE_SHOT_DISABLE;
-               reg |= BGE_MSIMODE_ENABLE;
-               CSR_WRITE_4(sc, BGE_MSI_MODE, reg);
-       }
+       if (BGE_IS_5755_PLUS(sc) && sc->bge_flags & BGE_MSI)
+               CSR_WRITE_4(sc, BGE_MSI_MODE, CSR_READ_4(sc, BGE_MSI_MODE) &
+                   ~BGE_MSIMODE_ONE_SHOT_DISABLE);
 
        /* Hookup IRQ last. */
        DPRINTFN(5, ("pci_intr_establish\n"));
@@ -3192,8 +3230,19 @@ bge_reset(struct bge_softc *sc)
        pci_conf_write(pa->pa_pc, pa->pa_tag, BGE_PCI_CACHESZ, cachesize);
        pci_conf_write(pa->pa_pc, pa->pa_tag, BGE_PCI_CMD, command);
 
-       /* Enable memory arbiter. */
+       /* Re-enable MSI, if necessary, and enable memory arbiter. */
        if (BGE_IS_5714_FAMILY(sc)) {
+               /* This chip disables MSI on reset. */
+               if (sc->bge_flags & BGE_MSI) {
+                       val = pci_conf_read(pa->pa_pc, pa->pa_tag,
+                           sc->bge_msicap + PCI_MSI_MC);
+                       pci_conf_write(pa->pa_pc, pa->pa_tag,
+                           sc->bge_msicap + PCI_MSI_MC,
+                           val | PCI_MSI_MC_MSIE);
+                       val = CSR_READ_4(sc, BGE_MSI_MODE);
+                       CSR_WRITE_4(sc, BGE_MSI_MODE,
+                           val | BGE_MSIMODE_ENABLE);
+               }
                val = CSR_READ_4(sc, BGE_MARB_MODE);
                CSR_WRITE_4(sc, BGE_MARB_MODE, BGE_MARBMODE_ENABLE | val);
        } else
index 61de08b..e94921e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_bgereg.h,v 1.117 2013/06/28 11:59:42 mikeb Exp $   */
+/*     $OpenBSD: if_bgereg.h,v 1.118 2013/12/30 18:47:45 brad Exp $    */
 
 /*
  * Copyright (c) 2001 Wind River Systems
 #define        BGE_MSIMODE_PCI_MSTR_ABRT_ATTN  0x00000008
 #define        BGE_MSIMODE_PCI_PERR_ATTN       0x00000010
 #define        BGE_MSIMODE_ONE_SHOT_DISABLE    0x00000020
+#define        BGE_MSIMODE_MULTIVEC_ENABLE     0x00000080
 
 /* MSI status register */
 #define        BGE_MSISTAT_PCI_TGT_ABRT_ATTN   0x00000004
@@ -2808,6 +2809,7 @@ struct bge_softc {
        struct mii_data         bge_mii;
        struct ifmedia          bge_ifmedia;    /* media info */
        u_int32_t               bge_expcap;
+       u_int32_t               bge_msicap;
        u_int32_t               bge_mps;
        u_int32_t               bge_expmrq;
        u_int32_t               bge_lasttag;
@@ -2843,6 +2845,7 @@ struct bge_softc {
 #define        BGE_APE                 0x10000000
 #define        BGE_CPMU_PRESENT        0x20000000
 #define        BGE_TAGGED_STATUS       0x40000000
+#define        BGE_MSI                 0x80000000
 
        bus_dma_tag_t           bge_dmatag;
        u_int32_t               bge_mfw_flags;  /* Management F/W flags */