bge(4) one packet wedge
Gleb Smirnoff
glebius at FreeBSD.org
Thu Aug 24 13:16:41 UTC 2006
Here I have prepared a patch, that utilizes the
tag in status block on the chips that can do this.
It also moves some chip quirks startup code to a
separate function.
--
Totus tuus, Glebius.
GLEBIUS-RIPN GLEB-RIPE
-------------- next part --------------
Index: if_bge.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/bge/if_bge.c,v
retrieving revision 1.139
diff -u -p -r1.139 if_bge.c
--- if_bge.c 23 Aug 2006 11:32:54 -0000 1.139
+++ if_bge.c 24 Aug 2006 13:07:12 -0000
@@ -978,7 +978,7 @@ bge_chipinit(struct bge_softc *sc)
int i;
/* Set endian type before we access any non-PCI registers. */
- pci_write_config(sc->bge_dev, BGE_PCI_MISC_CTL, BGE_INIT, 4);
+ pci_write_config(sc->bge_dev, BGE_PCI_MISC_CTL, sc->bge_misc_ctl, 4);
/*
* Check the 'ROM failed' bit on the RX CPU to see if
@@ -1982,6 +1982,70 @@ bge_dma_alloc(device_t dev)
return (0);
}
+static void
+bge_recognize(struct bge_softc *sc)
+{
+ device_t dev = sc->bge_dev;
+ uint32_t misccfg;
+
+ /* Save ASIC rev. */
+ sc->bge_chipid =
+ pci_read_config(dev, BGE_PCI_MISC_CTL, 4) &
+ BGE_PCIMISCCTL_ASICREV;
+ sc->bge_asicrev = BGE_ASICREV(sc->bge_chipid);
+ sc->bge_chiprev = BGE_CHIPREV(sc->bge_chipid);
+
+ sc->bge_misc_ctl = (BGE_HIF_SWAP_OPTIONS |
+ BGE_PCIMISCCTL_CLEAR_INTA |
+ BGE_PCIMISCCTL_MASK_PCI_INTR |
+ BGE_PCIMISCCTL_INDIRECT_ACCESS);
+ sc->bge_hcc_mode = 0;
+
+ /*
+ * XXX: Broadcom Linux driver. Not in specs or eratta.
+ * PCI-Express?
+ */
+ if (BGE_IS_5705_OR_BEYOND(sc)) {
+ uint32_t v;
+
+ v = pci_read_config(dev, BGE_PCI_MSI_CAPID, 4);
+ if (((v >> 8) & 0xff) == BGE_PCIE_CAPID_REG) {
+ v = pci_read_config(dev, BGE_PCIE_CAPID_REG, 4);
+ if ((v & 0xff) == BGE_PCIE_CAPID)
+ sc->bge_flags |= BGE_FLAG_PCIE;
+ }
+ }
+
+ /*
+ * PCI-X?
+ */
+ if ((pci_read_config(sc->bge_dev, BGE_PCI_PCISTATE, 4) &
+ BGE_PCISTATE_PCI_BUSMODE) == 0)
+ sc->bge_flags |= BGE_FLAG_PCIX;
+
+ misccfg = CSR_READ_4(sc, BGE_MISC_CFG) & BGE_MISCCFG_BOARD_ID_MASK;
+ if (sc->bge_asicrev == BGE_ASICREV_BCM5705 &&
+ (misccfg == BGE_MISCCFG_BOARD_ID_5788 ||
+ misccfg == BGE_MISCCFG_BOARD_ID_5788M))
+ sc->bge_flags |= BGE_FLAG_5788;
+
+ if (sc->bge_chiprev != BGE_CHIPREV_5700_AX &&
+ sc->bge_chiprev != BGE_CHIPREV_5700_BX)
+ sc->bge_hcc_mode |= BGE_STATBLKSZ_32BYTE;
+
+ /*
+ * 5788 and 5700 does not support tagging the status block.
+ * This is workarounded in bge_tick_locked().
+ */
+ if (!(sc->bge_flags & BGE_FLAG_5788) &&
+ sc->bge_asicrev != BGE_ASICREV_BCM5700) {
+ sc->bge_flags |= BGE_FLAG_STATUSTAG;
+ sc->bge_hcc_mode |= (BGE_HCCMODE_CLRTICK_RXBD |
+ BGE_HCCMODE_CLRTICK_TXBD);
+ sc->bge_misc_ctl |= BGE_PCIMISCCTL_TAGGED_STATUS;
+ }
+}
+
static int
bge_attach(device_t dev)
{
@@ -2027,35 +2091,8 @@ bge_attach(device_t dev)
BGE_LOCK_INIT(sc, device_get_nameunit(dev));
- /* Save ASIC rev. */
-
- sc->bge_chipid =
- pci_read_config(dev, BGE_PCI_MISC_CTL, 4) &
- BGE_PCIMISCCTL_ASICREV;
- sc->bge_asicrev = BGE_ASICREV(sc->bge_chipid);
- sc->bge_chiprev = BGE_CHIPREV(sc->bge_chipid);
-
- /*
- * XXX: Broadcom Linux driver. Not in specs or eratta.
- * PCI-Express?
- */
- if (BGE_IS_5705_OR_BEYOND(sc)) {
- uint32_t v;
-
- v = pci_read_config(dev, BGE_PCI_MSI_CAPID, 4);
- if (((v >> 8) & 0xff) == BGE_PCIE_CAPID_REG) {
- v = pci_read_config(dev, BGE_PCIE_CAPID_REG, 4);
- if ((v & 0xff) == BGE_PCIE_CAPID)
- sc->bge_flags |= BGE_FLAG_PCIE;
- }
- }
-
- /*
- * PCI-X ?
- */
- if ((pci_read_config(sc->bge_dev, BGE_PCI_PCISTATE, 4) &
- BGE_PCISTATE_PCI_BUSMODE) == 0)
- sc->bge_flags |= BGE_FLAG_PCIX;
+ /* Fill in bge_flags, recognize features/bugs.*/
+ bge_recognize(sc);
/* Try to reset the chip. */
bge_reset(sc);
@@ -2684,16 +2721,13 @@ bge_poll(struct ifnet *ifp, enum poll_cm
static void
bge_intr(void *xsc)
{
- struct bge_softc *sc;
- struct ifnet *ifp;
+ struct bge_softc *sc = xsc;
+ struct ifnet *ifp = sc->bge_ifp;
+ struct bge_status_block *sblock = sc->bge_ldata.bge_status_block;
uint32_t statusword;
- sc = xsc;
-
BGE_LOCK(sc);
- ifp = sc->bge_ifp;
-
#ifdef DEVICE_POLLING
if (ifp->if_capenable & IFCAP_POLLING) {
BGE_UNLOCK(sc);
@@ -2701,6 +2735,15 @@ bge_intr(void *xsc)
}
#endif
+ if ((((sc->bge_flags & BGE_FLAG_STATUSTAG) &&
+ (sc->bge_last_tag == sblock->bge_tag)) ||
+ !(sblock->bge_status & BGE_STATUS_UPDATED)) &&
+ (pci_read_config(sc->bge_dev, BGE_PCI_PCISTATE, 4) &
+ BGE_PCISTATE_INTR_STATE)) {
+ /* Not our interrupt? */
+ BGE_UNLOCK(sc);
+ return;
+ }
/*
* Do the mandatory PCI flush as well as get the link status.
*/
@@ -2729,7 +2772,13 @@ bge_intr(void *xsc)
}
/* Re-enable interrupts. */
- CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0);
+ if (sc->bge_flags & BGE_FLAG_STATUSTAG) {
+ sc->bge_last_tag = sblock->bge_tag;
+ CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, (sc->bge_last_tag << 24));
+ } else {
+ sblock->bge_status &= ~BGE_STATUS_UPDATED;
+ CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0);
+ }
if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
@@ -2769,6 +2818,16 @@ bge_tick_locked(struct bge_softc *sc)
}
}
+ if (!(sc->bge_flags & BGE_FLAG_STATUSTAG)) {
+ struct bge_status_block *sblock = sc->bge_ldata.bge_status_block;
+
+ if (sblock->bge_status & BGE_STATUS_UPDATED)
+ BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_INTR_SET);
+ else
+ CSR_WRITE_4(sc, BGE_HCC_MODE, BGE_HCCMODE_ENABLE |
+ BGE_HCCMODE_COAL_NOW);
+ }
+
callout_reset(&sc->bge_stat_ch, hz, bge_tick, sc);
}
Index: if_bgereg.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/bge/if_bgereg.h,v
retrieving revision 1.52
diff -u -p -r1.52 if_bgereg.h
--- if_bgereg.h 23 Aug 2006 11:32:54 -0000 1.52
+++ if_bgereg.h 24 Aug 2006 13:06:05 -0000
@@ -205,6 +205,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_HIF_SWAP_OPTIONS (BGE_PCIMISCCTL_ENDIAN_WORDSWAP)
@@ -218,10 +219,6 @@
BGE_MODECTL_BYTESWAP_DATA|BGE_MODECTL_WORDSWAP_DATA
#endif
-#define BGE_INIT \
- (BGE_HIF_SWAP_OPTIONS|BGE_PCIMISCCTL_CLEAR_INTA| \
- BGE_PCIMISCCTL_MASK_PCI_INTR|BGE_PCIMISCCTL_INDIRECT_ACCESS)
-
#define BGE_CHIPID_TIGON_I 0x40000000
#define BGE_CHIPID_TIGON_II 0x60000000
#define BGE_CHIPID_BCM5700_A0 0x70000000
@@ -1190,6 +1187,8 @@
#define BGE_STATBLKSZ_FULL 0x00000000
#define BGE_STATBLKSZ_64BYTE 0x00000080
#define BGE_STATBLKSZ_32BYTE 0x00000100
+#define BGE_HCCMODE_CLRTICK_RXBD 0x00000200
+#define BGE_HCCMODE_CLRTICK_TXBD 0x00000400
/* Host coalescing status register */
#define BGE_HCCSTAT_ERROR 0x00000004
@@ -1684,6 +1683,9 @@
/* Misc. config register */
#define BGE_MISCCFG_RESET_CORE_CLOCKS 0x00000001
#define BGE_MISCCFG_TIMER_PRESCALER 0x000000FE
+#define BGE_MISCCFG_BOARD_ID_MASK 0x0001e000
+#define BGE_MISCCFG_BOARD_ID_5788 0x00010000
+#define BGE_MISCCFG_BOARD_ID_5788M 0x00018000
#define BGE_32BITTIME_66MHZ (0x41 << 1)
@@ -1932,7 +1934,10 @@ struct bge_sts_idx {
struct bge_status_block {
uint32_t bge_status;
- uint32_t bge_rsvd0;
+#define BGE_STATUS_UPDATED 0x00000001
+#define BGE_STATUS_LINKEV 0x00000002
+#define BGE_STATUS_ERROR 0x00000004
+ uint32_t bge_tag;
#if BYTE_ORDER == LITTLE_ENDIAN
uint16_t bge_rx_jumbo_cons_idx;
uint16_t bge_rx_std_cons_idx;
@@ -2451,11 +2456,14 @@ struct bge_softc {
#define BGE_FLAG_NO3LED 0x00000008
#define BGE_FLAG_PCIX 0x00000010
#define BGE_FLAG_PCIE 0x00000020
+#define BGE_FLAG_5788 0x00000040
+#define BGE_FLAG_STATUSTAG 0x00000080
uint32_t bge_chipid;
uint8_t bge_asicrev;
uint8_t bge_chiprev;
struct bge_ring_data bge_ldata; /* rings */
struct bge_chain_data bge_cdata; /* mbufs */
+ uint32_t bge_last_tag;
uint16_t bge_tx_saved_considx;
uint16_t bge_rx_saved_considx;
uint16_t bge_ev_saved_considx;
@@ -2474,6 +2482,9 @@ struct bge_softc {
int bge_link; /* link state */
int bge_link_evt; /* pending link event */
struct callout bge_stat_ch;
+ /* Masks/values for some registers. */
+ uint32_t bge_hcc_mode; /* BGE_HCC_MODE */
+ uint32_t bge_misc_ctl; /* BGE_PCI_MISC_CTL */
char *bge_vpd_prodname;
char *bge_vpd_readonly;
u_long bge_rx_discards;
More information about the freebsd-net
mailing list