Module Name: src Committed By: msaitoh Date: Sun May 17 12:06:26 UTC 2015
Modified Files: src/sys/dev/pci: if_bge.c if_bgereg.h if_bgevar.h Log Message: - Add MSI support. - Use tagged status function for 5717 and newer devices. 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. Same as other *BSDs. To generate a diff of this commit: cvs rdiff -u -r1.287 -r1.288 src/sys/dev/pci/if_bge.c cvs rdiff -u -r1.90 -r1.91 src/sys/dev/pci/if_bgereg.h cvs rdiff -u -r1.18 -r1.19 src/sys/dev/pci/if_bgevar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/if_bge.c diff -u src/sys/dev/pci/if_bge.c:1.287 src/sys/dev/pci/if_bge.c:1.288 --- src/sys/dev/pci/if_bge.c:1.287 Fri May 1 03:42:15 2015 +++ src/sys/dev/pci/if_bge.c Sun May 17 12:06:26 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_bge.c,v 1.287 2015/05/01 03:42:15 msaitoh Exp $ */ +/* $NetBSD: if_bge.c,v 1.288 2015/05/17 12:06:26 msaitoh Exp $ */ /* * Copyright (c) 2001 Wind River Systems @@ -79,7 +79,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_bge.c,v 1.287 2015/05/01 03:42:15 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_bge.c,v 1.288 2015/05/17 12:06:26 msaitoh Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -183,6 +183,7 @@ static int bge_rxthresh_nodenum; typedef int (*bge_eaddr_fcn_t)(struct bge_softc *, uint8_t[]); static uint32_t bge_chipid(const struct pci_attach_args *); +static int bge_can_use_msi(struct bge_softc *); static int bge_probe(device_t, cfdata_t, void *); static void bge_attach(device_t, device_t, void *); static int bge_detach(device_t, int); @@ -2254,12 +2255,15 @@ bge_phy_addr(struct bge_softc *sc) static int bge_chipinit(struct bge_softc *sc) { - uint32_t dma_rw_ctl, mode_ctl, reg; + uint32_t dma_rw_ctl, misc_ctl, mode_ctl, reg; int i; /* Set endianness before we access any non-PCI registers. */ + misc_ctl = BGE_INIT; + if (sc->bge_flags & BGEF_TAGGED_STATUS) + misc_ctl |= BGE_PCIMISCCTL_TAGGED_STATUS; pci_conf_write(sc->sc_pc, sc->sc_pcitag, BGE_PCI_MISC_CTL, - BGE_INIT); + misc_ctl); /* * Clear the MAC statistics block in the NIC's @@ -3276,6 +3280,34 @@ bge_chipid(const struct pci_attach_args } /* + * Return true if MSI can be used with this device. + */ +static 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 * that since the Broadcom controller contains VPD support, we @@ -3303,7 +3335,9 @@ bge_attach(device_t parent, device_t sel const struct bge_product *bp; const struct bge_revision *br; pci_chipset_tag_t pc; +#ifndef __HAVE_PCI_MSI_MSIX pci_intr_handle_t ih; +#endif const char *intrstr = NULL; uint32_t hwcfg, hwcfg2, hwcfg3, hwcfg4, hwcfg5; uint32_t command; @@ -3318,6 +3352,7 @@ bge_attach(device_t parent, device_t sel int capmask; int mii_flags; int map_flags; + int rv; char intrbuf[PCI_INTRSTR_LEN]; bp = bge_lookup(pa); @@ -3381,26 +3416,6 @@ bge_attach(device_t parent, device_t sel return; } - DPRINTFN(5, ("pci_intr_map\n")); - if (pci_intr_map(pa, &ih)) { - aprint_error_dev(sc->bge_dev, "couldn't map interrupt\n"); - return; - } - - DPRINTFN(5, ("pci_intr_string\n")); - intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); - - DPRINTFN(5, ("pci_intr_establish\n")); - sc->bge_intrhand = pci_intr_establish(pc, ih, IPL_NET, bge_intr, sc); - - if (sc->bge_intrhand == NULL) { - aprint_error_dev(sc->bge_dev, - "couldn't establish interrupt%s%s\n", - intrstr ? " at " : "", intrstr ? intrstr : ""); - return; - } - aprint_normal_dev(sc->bge_dev, "interrupting at %s\n", intrstr); - /* Save various chip information. */ sc->bge_chipid = bge_chipid(pa); sc->bge_phy_addr = bge_phy_addr(sc); @@ -3705,6 +3720,68 @@ bge_attach(device_t parent, device_t sel } } +#ifdef __HAVE_PCI_MSI_MSIX + DPRINTFN(5, ("pci_get_capability\n")); + /* Check MSI capability */ + if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSI, + &sc->bge_msicap, NULL) != 0) { + if (bge_can_use_msi(sc) != 0) + sc->bge_flags |= BGEF_MSI; + } + rv = -1; + if (((sc->bge_flags & BGEF_MSI) != 0) && (pci_msi_count(pa) > 0)) { + DPRINTFN(5, ("pci_msi_alloc\n")); + rv = pci_msi_alloc_exact(pa, &sc->bge_pihp, 1); + if (rv != 0) + sc->bge_flags &= ~BGEF_MSI; + } + if (rv != 0) { + DPRINTFN(5, ("pci_intx_alloc\n")); + if (pci_intx_alloc(pa, &sc->bge_pihp)) { + aprint_error_dev(self, "can't map interrupt\n"); + return; + } + sc->bge_flags &= ~BGEF_MSI; + } +#else /* !__HAVE_PCI_MSI_MSIX */ + DPRINTFN(5, ("pci_intr_map\n")); + if (pci_intr_map(pa, &ih)) { + aprint_error_dev(sc->bge_dev, "couldn't map interrupt\n"); + return; + } +#endif + +#ifdef __HAVE_PCI_MSI_MSIX + DPRINTFN(5, ("pci_intr_string\n")); + intrstr = pci_intr_string(pc, sc->bge_pihp[0], intrbuf, + sizeof(intrbuf)); + DPRINTFN(5, ("pci_intr_establish\n")); + sc->bge_intrhand = pci_intr_establish(pc, sc->bge_pihp[0], IPL_NET, + bge_intr, sc); +#else /* !__HAVE_PCI_MSI_MSIX */ + DPRINTFN(5, ("pci_intr_string\n")); + intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); + + DPRINTFN(5, ("pci_intr_establish\n")); + sc->bge_intrhand = pci_intr_establish(pc, ih, IPL_NET, bge_intr, sc); +#endif + + if (sc->bge_intrhand == NULL) { + aprint_error_dev(sc->bge_dev, + "couldn't establish interrupt%s%s\n", + intrstr ? " at " : "", intrstr ? intrstr : ""); + return; + } + aprint_normal_dev(sc->bge_dev, "interrupting at %s\n", intrstr); + + /* + * 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 & BGEF_MSI) + sc->bge_flags |= BGEF_TAGGED_STATUS; + /* * Reset NVRAM before bge_reset(). It's required to acquire NVRAM * lock in bge_reset(). @@ -4631,7 +4708,7 @@ bge_intr(void *xsc) { struct bge_softc *sc; struct ifnet *ifp; - uint32_t statusword; + uint32_t pcistate, statusword, statustag; uint32_t intrmask = BGE_PCISTATE_INTR_NOT_ACTIVE; sc = xsc; @@ -4646,6 +4723,7 @@ bge_intr(void *xsc) * Reading the PCI State register will confirm whether the * interrupt is ours and will flush the status block. */ + pcistate = CSR_READ_4(sc, BGE_PCI_PCISTATE); /* read status word from status block */ bus_dmamap_sync(sc->bge_dmatag, sc->bge_ring_map, @@ -4653,55 +4731,70 @@ bge_intr(void *xsc) sizeof (struct bge_status_block), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); statusword = sc->bge_rdata->bge_status_block.bge_status; + statustag = sc->bge_rdata->bge_status_block.bge_status_tag << 24; - if ((statusword & BGE_STATFLAG_UPDATED) || - (~CSR_READ_4(sc, BGE_PCI_PCISTATE) & intrmask)) { - /* Ack interrupt and stop others from occuring. */ - bge_writembx_flush(sc, BGE_MBX_IRQ0_LO, 1); + if (sc->bge_flags & BGEF_TAGGED_STATUS) { + if (sc->bge_lasttag == statustag && + (~pcistate & intrmask)) { + printf("[SP]"); + return (0); + } + sc->bge_lasttag = statustag; + } else { + if (!(statusword & BGE_STATFLAG_UPDATED) && + !(~pcistate & intrmask)) { + return (0); + } + statustag = 0; + } + /* Ack interrupt and stop others from occurring. */ + bge_writembx_flush(sc, BGE_MBX_IRQ0_LO, 1); + BGE_EVCNT_INCR(sc->bge_ev_intr); - BGE_EVCNT_INCR(sc->bge_ev_intr); + /* clear status word */ + sc->bge_rdata->bge_status_block.bge_status = 0; - /* clear status word */ - sc->bge_rdata->bge_status_block.bge_status = 0; + bus_dmamap_sync(sc->bge_dmatag, sc->bge_ring_map, + offsetof(struct bge_ring_data, bge_status_block), + sizeof (struct bge_status_block), + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5700 || - statusword & BGE_STATFLAG_LINKSTATE_CHANGED || - BGE_STS_BIT(sc, BGE_STS_LINK_EVT)) - bge_link_upd(sc); + if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5700 || + statusword & BGE_STATFLAG_LINKSTATE_CHANGED || + BGE_STS_BIT(sc, BGE_STS_LINK_EVT)) + bge_link_upd(sc); - if (ifp->if_flags & IFF_RUNNING) { - /* Check RX return ring producer/consumer */ - bge_rxeof(sc); + if (ifp->if_flags & IFF_RUNNING) { + /* Check RX return ring producer/consumer */ + bge_rxeof(sc); - /* Check TX ring producer/consumer */ - bge_txeof(sc); - } + /* Check TX ring producer/consumer */ + bge_txeof(sc); + } - if (sc->bge_pending_rxintr_change) { - uint32_t rx_ticks = sc->bge_rx_coal_ticks; - uint32_t rx_bds = sc->bge_rx_max_coal_bds; + if (sc->bge_pending_rxintr_change) { + uint32_t rx_ticks = sc->bge_rx_coal_ticks; + uint32_t rx_bds = sc->bge_rx_max_coal_bds; - CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS, rx_ticks); - DELAY(10); - (void)CSR_READ_4(sc, BGE_HCC_RX_COAL_TICKS); + CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS, rx_ticks); + DELAY(10); + (void)CSR_READ_4(sc, BGE_HCC_RX_COAL_TICKS); - CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS, rx_bds); - DELAY(10); - (void)CSR_READ_4(sc, BGE_HCC_RX_MAX_COAL_BDS); + CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS, rx_bds); + DELAY(10); + (void)CSR_READ_4(sc, BGE_HCC_RX_MAX_COAL_BDS); - sc->bge_pending_rxintr_change = 0; - } - bge_handle_events(sc); + sc->bge_pending_rxintr_change = 0; + } + bge_handle_events(sc); - /* Re-enable interrupts. */ - bge_writembx_flush(sc, BGE_MBX_IRQ0_LO, 0); + /* Re-enable interrupts. */ + bge_writembx_flush(sc, BGE_MBX_IRQ0_LO, statustag); - if (ifp->if_flags & IFF_RUNNING && !IFQ_IS_EMPTY(&ifp->if_snd)) - bge_start(ifp); + if (ifp->if_flags & IFF_RUNNING && !IFQ_IS_EMPTY(&ifp->if_snd)) + bge_start(ifp); - return 1; - } else - return 0; + return 1; } static void @@ -6112,6 +6205,8 @@ bge_debug_info(struct bge_softc *sc) printf(" - CPMU\n"); if (sc->bge_flags & BGEF_TSO) printf(" - TSO\n"); + if (sc->bge_flags & BGEF_TAGGED_STATUS) + printf(" - TAGGED_STATUS\n"); /* PHY related */ if (sc->bge_phy_flags & BGEPHYF_NO_3LED) Index: src/sys/dev/pci/if_bgereg.h diff -u src/sys/dev/pci/if_bgereg.h:1.90 src/sys/dev/pci/if_bgereg.h:1.91 --- src/sys/dev/pci/if_bgereg.h:1.90 Thu Apr 30 16:09:06 2015 +++ src/sys/dev/pci/if_bgereg.h Sun May 17 12:06:26 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_bgereg.h,v 1.90 2015/04/30 16:09:06 msaitoh Exp $ */ +/* $NetBSD: if_bgereg.h,v 1.91 2015/05/17 12:06:26 msaitoh Exp $ */ /* * Copyright (c) 2001 Wind River Systems * Copyright (c) 1997, 1998, 1999, 2001 @@ -260,6 +260,7 @@ #define BGE_PCIMISCCTL_CLOCKCTL_RW 0x00000020 #define BGE_PCIMISCCTL_REG_WORDSWAP 0x00000040 #define BGE_PCIMISCCTL_INDIRECT_ACCESS 0x00000080 +#define BGE_PCIMISCCTL_TAGGED_STATUS 0x00000200 #define BGE_PCIMISCCTL_ASICREV 0xFFFF0000 #define BGE_PCIMISCCTL_ASICREV_SHIFT 16 @@ -2298,7 +2299,7 @@ struct bge_sts_idx { struct bge_status_block { volatile u_int32_t bge_status; - volatile u_int32_t bge_rsvd0; + volatile u_int32_t bge_status_tag; #if BYTE_ORDER == BIG_ENDIAN volatile u_int16_t bge_rx_std_cons_idx; volatile u_int16_t bge_rx_jumbo_cons_idx; @@ -2617,7 +2618,7 @@ struct vpd_key { #define BGEF_FIBER_MII 0x00000004 #define BGEF_CPMU_PRESENT 0x00000008 #define BGEF_APE 0x00000010 -/* Reserved for BGEF_MSI 0x00000020 */ +#define BGEF_MSI 0x00000020 #define BGEF_PCIX 0x00000040 #define BGEF_PCIE 0x00000080 #define BGEF_TSO 0x00000100 @@ -2632,6 +2633,7 @@ struct vpd_key { #define BGEF_57765_FAMILY 0x00040000 #define BGEF_57765_PLUS 0x00080000 #define BGEF_40BIT_BUG 0x00100000 +#define BGEF_TAGGED_STATUS 0x00200000 #define BGEF_RX_ALIGNBUG 0x00800000 #define BGEF_TXRING_VALID 0x20000000 #define BGEF_RXRING_VALID 0x40000000 Index: src/sys/dev/pci/if_bgevar.h diff -u src/sys/dev/pci/if_bgevar.h:1.18 src/sys/dev/pci/if_bgevar.h:1.19 --- src/sys/dev/pci/if_bgevar.h:1.18 Tue Apr 14 20:32:36 2015 +++ src/sys/dev/pci/if_bgevar.h Sun May 17 12:06:26 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_bgevar.h,v 1.18 2015/04/14 20:32:36 riastradh Exp $ */ +/* $NetBSD: if_bgevar.h,v 1.19 2015/05/17 12:06:26 msaitoh Exp $ */ /* * Copyright (c) 2001 Wind River Systems * Copyright (c) 1997, 1998, 1999, 2001 @@ -266,6 +266,9 @@ struct bge_softc { bus_space_tag_t bge_apetag; bus_size_t bge_apesize; void *bge_intrhand; +#ifdef __HAVE_PCI_MSI_MSIX + pci_intr_handle_t *bge_pihp; +#endif pci_chipset_tag_t sc_pc; pcitag_t sc_pcitag; @@ -277,8 +280,10 @@ struct bge_softc { bus_dma_tag_t bge_dmatag; uint32_t bge_pcixcap; uint32_t bge_pciecap; + uint32_t bge_msicap; uint16_t bge_mps; int bge_expmrq; + uint32_t bge_lasttag; u_int32_t bge_mfw_flags; /* Management F/W flags */ #define BGE_MFW_ON_RXCPU 0x00000001 #define BGE_MFW_ON_APE 0x00000002