Add support for the "CPUSaver" receive interrupt mitigating microcode
on the following PRO/100 chips: * i82558 step A4 * i82558 step B0 * i82559 step A0 * i82559S step A * i82550 * i82550 step C The interrupt delay is configurable on all microcodable chips. The maximum "bundle" size (packet count) is configurable on all but the i82558. The microcode is enabled by setting IFF_LINK0 on the interface. Derived from code in FreeBSD.
This commit is contained in:
parent
0acd189ee0
commit
60e2bbd09a
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: i82557.c,v 1.63 2002/04/04 23:15:43 thorpej Exp $ */
|
/* $NetBSD: i82557.c,v 1.64 2002/04/05 19:51:04 thorpej Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 1997, 1998, 1999, 2001 The NetBSD Foundation, Inc.
|
* Copyright (c) 1997, 1998, 1999, 2001 The NetBSD Foundation, Inc.
|
||||||
@ -73,7 +73,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: i82557.c,v 1.63 2002/04/04 23:15:43 thorpej Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: i82557.c,v 1.64 2002/04/05 19:51:04 thorpej Exp $");
|
||||||
|
|
||||||
#include "bpfilter.h"
|
#include "bpfilter.h"
|
||||||
#include "rnd.h"
|
#include "rnd.h"
|
||||||
@ -114,6 +114,8 @@ __KERNEL_RCSID(0, "$NetBSD: i82557.c,v 1.63 2002/04/04 23:15:43 thorpej Exp $");
|
|||||||
#include <dev/ic/i82557reg.h>
|
#include <dev/ic/i82557reg.h>
|
||||||
#include <dev/ic/i82557var.h>
|
#include <dev/ic/i82557var.h>
|
||||||
|
|
||||||
|
#include <dev/microcode/i8255x/rcvbundl.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE! On the Alpha, we have an alignment constraint. The
|
* NOTE! On the Alpha, we have an alignment constraint. The
|
||||||
* card DMAs the packet immediately following the RFA. However,
|
* card DMAs the packet immediately following the RFA. However,
|
||||||
@ -200,12 +202,19 @@ void fxp_eeprom_update_cksum(struct fxp_softc *);
|
|||||||
void fxp_get_info(struct fxp_softc *, u_int8_t *);
|
void fxp_get_info(struct fxp_softc *, u_int8_t *);
|
||||||
void fxp_tick(void *);
|
void fxp_tick(void *);
|
||||||
void fxp_mc_setup(struct fxp_softc *);
|
void fxp_mc_setup(struct fxp_softc *);
|
||||||
|
void fxp_load_ucode(struct fxp_softc *);
|
||||||
|
|
||||||
void fxp_shutdown(void *);
|
void fxp_shutdown(void *);
|
||||||
void fxp_power(int, void *);
|
void fxp_power(int, void *);
|
||||||
|
|
||||||
int fxp_copy_small = 0;
|
int fxp_copy_small = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variables for interrupt mitigating microcode.
|
||||||
|
*/
|
||||||
|
int fxp_int_delay = 1000; /* usec */
|
||||||
|
int fxp_bundle_max = 6; /* packets */
|
||||||
|
|
||||||
struct fxp_phytype {
|
struct fxp_phytype {
|
||||||
int fp_phy; /* type of PHY, -1 for MII at the end. */
|
int fp_phy; /* type of PHY, -1 for MII at the end. */
|
||||||
void (*fp_init)(struct fxp_softc *);
|
void (*fp_init)(struct fxp_softc *);
|
||||||
@ -1386,10 +1395,12 @@ fxp_stop(struct ifnet *ifp, int disable)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Issue software reset
|
* Issue software reset. This unloads any microcode that
|
||||||
|
* might already be loaded.
|
||||||
*/
|
*/
|
||||||
CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
|
sc->sc_flags &= ~FXPF_UCODE_LOADED;
|
||||||
DELAY(10);
|
CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SOFTWARE_RESET);
|
||||||
|
DELAY(50);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release any xmit buffers.
|
* Release any xmit buffers.
|
||||||
@ -1506,6 +1517,11 @@ fxp_init(struct ifnet *ifp)
|
|||||||
cbp = &sc->sc_control_data->fcd_configcb;
|
cbp = &sc->sc_control_data->fcd_configcb;
|
||||||
memset(cbp, 0, sizeof(struct fxp_cb_config));
|
memset(cbp, 0, sizeof(struct fxp_cb_config));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load microcode for this controller.
|
||||||
|
*/
|
||||||
|
fxp_load_ucode(sc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This copy is kind of disgusting, but there are a bunch of must be
|
* This copy is kind of disgusting, but there are a bunch of must be
|
||||||
* zero and must be one bits in this structure and this is the easiest
|
* zero and must be one bits in this structure and this is the easiest
|
||||||
@ -2038,6 +2054,121 @@ fxp_mc_setup(struct fxp_softc *sc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const uint32_t fxp_ucode_d101a[] = D101_A_RCVBUNDLE_UCODE;
|
||||||
|
static const uint32_t fxp_ucode_d101b0[] = D101_B0_RCVBUNDLE_UCODE;
|
||||||
|
static const uint32_t fxp_ucode_d101ma[] = D101M_B_RCVBUNDLE_UCODE;
|
||||||
|
static const uint32_t fxp_ucode_d101s[] = D101S_RCVBUNDLE_UCODE;
|
||||||
|
static const uint32_t fxp_ucode_d102[] = D102_B_RCVBUNDLE_UCODE;
|
||||||
|
static const uint32_t fxp_ucode_d102c[] = D102_C_RCVBUNDLE_UCODE;
|
||||||
|
|
||||||
|
#define UCODE(x) x, sizeof(x)
|
||||||
|
|
||||||
|
static const struct ucode {
|
||||||
|
uint32_t revision;
|
||||||
|
const uint32_t *ucode;
|
||||||
|
size_t length;
|
||||||
|
uint16_t int_delay_offset;
|
||||||
|
uint16_t bundle_max_offset;
|
||||||
|
} ucode_table[] = {
|
||||||
|
{ FXP_REV_82558_A4, UCODE(fxp_ucode_d101a),
|
||||||
|
D101_CPUSAVER_DWORD, 0 },
|
||||||
|
|
||||||
|
{ FXP_REV_82558_B0, UCODE(fxp_ucode_d101b0),
|
||||||
|
D101_CPUSAVER_DWORD, 0 },
|
||||||
|
|
||||||
|
{ FXP_REV_82559_A0, UCODE(fxp_ucode_d101ma),
|
||||||
|
D101M_CPUSAVER_DWORD, D101M_CPUSAVER_BUNDLE_MAX_DWORD },
|
||||||
|
|
||||||
|
{ FXP_REV_82559S_A, UCODE(fxp_ucode_d101s),
|
||||||
|
D101S_CPUSAVER_DWORD, D101S_CPUSAVER_BUNDLE_MAX_DWORD },
|
||||||
|
|
||||||
|
{ FXP_REV_82550, UCODE(fxp_ucode_d102),
|
||||||
|
D102_B_CPUSAVER_DWORD, D102_B_CPUSAVER_BUNDLE_MAX_DWORD },
|
||||||
|
|
||||||
|
{ FXP_REV_82550_C, UCODE(fxp_ucode_d102c),
|
||||||
|
D102_C_CPUSAVER_DWORD, D102_C_CPUSAVER_BUNDLE_MAX_DWORD },
|
||||||
|
|
||||||
|
{ 0, NULL, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
fxp_load_ucode(struct fxp_softc *sc)
|
||||||
|
{
|
||||||
|
const struct ucode *uc;
|
||||||
|
struct fxp_cb_ucode *cbp = &sc->sc_control_data->fcd_ucode;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
if (sc->sc_flags & FXPF_UCODE_LOADED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only load the uCode if the user has requested that
|
||||||
|
* we do so.
|
||||||
|
*/
|
||||||
|
if ((sc->sc_ethercom.ec_if.if_flags & IFF_LINK0) == 0) {
|
||||||
|
sc->sc_int_delay = 0;
|
||||||
|
sc->sc_bundle_max = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uc = ucode_table; uc->ucode != NULL; uc++) {
|
||||||
|
if (sc->sc_rev == uc->revision)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (uc->ucode == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* BIG ENDIAN: no need to swap to store 0 */
|
||||||
|
cbp->cb_status = 0;
|
||||||
|
cbp->cb_command = htole16(FXP_CB_COMMAND_UCODE | FXP_CB_COMMAND_EL);
|
||||||
|
cbp->link_addr = 0xffffffff; /* (no) next command */
|
||||||
|
memcpy((void *) cbp->ucode, uc->ucode, uc->length);
|
||||||
|
|
||||||
|
if (uc->int_delay_offset)
|
||||||
|
*(uint16_t *) &cbp->ucode[uc->int_delay_offset] =
|
||||||
|
htole16(fxp_int_delay + (fxp_int_delay / 2));
|
||||||
|
|
||||||
|
if (uc->bundle_max_offset)
|
||||||
|
*(uint16_t *) &cbp->ucode[uc->bundle_max_offset] =
|
||||||
|
htole16(fxp_bundle_max);
|
||||||
|
|
||||||
|
FXP_CDUCODESYNC(sc, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Download the uCode to the chip.
|
||||||
|
*/
|
||||||
|
fxp_scb_wait(sc);
|
||||||
|
CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, sc->sc_cddma + FXP_CDUCODEOFF);
|
||||||
|
fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START);
|
||||||
|
|
||||||
|
/* ...and wait for it to complete. */
|
||||||
|
count = 10000;
|
||||||
|
do {
|
||||||
|
FXP_CDUCODESYNC(sc,
|
||||||
|
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
|
||||||
|
DELAY(2);
|
||||||
|
} while ((le16toh(cbp->cb_status) & FXP_CB_STATUS_C) == 0 && --count);
|
||||||
|
if (count == 0) {
|
||||||
|
sc->sc_int_delay = 0;
|
||||||
|
sc->sc_bundle_max = 0;
|
||||||
|
printf("%s: timeout loading microcode\n",
|
||||||
|
sc->sc_dev.dv_xname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc->sc_int_delay != fxp_int_delay ||
|
||||||
|
sc->sc_bundle_max != fxp_bundle_max) {
|
||||||
|
sc->sc_int_delay = fxp_int_delay;
|
||||||
|
sc->sc_bundle_max = fxp_bundle_max;
|
||||||
|
printf("%s: Microcode loaded: int delay: %d usec, "
|
||||||
|
"max bundle: %d\n", sc->sc_dev.dv_xname,
|
||||||
|
sc->sc_int_delay,
|
||||||
|
uc->bundle_max_offset == 0 ? 0 : sc->sc_bundle_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->sc_flags |= FXPF_UCODE_LOADED;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fxp_enable(struct fxp_softc *sc)
|
fxp_enable(struct fxp_softc *sc)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: i82557var.h,v 1.26 2001/06/15 22:16:01 thorpej Exp $ */
|
/* $NetBSD: i82557var.h,v 1.27 2002/04/05 19:51:05 thorpej Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 1997, 1998, 1999, 2001 The NetBSD Foundation, Inc.
|
* Copyright (c) 1997, 1998, 1999, 2001 The NetBSD Foundation, Inc.
|
||||||
@ -126,6 +126,11 @@ struct fxp_control_data {
|
|||||||
*/
|
*/
|
||||||
struct fxp_cb_mcs fcd_mcscb;
|
struct fxp_cb_mcs fcd_mcscb;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The microcode setup CB.
|
||||||
|
*/
|
||||||
|
struct fxp_cb_ucode fcd_ucode;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The NIC statistics.
|
* The NIC statistics.
|
||||||
*/
|
*/
|
||||||
@ -138,6 +143,7 @@ struct fxp_control_data {
|
|||||||
#define FXP_CDCONFIGOFF FXP_CDOFF(fcd_configcb)
|
#define FXP_CDCONFIGOFF FXP_CDOFF(fcd_configcb)
|
||||||
#define FXP_CDIASOFF FXP_CDOFF(fcd_iascb)
|
#define FXP_CDIASOFF FXP_CDOFF(fcd_iascb)
|
||||||
#define FXP_CDMCSOFF FXP_CDOFF(fcd_mcscb)
|
#define FXP_CDMCSOFF FXP_CDOFF(fcd_mcscb)
|
||||||
|
#define FXP_CDUCODEOFF FXP_CDOFF(fcd_ucode)
|
||||||
#define FXP_CDSTATSOFF FXP_CDOFF(fcd_stats)
|
#define FXP_CDSTATSOFF FXP_CDOFF(fcd_stats)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -210,6 +216,10 @@ struct fxp_softc {
|
|||||||
#define FXPF_READ_ALIGN 0x0040 /* align read access w/ cacheline */
|
#define FXPF_READ_ALIGN 0x0040 /* align read access w/ cacheline */
|
||||||
#define FXPF_WRITE_ALIGN 0x0080 /* end write on cacheline */
|
#define FXPF_WRITE_ALIGN 0x0080 /* end write on cacheline */
|
||||||
#define FXPF_EXT_TXCB 0x0100 /* enable extended TxCB */
|
#define FXPF_EXT_TXCB 0x0100 /* enable extended TxCB */
|
||||||
|
#define FXPF_UCODE_LOADED 0x0200 /* microcode is loaded */
|
||||||
|
|
||||||
|
int sc_int_delay; /* interrupt delay */
|
||||||
|
int sc_bundle_max; /* max packet bundle */
|
||||||
|
|
||||||
int sc_txpending; /* number of TX requests pending */
|
int sc_txpending; /* number of TX requests pending */
|
||||||
int sc_txdirty; /* first dirty TX descriptor */
|
int sc_txdirty; /* first dirty TX descriptor */
|
||||||
@ -260,6 +270,10 @@ struct fxp_softc {
|
|||||||
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, \
|
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, \
|
||||||
FXP_CDMCSOFF, sizeof(struct fxp_cb_mcs), (ops))
|
FXP_CDMCSOFF, sizeof(struct fxp_cb_mcs), (ops))
|
||||||
|
|
||||||
|
#define FXP_CDUCODESYNC(sc, ops) \
|
||||||
|
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, \
|
||||||
|
FXP_CDUCODEOFF, sizeof(struct fxp_cb_ucode), (ops))
|
||||||
|
|
||||||
#define FXP_CDSTATSSYNC(sc, ops) \
|
#define FXP_CDSTATSSYNC(sc, ops) \
|
||||||
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, \
|
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, \
|
||||||
FXP_CDSTATSOFF, sizeof(struct fxp_stats), (ops))
|
FXP_CDSTATSOFF, sizeof(struct fxp_stats), (ops))
|
||||||
|
Loading…
Reference in New Issue
Block a user