version 1.113, 2007/07/09 21:00:55 |
version 1.113.8.3, 2008/03/23 02:04:48 |
|
|
/* $NetBSD$ */ |
/* if_sip.c,v 1.113.8.2 2008/01/09 01:53:49 matt Exp */ |
|
|
/*- |
/*- |
* Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. |
* Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. |
|
|
*/ |
*/ |
|
|
#include <sys/cdefs.h> |
#include <sys/cdefs.h> |
__KERNEL_RCSID(0, "$NetBSD$"); |
__KERNEL_RCSID(0, "if_sip.c,v 1.113.8.2 2008/01/09 01:53:49 matt Exp"); |
|
|
#include "bpfilter.h" |
#include "bpfilter.h" |
#include "rnd.h" |
#include "rnd.h" |
Line 112 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 112 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <net/bpf.h> |
#include <net/bpf.h> |
#endif |
#endif |
|
|
#include <machine/bus.h> |
#include <sys/bus.h> |
#include <machine/intr.h> |
#include <sys/intr.h> |
#include <machine/endian.h> |
#include <machine/endian.h> |
|
|
#include <dev/mii/mii.h> |
#include <dev/mii/mii.h> |
Line 126 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 126 __KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#include <dev/pci/if_sipreg.h> |
#include <dev/pci/if_sipreg.h> |
|
|
#ifdef DP83820 /* DP83820 Gigabit Ethernet */ |
|
#define SIP_DECL(x) __CONCAT(gsip_,x) |
|
#else /* SiS900 and DP83815 */ |
|
#define SIP_DECL(x) __CONCAT(sip_,x) |
|
#endif |
|
|
|
#define SIP_STR(x) __STRING(SIP_DECL(x)) |
|
|
|
/* |
/* |
* Transmit descriptor list size. This is arbitrary, but allocate |
* Transmit descriptor list size. This is arbitrary, but allocate |
* enough descriptors for 128 pending transmissions, and 8 segments |
* enough descriptors for 128 pending transmissions, and 8 segments |
Line 141 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 133 __KERNEL_RCSID(0, "$NetBSD$"); |
|
* |
* |
* This MUST work out to a power of 2. |
* This MUST work out to a power of 2. |
*/ |
*/ |
#ifdef DP83820 |
#define GSIP_NTXSEGS_ALLOC 16 |
#define SIP_NTXSEGS 64 |
#define SIP_NTXSEGS_ALLOC 8 |
#define SIP_NTXSEGS_ALLOC 16 |
|
#else |
|
#define SIP_NTXSEGS 16 |
|
#define SIP_NTXSEGS_ALLOC 8 |
|
#endif |
|
|
|
#define SIP_TXQUEUELEN 256 |
#define SIP_TXQUEUELEN 256 |
#define SIP_NTXDESC (SIP_TXQUEUELEN * SIP_NTXSEGS_ALLOC) |
#define MAX_SIP_NTXDESC \ |
#define SIP_NTXDESC_MASK (SIP_NTXDESC - 1) |
(SIP_TXQUEUELEN * MAX(SIP_NTXSEGS_ALLOC, GSIP_NTXSEGS_ALLOC)) |
#define SIP_NEXTTX(x) (((x) + 1) & SIP_NTXDESC_MASK) |
|
|
|
#if defined(DP83820) |
|
#define TX_DMAMAP_SIZE ETHER_MAX_LEN_JUMBO |
|
#else |
|
#define TX_DMAMAP_SIZE MCLBYTES |
|
#endif |
|
|
|
/* |
/* |
* Receive descriptor list size. We have one Rx buffer per incoming |
* Receive descriptor list size. We have one Rx buffer per incoming |
Line 170 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 150 __KERNEL_RCSID(0, "$NetBSD$"); |
|
* mbuf cluster). 256 receive buffers is only 51 maximum size packets, |
* mbuf cluster). 256 receive buffers is only 51 maximum size packets, |
* so we'd better be quick about handling receive interrupts. |
* so we'd better be quick about handling receive interrupts. |
*/ |
*/ |
#if defined(DP83820) |
#define GSIP_NRXDESC 256 |
#define SIP_NRXDESC 256 |
|
#else |
|
#define SIP_NRXDESC 128 |
#define SIP_NRXDESC 128 |
#endif /* DP83820 */ |
|
#define SIP_NRXDESC_MASK (SIP_NRXDESC - 1) |
#define MAX_SIP_NRXDESC MAX(GSIP_NRXDESC, SIP_NRXDESC) |
#define SIP_NEXTRX(x) (((x) + 1) & SIP_NRXDESC_MASK) |
|
|
|
/* |
/* |
* Control structures are DMA'd to the SiS900 chip. We allocate them in |
* Control structures are DMA'd to the SiS900 chip. We allocate them in |
Line 187 struct sip_control_data { |
|
Line 164 struct sip_control_data { |
|
/* |
/* |
* The transmit descriptors. |
* The transmit descriptors. |
*/ |
*/ |
struct sip_desc scd_txdescs[SIP_NTXDESC]; |
struct sip_desc scd_txdescs[MAX_SIP_NTXDESC]; |
|
|
/* |
/* |
* The receive descriptors. |
* The receive descriptors. |
*/ |
*/ |
struct sip_desc scd_rxdescs[SIP_NRXDESC]; |
struct sip_desc scd_rxdescs[MAX_SIP_NRXDESC]; |
}; |
}; |
|
|
#define SIP_CDOFF(x) offsetof(struct sip_control_data, x) |
#define SIP_CDOFF(x) offsetof(struct sip_control_data, x) |
Line 220 struct sip_rxsoft { |
|
Line 197 struct sip_rxsoft { |
|
bus_dmamap_t rxs_dmamap; /* our DMA map */ |
bus_dmamap_t rxs_dmamap; /* our DMA map */ |
}; |
}; |
|
|
|
enum sip_attach_stage { |
|
SIP_ATTACH_FIN = 0 |
|
, SIP_ATTACH_CREATE_RXMAP |
|
, SIP_ATTACH_CREATE_TXMAP |
|
, SIP_ATTACH_LOAD_MAP |
|
, SIP_ATTACH_CREATE_MAP |
|
, SIP_ATTACH_MAP_MEM |
|
, SIP_ATTACH_ALLOC_MEM |
|
, SIP_ATTACH_INTR |
|
, SIP_ATTACH_MAP |
|
}; |
|
|
/* |
/* |
* Software state per device. |
* Software state per device. |
*/ |
*/ |
Line 227 struct sip_softc { |
|
Line 216 struct sip_softc { |
|
struct device sc_dev; /* generic device information */ |
struct device sc_dev; /* generic device information */ |
bus_space_tag_t sc_st; /* bus space tag */ |
bus_space_tag_t sc_st; /* bus space tag */ |
bus_space_handle_t sc_sh; /* bus space handle */ |
bus_space_handle_t sc_sh; /* bus space handle */ |
|
bus_size_t sc_sz; /* bus space size */ |
bus_dma_tag_t sc_dmat; /* bus DMA tag */ |
bus_dma_tag_t sc_dmat; /* bus DMA tag */ |
|
pci_chipset_tag_t sc_pc; |
|
bus_dma_segment_t sc_seg; |
struct ethercom sc_ethercom; /* ethernet common data */ |
struct ethercom sc_ethercom; /* ethernet common data */ |
void *sc_sdhook; /* shutdown hook */ |
|
|
|
const struct sip_product *sc_model; /* which model are we? */ |
const struct sip_product *sc_model; /* which model are we? */ |
|
int sc_gigabit; /* 1: 83820, 0: other */ |
int sc_rev; /* chip revision */ |
int sc_rev; /* chip revision */ |
|
|
void *sc_ih; /* interrupt cookie */ |
void *sc_ih; /* interrupt cookie */ |
Line 247 struct sip_softc { |
|
Line 239 struct sip_softc { |
|
* Software state for transmit and receive descriptors. |
* Software state for transmit and receive descriptors. |
*/ |
*/ |
struct sip_txsoft sc_txsoft[SIP_TXQUEUELEN]; |
struct sip_txsoft sc_txsoft[SIP_TXQUEUELEN]; |
struct sip_rxsoft sc_rxsoft[SIP_NRXDESC]; |
struct sip_rxsoft sc_rxsoft[MAX_SIP_NRXDESC]; |
|
|
/* |
/* |
* Control data structures. |
* Control data structures. |
Line 268 struct sip_softc { |
|
Line 260 struct sip_softc { |
|
struct evcnt sc_ev_rxintr; /* Rx interrupts */ |
struct evcnt sc_ev_rxintr; /* Rx interrupts */ |
struct evcnt sc_ev_hiberr; /* HIBERR interrupts */ |
struct evcnt sc_ev_hiberr; /* HIBERR interrupts */ |
struct evcnt sc_ev_rxpause; /* PAUSE received */ |
struct evcnt sc_ev_rxpause; /* PAUSE received */ |
#ifdef DP83820 |
/* DP83820 only */ |
struct evcnt sc_ev_txpause; /* PAUSE transmitted */ |
struct evcnt sc_ev_txpause; /* PAUSE transmitted */ |
struct evcnt sc_ev_rxipsum; /* IP checksums checked in-bound */ |
struct evcnt sc_ev_rxipsum; /* IP checksums checked in-bound */ |
struct evcnt sc_ev_rxtcpsum; /* TCP checksums checked in-bound */ |
struct evcnt sc_ev_rxtcpsum; /* TCP checksums checked in-bound */ |
Line 276 struct sip_softc { |
|
Line 268 struct sip_softc { |
|
struct evcnt sc_ev_txipsum; /* IP checksums comp. out-bound */ |
struct evcnt sc_ev_txipsum; /* IP checksums comp. out-bound */ |
struct evcnt sc_ev_txtcpsum; /* TCP checksums comp. out-bound */ |
struct evcnt sc_ev_txtcpsum; /* TCP checksums comp. out-bound */ |
struct evcnt sc_ev_txudpsum; /* UDP checksums comp. out-bound */ |
struct evcnt sc_ev_txudpsum; /* UDP checksums comp. out-bound */ |
#endif /* DP83820 */ |
|
#endif /* SIP_EVENT_COUNTERS */ |
#endif /* SIP_EVENT_COUNTERS */ |
|
|
u_int32_t sc_txcfg; /* prototype TXCFG register */ |
u_int32_t sc_txcfg; /* prototype TXCFG register */ |
Line 286 struct sip_softc { |
|
Line 277 struct sip_softc { |
|
|
|
u_int32_t sc_cfg; /* prototype CFG register */ |
u_int32_t sc_cfg; /* prototype CFG register */ |
|
|
#ifdef DP83820 |
|
u_int32_t sc_gpior; /* prototype GPIOR register */ |
u_int32_t sc_gpior; /* prototype GPIOR register */ |
#endif /* DP83820 */ |
|
|
|
u_int32_t sc_tx_fill_thresh; /* transmit fill threshold */ |
u_int32_t sc_tx_fill_thresh; /* transmit fill threshold */ |
u_int32_t sc_tx_drain_thresh; /* transmit drain threshold */ |
u_int32_t sc_tx_drain_thresh; /* transmit drain threshold */ |
Line 296 struct sip_softc { |
|
Line 285 struct sip_softc { |
|
u_int32_t sc_rx_drain_thresh; /* receive drain threshold */ |
u_int32_t sc_rx_drain_thresh; /* receive drain threshold */ |
|
|
int sc_flowflags; /* 802.3x flow control flags */ |
int sc_flowflags; /* 802.3x flow control flags */ |
#ifdef DP83820 |
|
int sc_rx_flow_thresh; /* Rx FIFO threshold for flow control */ |
int sc_rx_flow_thresh; /* Rx FIFO threshold for flow control */ |
#else |
|
int sc_paused; /* paused indication */ |
int sc_paused; /* paused indication */ |
#endif |
|
|
|
int sc_txfree; /* number of free Tx descriptors */ |
int sc_txfree; /* number of free Tx descriptors */ |
int sc_txnext; /* next ready Tx descriptor */ |
int sc_txnext; /* next ready Tx descriptor */ |
Line 322 struct sip_softc { |
|
Line 308 struct sip_softc { |
|
short sc_if_flags; |
short sc_if_flags; |
|
|
int sc_rxptr; /* next ready Rx descriptor/descsoft */ |
int sc_rxptr; /* next ready Rx descriptor/descsoft */ |
#if defined(DP83820) |
|
int sc_rxdiscard; |
int sc_rxdiscard; |
int sc_rxlen; |
int sc_rxlen; |
struct mbuf *sc_rxhead; |
struct mbuf *sc_rxhead; |
struct mbuf *sc_rxtail; |
struct mbuf *sc_rxtail; |
struct mbuf **sc_rxtailp; |
struct mbuf **sc_rxtailp; |
#endif /* DP83820 */ |
|
|
int sc_ntxdesc; |
|
int sc_ntxdesc_mask; |
|
|
|
int sc_nrxdesc_mask; |
|
|
|
const struct sip_parm { |
|
const struct sip_regs { |
|
int r_rxcfg; |
|
int r_txcfg; |
|
} p_regs; |
|
|
|
const struct sip_bits { |
|
uint32_t b_txcfg_mxdma_8; |
|
uint32_t b_txcfg_mxdma_16; |
|
uint32_t b_txcfg_mxdma_32; |
|
uint32_t b_txcfg_mxdma_64; |
|
uint32_t b_txcfg_mxdma_128; |
|
uint32_t b_txcfg_mxdma_256; |
|
uint32_t b_txcfg_mxdma_512; |
|
uint32_t b_txcfg_flth_mask; |
|
uint32_t b_txcfg_drth_mask; |
|
|
|
uint32_t b_rxcfg_mxdma_8; |
|
uint32_t b_rxcfg_mxdma_16; |
|
uint32_t b_rxcfg_mxdma_32; |
|
uint32_t b_rxcfg_mxdma_64; |
|
uint32_t b_rxcfg_mxdma_128; |
|
uint32_t b_rxcfg_mxdma_256; |
|
uint32_t b_rxcfg_mxdma_512; |
|
|
|
uint32_t b_isr_txrcmp; |
|
uint32_t b_isr_rxrcmp; |
|
uint32_t b_isr_dperr; |
|
uint32_t b_isr_sserr; |
|
uint32_t b_isr_rmabt; |
|
uint32_t b_isr_rtabt; |
|
|
|
uint32_t b_cmdsts_size_mask; |
|
} p_bits; |
|
int p_filtmem; |
|
int p_rxbuf_len; |
|
bus_size_t p_tx_dmamap_size; |
|
int p_ntxsegs; |
|
int p_ntxsegs_alloc; |
|
int p_nrxdesc; |
|
} *sc_parm; |
|
|
|
void (*sc_rxintr)(struct sip_softc *); |
|
|
#if NRND > 0 |
#if NRND > 0 |
rndsource_element_t rnd_source; /* random source */ |
rndsource_element_t rnd_source; /* random source */ |
#endif |
#endif |
}; |
}; |
|
|
#ifdef DP83820 |
#define sc_bits sc_parm->p_bits |
#define SIP_RXCHAIN_RESET(sc) \ |
#define sc_regs sc_parm->p_regs |
do { \ |
|
(sc)->sc_rxtailp = &(sc)->sc_rxhead; \ |
static const struct sip_parm sip_parm = { |
*(sc)->sc_rxtailp = NULL; \ |
.p_filtmem = OTHER_RFCR_NS_RFADDR_FILTMEM |
(sc)->sc_rxlen = 0; \ |
, .p_rxbuf_len = MCLBYTES - 1 /* field width */ |
} while (/*CONSTCOND*/0) |
, .p_tx_dmamap_size = MCLBYTES |
|
, .p_ntxsegs = 16 |
#define SIP_RXCHAIN_LINK(sc, m) \ |
, .p_ntxsegs_alloc = SIP_NTXSEGS_ALLOC |
do { \ |
, .p_nrxdesc = SIP_NRXDESC |
*(sc)->sc_rxtailp = (sc)->sc_rxtail = (m); \ |
, .p_bits = { |
(sc)->sc_rxtailp = &(m)->m_next; \ |
.b_txcfg_mxdma_8 = 0x00200000 /* 8 bytes */ |
} while (/*CONSTCOND*/0) |
, .b_txcfg_mxdma_16 = 0x00300000 /* 16 bytes */ |
#endif /* DP83820 */ |
, .b_txcfg_mxdma_32 = 0x00400000 /* 32 bytes */ |
|
, .b_txcfg_mxdma_64 = 0x00500000 /* 64 bytes */ |
|
, .b_txcfg_mxdma_128 = 0x00600000 /* 128 bytes */ |
|
, .b_txcfg_mxdma_256 = 0x00700000 /* 256 bytes */ |
|
, .b_txcfg_mxdma_512 = 0x00000000 /* 512 bytes */ |
|
, .b_txcfg_flth_mask = 0x00003f00 /* Tx fill threshold */ |
|
, .b_txcfg_drth_mask = 0x0000003f /* Tx drain threshold */ |
|
|
|
, .b_rxcfg_mxdma_8 = 0x00200000 /* 8 bytes */ |
|
, .b_rxcfg_mxdma_16 = 0x00300000 /* 16 bytes */ |
|
, .b_rxcfg_mxdma_32 = 0x00400000 /* 32 bytes */ |
|
, .b_rxcfg_mxdma_64 = 0x00500000 /* 64 bytes */ |
|
, .b_rxcfg_mxdma_128 = 0x00600000 /* 128 bytes */ |
|
, .b_rxcfg_mxdma_256 = 0x00700000 /* 256 bytes */ |
|
, .b_rxcfg_mxdma_512 = 0x00000000 /* 512 bytes */ |
|
|
|
, .b_isr_txrcmp = 0x02000000 /* transmit reset complete */ |
|
, .b_isr_rxrcmp = 0x01000000 /* receive reset complete */ |
|
, .b_isr_dperr = 0x00800000 /* detected parity error */ |
|
, .b_isr_sserr = 0x00400000 /* signalled system error */ |
|
, .b_isr_rmabt = 0x00200000 /* received master abort */ |
|
, .b_isr_rtabt = 0x00100000 /* received target abort */ |
|
, .b_cmdsts_size_mask = OTHER_CMDSTS_SIZE_MASK |
|
} |
|
, .p_regs = { |
|
.r_rxcfg = OTHER_SIP_RXCFG, |
|
.r_txcfg = OTHER_SIP_TXCFG |
|
} |
|
}, gsip_parm = { |
|
.p_filtmem = DP83820_RFCR_NS_RFADDR_FILTMEM |
|
, .p_rxbuf_len = MCLBYTES - 8 |
|
, .p_tx_dmamap_size = ETHER_MAX_LEN_JUMBO |
|
, .p_ntxsegs = 64 |
|
, .p_ntxsegs_alloc = GSIP_NTXSEGS_ALLOC |
|
, .p_nrxdesc = GSIP_NRXDESC |
|
, .p_bits = { |
|
.b_txcfg_mxdma_8 = 0x00100000 /* 8 bytes */ |
|
, .b_txcfg_mxdma_16 = 0x00200000 /* 16 bytes */ |
|
, .b_txcfg_mxdma_32 = 0x00300000 /* 32 bytes */ |
|
, .b_txcfg_mxdma_64 = 0x00400000 /* 64 bytes */ |
|
, .b_txcfg_mxdma_128 = 0x00500000 /* 128 bytes */ |
|
, .b_txcfg_mxdma_256 = 0x00600000 /* 256 bytes */ |
|
, .b_txcfg_mxdma_512 = 0x00700000 /* 512 bytes */ |
|
, .b_txcfg_flth_mask = 0x0000ff00 /* Fx fill threshold */ |
|
, .b_txcfg_drth_mask = 0x000000ff /* Tx drain threshold */ |
|
|
|
, .b_rxcfg_mxdma_8 = 0x00100000 /* 8 bytes */ |
|
, .b_rxcfg_mxdma_16 = 0x00200000 /* 16 bytes */ |
|
, .b_rxcfg_mxdma_32 = 0x00300000 /* 32 bytes */ |
|
, .b_rxcfg_mxdma_64 = 0x00400000 /* 64 bytes */ |
|
, .b_rxcfg_mxdma_128 = 0x00500000 /* 128 bytes */ |
|
, .b_rxcfg_mxdma_256 = 0x00600000 /* 256 bytes */ |
|
, .b_rxcfg_mxdma_512 = 0x00700000 /* 512 bytes */ |
|
|
|
, .b_isr_txrcmp = 0x00400000 /* transmit reset complete */ |
|
, .b_isr_rxrcmp = 0x00200000 /* receive reset complete */ |
|
, .b_isr_dperr = 0x00100000 /* detected parity error */ |
|
, .b_isr_sserr = 0x00080000 /* signalled system error */ |
|
, .b_isr_rmabt = 0x00040000 /* received master abort */ |
|
, .b_isr_rtabt = 0x00020000 /* received target abort */ |
|
, .b_cmdsts_size_mask = DP83820_CMDSTS_SIZE_MASK |
|
} |
|
, .p_regs = { |
|
.r_rxcfg = DP83820_SIP_RXCFG, |
|
.r_txcfg = DP83820_SIP_TXCFG |
|
} |
|
}; |
|
|
|
static inline int |
|
sip_nexttx(const struct sip_softc *sc, int x) |
|
{ |
|
return (x + 1) & sc->sc_ntxdesc_mask; |
|
} |
|
|
|
static inline int |
|
sip_nextrx(const struct sip_softc *sc, int x) |
|
{ |
|
return (x + 1) & sc->sc_nrxdesc_mask; |
|
} |
|
|
|
/* 83820 only */ |
|
static inline void |
|
sip_rxchain_reset(struct sip_softc *sc) |
|
{ |
|
sc->sc_rxtailp = &sc->sc_rxhead; |
|
*sc->sc_rxtailp = NULL; |
|
sc->sc_rxlen = 0; |
|
} |
|
|
|
/* 83820 only */ |
|
static inline void |
|
sip_rxchain_link(struct sip_softc *sc, struct mbuf *m) |
|
{ |
|
*sc->sc_rxtailp = sc->sc_rxtail = m; |
|
sc->sc_rxtailp = &m->m_next; |
|
} |
|
|
#ifdef SIP_EVENT_COUNTERS |
#ifdef SIP_EVENT_COUNTERS |
#define SIP_EVCNT_INCR(ev) (ev)->ev_count++ |
#define SIP_EVCNT_INCR(ev) (ev)->ev_count++ |
|
|
#define SIP_CDTXADDR(sc, x) ((sc)->sc_cddma + SIP_CDTXOFF((x))) |
#define SIP_CDTXADDR(sc, x) ((sc)->sc_cddma + SIP_CDTXOFF((x))) |
#define SIP_CDRXADDR(sc, x) ((sc)->sc_cddma + SIP_CDRXOFF((x))) |
#define SIP_CDRXADDR(sc, x) ((sc)->sc_cddma + SIP_CDRXOFF((x))) |
|
|
#define SIP_CDTXSYNC(sc, x, n, ops) \ |
static inline void |
do { \ |
sip_cdtxsync(struct sip_softc *sc, const int x0, const int n0, const int ops) |
int __x, __n; \ |
{ |
\ |
int x, n; |
__x = (x); \ |
|
__n = (n); \ |
x = x0; |
\ |
n = n0; |
/* If it will wrap around, sync to the end of the ring. */ \ |
|
if ((__x + __n) > SIP_NTXDESC) { \ |
/* If it will wrap around, sync to the end of the ring. */ |
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cddmamap, \ |
if (x + n > sc->sc_ntxdesc) { |
SIP_CDTXOFF(__x), sizeof(struct sip_desc) * \ |
bus_dmamap_sync(sc->sc_dmat, sc->sc_cddmamap, |
(SIP_NTXDESC - __x), (ops)); \ |
SIP_CDTXOFF(x), sizeof(struct sip_desc) * |
__n -= (SIP_NTXDESC - __x); \ |
(sc->sc_ntxdesc - x), ops); |
__x = 0; \ |
n -= (sc->sc_ntxdesc - x); |
} \ |
x = 0; |
\ |
} |
/* Now sync whatever is left. */ \ |
|
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cddmamap, \ |
/* Now sync whatever is left. */ |
SIP_CDTXOFF(__x), sizeof(struct sip_desc) * __n, (ops)); \ |
bus_dmamap_sync(sc->sc_dmat, sc->sc_cddmamap, |
} while (0) |
SIP_CDTXOFF(x), sizeof(struct sip_desc) * n, ops); |
|
} |
#define SIP_CDRXSYNC(sc, x, ops) \ |
|
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cddmamap, \ |
|
SIP_CDRXOFF((x)), sizeof(struct sip_desc), (ops)) |
|
|
|
|
static inline void |
|
sip_cdrxsync(struct sip_softc *sc, int x, int ops) |
|
{ |
|
bus_dmamap_sync(sc->sc_dmat, sc->sc_cddmamap, |
|
SIP_CDRXOFF(x), sizeof(struct sip_desc), ops); |
|
} |
|
|
|
#if 0 |
#ifdef DP83820 |
#ifdef DP83820 |
#define SIP_INIT_RXDESC_EXTSTS __sipd->sipd_extsts = 0; |
u_int32_t sipd_bufptr; /* pointer to DMA segment */ |
#define SIP_RXBUF_LEN (MCLBYTES - 8) |
u_int32_t sipd_cmdsts; /* command/status word */ |
#else |
#else |
#define SIP_INIT_RXDESC_EXTSTS /* nothing */ |
u_int32_t sipd_cmdsts; /* command/status word */ |
#define SIP_RXBUF_LEN (MCLBYTES - 1) /* field width */ |
u_int32_t sipd_bufptr; /* pointer to DMA segment */ |
#endif |
#endif /* DP83820 */ |
#define SIP_INIT_RXDESC(sc, x) \ |
#endif /* 0 */ |
do { \ |
|
struct sip_rxsoft *__rxs = &(sc)->sc_rxsoft[(x)]; \ |
static inline volatile uint32_t * |
struct sip_desc *__sipd = &(sc)->sc_rxdescs[(x)]; \ |
sipd_cmdsts(struct sip_softc *sc, struct sip_desc *sipd) |
\ |
{ |
__sipd->sipd_link = \ |
return &sipd->sipd_cbs[(sc->sc_gigabit) ? 1 : 0]; |
htole32(SIP_CDRXADDR((sc), SIP_NEXTRX((x)))); \ |
} |
__sipd->sipd_bufptr = \ |
|
htole32(__rxs->rxs_dmamap->dm_segs[0].ds_addr); \ |
static inline volatile uint32_t * |
__sipd->sipd_cmdsts = htole32(CMDSTS_INTR | \ |
sipd_bufptr(struct sip_softc *sc, struct sip_desc *sipd) |
(SIP_RXBUF_LEN & CMDSTS_SIZE_MASK)); \ |
{ |
SIP_INIT_RXDESC_EXTSTS \ |
return &sipd->sipd_cbs[(sc->sc_gigabit) ? 0 : 1]; |
SIP_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \ |
} |
} while (0) |
|
|
static inline void |
|
sip_init_rxdesc(struct sip_softc *sc, int x) |
|
{ |
|
struct sip_rxsoft *rxs = &sc->sc_rxsoft[x]; |
|
struct sip_desc *sipd = &sc->sc_rxdescs[x]; |
|
|
|
sipd->sipd_link = htole32(SIP_CDRXADDR(sc, sip_nextrx(sc, x))); |
|
*sipd_bufptr(sc, sipd) = htole32(rxs->rxs_dmamap->dm_segs[0].ds_addr); |
|
*sipd_cmdsts(sc, sipd) = htole32(CMDSTS_INTR | |
|
(sc->sc_parm->p_rxbuf_len & sc->sc_bits.b_cmdsts_size_mask)); |
|
sipd->sipd_extsts = 0; |
|
sip_cdrxsync(sc, x, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
|
} |
|
|
#define SIP_CHIP_VERS(sc, v, p, r) \ |
#define SIP_CHIP_VERS(sc, v, p, r) \ |
((sc)->sc_model->sip_vendor == (v) && \ |
((sc)->sc_model->sip_vendor == (v) && \ |
|
|
((sc)->sc_model->sip_vendor == (v) && \ |
((sc)->sc_model->sip_vendor == (v) && \ |
(sc)->sc_model->sip_product == (p)) |
(sc)->sc_model->sip_product == (p)) |
|
|
#if !defined(DP83820) |
|
#define SIP_SIS900_REV(sc, rev) \ |
#define SIP_SIS900_REV(sc, rev) \ |
SIP_CHIP_VERS((sc), PCI_VENDOR_SIS, PCI_PRODUCT_SIS_900, (rev)) |
SIP_CHIP_VERS((sc), PCI_VENDOR_SIS, PCI_PRODUCT_SIS_900, (rev)) |
#endif |
|
|
|
#define SIP_TIMEOUT 1000 |
#define SIP_TIMEOUT 1000 |
|
|
static void SIP_DECL(start)(struct ifnet *); |
static void sipcom_start(struct ifnet *); |
static void SIP_DECL(watchdog)(struct ifnet *); |
static void sipcom_watchdog(struct ifnet *); |
static int SIP_DECL(ioctl)(struct ifnet *, u_long, void *); |
static int sipcom_ioctl(struct ifnet *, u_long, void *); |
static int SIP_DECL(init)(struct ifnet *); |
static int sipcom_init(struct ifnet *); |
static void SIP_DECL(stop)(struct ifnet *, int); |
static void sipcom_stop(struct ifnet *, int); |
|
|
static void SIP_DECL(shutdown)(void *); |
static bool sipcom_reset(struct sip_softc *); |
|
static void sipcom_rxdrain(struct sip_softc *); |
static void SIP_DECL(reset)(struct sip_softc *); |
static int sipcom_add_rxbuf(struct sip_softc *, int); |
static void SIP_DECL(rxdrain)(struct sip_softc *); |
static void sipcom_read_eeprom(struct sip_softc *, int, int, |
static int SIP_DECL(add_rxbuf)(struct sip_softc *, int); |
|
static void SIP_DECL(read_eeprom)(struct sip_softc *, int, int, |
|
u_int16_t *); |
u_int16_t *); |
static void SIP_DECL(tick)(void *); |
static void sipcom_tick(void *); |
|
|
#if !defined(DP83820) |
static void sipcom_sis900_set_filter(struct sip_softc *); |
static void SIP_DECL(sis900_set_filter)(struct sip_softc *); |
static void sipcom_dp83815_set_filter(struct sip_softc *); |
#endif /* ! DP83820 */ |
|
static void SIP_DECL(dp83815_set_filter)(struct sip_softc *); |
|
|
|
#if defined(DP83820) |
static void sipcom_dp83820_read_macaddr(struct sip_softc *, |
static void SIP_DECL(dp83820_read_macaddr)(struct sip_softc *, |
|
const struct pci_attach_args *, u_int8_t *); |
const struct pci_attach_args *, u_int8_t *); |
#else |
static void sipcom_sis900_eeprom_delay(struct sip_softc *sc); |
static void SIP_DECL(sis900_eeprom_delay)(struct sip_softc *sc); |
static void sipcom_sis900_read_macaddr(struct sip_softc *, |
static void SIP_DECL(sis900_read_macaddr)(struct sip_softc *, |
|
const struct pci_attach_args *, u_int8_t *); |
const struct pci_attach_args *, u_int8_t *); |
static void SIP_DECL(dp83815_read_macaddr)(struct sip_softc *, |
static void sipcom_dp83815_read_macaddr(struct sip_softc *, |
const struct pci_attach_args *, u_int8_t *); |
const struct pci_attach_args *, u_int8_t *); |
#endif /* DP83820 */ |
|
|
|
static int SIP_DECL(intr)(void *); |
static int sipcom_intr(void *); |
static void SIP_DECL(txintr)(struct sip_softc *); |
static void sipcom_txintr(struct sip_softc *); |
static void SIP_DECL(rxintr)(struct sip_softc *); |
static void sip_rxintr(struct sip_softc *); |
|
static void gsip_rxintr(struct sip_softc *); |
#if defined(DP83820) |
|
static int SIP_DECL(dp83820_mii_readreg)(struct device *, int, int); |
static int sipcom_dp83820_mii_readreg(device_t, int, int); |
static void SIP_DECL(dp83820_mii_writereg)(struct device *, int, int, int); |
static void sipcom_dp83820_mii_writereg(device_t, int, int, int); |
static void SIP_DECL(dp83820_mii_statchg)(struct device *); |
static void sipcom_dp83820_mii_statchg(device_t); |
#else |
|
static int SIP_DECL(sis900_mii_readreg)(struct device *, int, int); |
static int sipcom_sis900_mii_readreg(device_t, int, int); |
static void SIP_DECL(sis900_mii_writereg)(struct device *, int, int, int); |
static void sipcom_sis900_mii_writereg(device_t, int, int, int); |
static void SIP_DECL(sis900_mii_statchg)(struct device *); |
static void sipcom_sis900_mii_statchg(device_t); |
|
|
static int SIP_DECL(dp83815_mii_readreg)(struct device *, int, int); |
static int sipcom_dp83815_mii_readreg(device_t, int, int); |
static void SIP_DECL(dp83815_mii_writereg)(struct device *, int, int, int); |
static void sipcom_dp83815_mii_writereg(device_t, int, int, int); |
static void SIP_DECL(dp83815_mii_statchg)(struct device *); |
static void sipcom_dp83815_mii_statchg(device_t); |
#endif /* DP83820 */ |
|
|
static void sipcom_mediastatus(struct ifnet *, struct ifmediareq *); |
static int SIP_DECL(mediachange)(struct ifnet *); |
|
static void SIP_DECL(mediastatus)(struct ifnet *, struct ifmediareq *); |
static int sipcom_match(device_t, struct cfdata *, void *); |
|
static void sipcom_attach(device_t, device_t, void *); |
|
static void sipcom_do_detach(device_t, enum sip_attach_stage); |
|
static int sipcom_detach(device_t, int); |
|
static bool sipcom_resume(device_t PMF_FN_PROTO); |
|
static bool sipcom_suspend(device_t PMF_FN_PROTO); |
|
|
static int SIP_DECL(match)(struct device *, struct cfdata *, void *); |
int gsip_copy_small = 0; |
static void SIP_DECL(attach)(struct device *, struct device *, void *); |
int sip_copy_small = 0; |
|
|
int SIP_DECL(copy_small) = 0; |
|
|
|
#ifdef DP83820 |
|
CFATTACH_DECL(gsip, sizeof(struct sip_softc), |
CFATTACH_DECL(gsip, sizeof(struct sip_softc), |
gsip_match, gsip_attach, NULL, NULL); |
sipcom_match, sipcom_attach, sipcom_detach, NULL); |
#else |
|
CFATTACH_DECL(sip, sizeof(struct sip_softc), |
CFATTACH_DECL(sip, sizeof(struct sip_softc), |
sip_match, sip_attach, NULL, NULL); |
sipcom_match, sipcom_attach, sipcom_detach, NULL); |
#endif |
|
|
|
/* |
/* |
* Descriptions of the variants of the SiS900. |
* Descriptions of the variants of the SiS900. |
*/ |
*/ |
struct sip_variant { |
struct sip_variant { |
int (*sipv_mii_readreg)(struct device *, int, int); |
int (*sipv_mii_readreg)(device_t, int, int); |
void (*sipv_mii_writereg)(struct device *, int, int, int); |
void (*sipv_mii_writereg)(device_t, int, int, int); |
void (*sipv_mii_statchg)(struct device *); |
void (*sipv_mii_statchg)(device_t); |
void (*sipv_set_filter)(struct sip_softc *); |
void (*sipv_set_filter)(struct sip_softc *); |
void (*sipv_read_macaddr)(struct sip_softc *, |
void (*sipv_read_macaddr)(struct sip_softc *, |
const struct pci_attach_args *, u_int8_t *); |
const struct pci_attach_args *, u_int8_t *); |
}; |
}; |
|
|
static u_int32_t SIP_DECL(mii_bitbang_read)(struct device *); |
static u_int32_t sipcom_mii_bitbang_read(device_t); |
static void SIP_DECL(mii_bitbang_write)(struct device *, u_int32_t); |
static void sipcom_mii_bitbang_write(device_t, u_int32_t); |
|
|
static const struct mii_bitbang_ops SIP_DECL(mii_bitbang_ops) = { |
static const struct mii_bitbang_ops sipcom_mii_bitbang_ops = { |
SIP_DECL(mii_bitbang_read), |
sipcom_mii_bitbang_read, |
SIP_DECL(mii_bitbang_write), |
sipcom_mii_bitbang_write, |
{ |
{ |
EROMAR_MDIO, /* MII_BIT_MDO */ |
EROMAR_MDIO, /* MII_BIT_MDO */ |
EROMAR_MDIO, /* MII_BIT_MDI */ |
EROMAR_MDIO, /* MII_BIT_MDI */ |
Line 514 static const struct mii_bitbang_ops SIP_ |
|
Line 651 static const struct mii_bitbang_ops SIP_ |
|
} |
} |
}; |
}; |
|
|
#if defined(DP83820) |
static const struct sip_variant sipcom_variant_dp83820 = { |
static const struct sip_variant SIP_DECL(variant_dp83820) = { |
sipcom_dp83820_mii_readreg, |
SIP_DECL(dp83820_mii_readreg), |
sipcom_dp83820_mii_writereg, |
SIP_DECL(dp83820_mii_writereg), |
sipcom_dp83820_mii_statchg, |
SIP_DECL(dp83820_mii_statchg), |
sipcom_dp83815_set_filter, |
SIP_DECL(dp83815_set_filter), |
sipcom_dp83820_read_macaddr, |
SIP_DECL(dp83820_read_macaddr), |
|
}; |
}; |
#else |
|
static const struct sip_variant SIP_DECL(variant_sis900) = { |
static const struct sip_variant sipcom_variant_sis900 = { |
SIP_DECL(sis900_mii_readreg), |
sipcom_sis900_mii_readreg, |
SIP_DECL(sis900_mii_writereg), |
sipcom_sis900_mii_writereg, |
SIP_DECL(sis900_mii_statchg), |
sipcom_sis900_mii_statchg, |
SIP_DECL(sis900_set_filter), |
sipcom_sis900_set_filter, |
SIP_DECL(sis900_read_macaddr), |
sipcom_sis900_read_macaddr, |
}; |
}; |
|
|
static const struct sip_variant SIP_DECL(variant_dp83815) = { |
static const struct sip_variant sipcom_variant_dp83815 = { |
SIP_DECL(dp83815_mii_readreg), |
sipcom_dp83815_mii_readreg, |
SIP_DECL(dp83815_mii_writereg), |
sipcom_dp83815_mii_writereg, |
SIP_DECL(dp83815_mii_statchg), |
sipcom_dp83815_mii_statchg, |
SIP_DECL(dp83815_set_filter), |
sipcom_dp83815_set_filter, |
SIP_DECL(dp83815_read_macaddr), |
sipcom_dp83815_read_macaddr, |
}; |
}; |
#endif /* DP83820 */ |
|
|
|
/* |
/* |
* Devices supported by this driver. |
* Devices supported by this driver. |
Line 548 static const struct sip_product { |
|
Line 684 static const struct sip_product { |
|
pci_product_id_t sip_product; |
pci_product_id_t sip_product; |
const char *sip_name; |
const char *sip_name; |
const struct sip_variant *sip_variant; |
const struct sip_variant *sip_variant; |
} SIP_DECL(products)[] = { |
int sip_gigabit; |
#if defined(DP83820) |
} sipcom_products[] = { |
{ PCI_VENDOR_NS, PCI_PRODUCT_NS_DP83820, |
{ PCI_VENDOR_NS, PCI_PRODUCT_NS_DP83820, |
"NatSemi DP83820 Gigabit Ethernet", |
"NatSemi DP83820 Gigabit Ethernet", |
&SIP_DECL(variant_dp83820) }, |
&sipcom_variant_dp83820, 1 }, |
#else |
|
{ PCI_VENDOR_SIS, PCI_PRODUCT_SIS_900, |
{ PCI_VENDOR_SIS, PCI_PRODUCT_SIS_900, |
"SiS 900 10/100 Ethernet", |
"SiS 900 10/100 Ethernet", |
&SIP_DECL(variant_sis900) }, |
&sipcom_variant_sis900, 0 }, |
{ PCI_VENDOR_SIS, PCI_PRODUCT_SIS_7016, |
{ PCI_VENDOR_SIS, PCI_PRODUCT_SIS_7016, |
"SiS 7016 10/100 Ethernet", |
"SiS 7016 10/100 Ethernet", |
&SIP_DECL(variant_sis900) }, |
&sipcom_variant_sis900, 0 }, |
|
|
{ PCI_VENDOR_NS, PCI_PRODUCT_NS_DP83815, |
{ PCI_VENDOR_NS, PCI_PRODUCT_NS_DP83815, |
"NatSemi DP83815 10/100 Ethernet", |
"NatSemi DP83815 10/100 Ethernet", |
&SIP_DECL(variant_dp83815) }, |
&sipcom_variant_dp83815, 0 }, |
#endif /* DP83820 */ |
|
|
|
{ 0, 0, |
{ 0, 0, |
NULL, |
NULL, |
NULL }, |
NULL, 0 }, |
}; |
}; |
|
|
static const struct sip_product * |
static const struct sip_product * |
SIP_DECL(lookup)(const struct pci_attach_args *pa) |
sipcom_lookup(const struct pci_attach_args *pa, bool gigabit) |
{ |
{ |
const struct sip_product *sip; |
const struct sip_product *sip; |
|
|
for (sip = SIP_DECL(products); sip->sip_name != NULL; sip++) { |
for (sip = sipcom_products; sip->sip_name != NULL; sip++) { |
if (PCI_VENDOR(pa->pa_id) == sip->sip_vendor && |
if (PCI_VENDOR(pa->pa_id) == sip->sip_vendor && |
PCI_PRODUCT(pa->pa_id) == sip->sip_product) |
PCI_PRODUCT(pa->pa_id) == sip->sip_product && |
return (sip); |
sip->sip_gigabit == gigabit) |
|
return sip; |
} |
} |
return (NULL); |
return NULL; |
} |
} |
|
|
#ifdef DP83820 |
|
/* |
/* |
* I really hate stupid hardware vendors. There's a bit in the EEPROM |
* I really hate stupid hardware vendors. There's a bit in the EEPROM |
* which indicates if the card can do 64-bit data transfers. Unfortunately, |
* which indicates if the card can do 64-bit data transfers. Unfortunately, |
Line 601 SIP_DECL(lookup)(const struct pci_attach |
|
Line 735 SIP_DECL(lookup)(const struct pci_attach |
|
* June 30, 2002 |
* June 30, 2002 |
*/ |
*/ |
static int |
static int |
SIP_DECL(check_64bit)(const struct pci_attach_args *pa) |
sipcom_check_64bit(const struct pci_attach_args *pa) |
{ |
{ |
static const struct { |
static const struct { |
pci_vendor_id_t c64_vendor; |
pci_vendor_id_t c64_vendor; |
Line 634 SIP_DECL(check_64bit)(const struct pci_a |
|
Line 768 SIP_DECL(check_64bit)(const struct pci_a |
|
|
|
return (0); |
return (0); |
} |
} |
#endif /* DP83820 */ |
|
|
|
static int |
static int |
SIP_DECL(match)(struct device *parent, struct cfdata *cf, |
sipcom_match(device_t parent, struct cfdata *cf, void *aux) |
void *aux) |
|
{ |
{ |
struct pci_attach_args *pa = aux; |
struct pci_attach_args *pa = aux; |
|
|
if (SIP_DECL(lookup)(pa) != NULL) |
if (sipcom_lookup(pa, strcmp(cf->cf_name, "gsip") == 0) != NULL) |
return (1); |
return 1; |
|
|
return (0); |
return 0; |
} |
} |
|
|
static void |
static void |
SIP_DECL(attach)(struct device *parent, struct device *self, void *aux) |
sipcom_dp83820_attach(struct sip_softc *sc, struct pci_attach_args *pa) |
{ |
{ |
struct sip_softc *sc = (struct sip_softc *) self; |
u_int32_t reg; |
|
int i; |
|
|
|
/* |
|
* Cause the chip to load configuration data from the EEPROM. |
|
*/ |
|
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_PTSCR, PTSCR_EELOAD_EN); |
|
for (i = 0; i < 10000; i++) { |
|
delay(10); |
|
if ((bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_PTSCR) & |
|
PTSCR_EELOAD_EN) == 0) |
|
break; |
|
} |
|
if (bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_PTSCR) & |
|
PTSCR_EELOAD_EN) { |
|
printf("%s: timeout loading configuration from EEPROM\n", |
|
sc->sc_dev.dv_xname); |
|
return; |
|
} |
|
|
|
sc->sc_gpior = bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_GPIOR); |
|
|
|
reg = bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_CFG); |
|
if (reg & CFG_PCI64_DET) { |
|
printf("%s: 64-bit PCI slot detected", sc->sc_dev.dv_xname); |
|
/* |
|
* Check to see if this card is 64-bit. If so, enable 64-bit |
|
* data transfers. |
|
* |
|
* We can't use the DATA64_EN bit in the EEPROM, because |
|
* vendors of 32-bit cards fail to clear that bit in many |
|
* cases (yet the card still detects that it's in a 64-bit |
|
* slot; go figure). |
|
*/ |
|
if (sipcom_check_64bit(pa)) { |
|
sc->sc_cfg |= CFG_DATA64_EN; |
|
printf(", using 64-bit data transfers"); |
|
} |
|
printf("\n"); |
|
} |
|
|
|
/* |
|
* XXX Need some PCI flags indicating support for |
|
* XXX 64-bit addressing. |
|
*/ |
|
#if 0 |
|
if (reg & CFG_M64ADDR) |
|
sc->sc_cfg |= CFG_M64ADDR; |
|
if (reg & CFG_T64ADDR) |
|
sc->sc_cfg |= CFG_T64ADDR; |
|
#endif |
|
|
|
if (reg & (CFG_TBI_EN|CFG_EXT_125)) { |
|
const char *sep = ""; |
|
printf("%s: using ", sc->sc_dev.dv_xname); |
|
if (reg & CFG_EXT_125) { |
|
sc->sc_cfg |= CFG_EXT_125; |
|
printf("%s125MHz clock", sep); |
|
sep = ", "; |
|
} |
|
if (reg & CFG_TBI_EN) { |
|
sc->sc_cfg |= CFG_TBI_EN; |
|
printf("%sten-bit interface", sep); |
|
sep = ", "; |
|
} |
|
printf("\n"); |
|
} |
|
if ((pa->pa_flags & PCI_FLAGS_MRM_OKAY) == 0 || |
|
(reg & CFG_MRM_DIS) != 0) |
|
sc->sc_cfg |= CFG_MRM_DIS; |
|
if ((pa->pa_flags & PCI_FLAGS_MWI_OKAY) == 0 || |
|
(reg & CFG_MWI_DIS) != 0) |
|
sc->sc_cfg |= CFG_MWI_DIS; |
|
|
|
/* |
|
* Use the extended descriptor format on the DP83820. This |
|
* gives us an interface to VLAN tagging and IPv4/TCP/UDP |
|
* checksumming. |
|
*/ |
|
sc->sc_cfg |= CFG_EXTSTS_EN; |
|
} |
|
|
|
static int |
|
sipcom_detach(device_t self, int flags) |
|
{ |
|
int s; |
|
|
|
s = splnet(); |
|
sipcom_do_detach(self, SIP_ATTACH_FIN); |
|
splx(s); |
|
|
|
return 0; |
|
} |
|
|
|
static void |
|
sipcom_do_detach(device_t self, enum sip_attach_stage stage) |
|
{ |
|
int i; |
|
struct sip_softc *sc = device_private(self); |
|
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
|
|
|
/* |
|
* Free any resources we've allocated during attach. |
|
* Do this in reverse order and fall through. |
|
*/ |
|
switch (stage) { |
|
case SIP_ATTACH_FIN: |
|
sipcom_stop(ifp, 1); |
|
pmf_device_deregister(self); |
|
#ifdef SIP_EVENT_COUNTERS |
|
/* |
|
* Attach event counters. |
|
*/ |
|
evcnt_detach(&sc->sc_ev_txforceintr); |
|
evcnt_detach(&sc->sc_ev_txdstall); |
|
evcnt_detach(&sc->sc_ev_txsstall); |
|
evcnt_detach(&sc->sc_ev_hiberr); |
|
evcnt_detach(&sc->sc_ev_rxintr); |
|
evcnt_detach(&sc->sc_ev_txiintr); |
|
evcnt_detach(&sc->sc_ev_txdintr); |
|
if (!sc->sc_gigabit) { |
|
evcnt_detach(&sc->sc_ev_rxpause); |
|
} else { |
|
evcnt_detach(&sc->sc_ev_txudpsum); |
|
evcnt_detach(&sc->sc_ev_txtcpsum); |
|
evcnt_detach(&sc->sc_ev_txipsum); |
|
evcnt_detach(&sc->sc_ev_rxudpsum); |
|
evcnt_detach(&sc->sc_ev_rxtcpsum); |
|
evcnt_detach(&sc->sc_ev_rxipsum); |
|
evcnt_detach(&sc->sc_ev_txpause); |
|
evcnt_detach(&sc->sc_ev_rxpause); |
|
} |
|
#endif /* SIP_EVENT_COUNTERS */ |
|
|
|
#if NRND > 0 |
|
rnd_detach_source(&sc->rnd_source); |
|
#endif |
|
|
|
ether_ifdetach(ifp); |
|
if_detach(ifp); |
|
mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY); |
|
|
|
/*FALLTHROUGH*/ |
|
case SIP_ATTACH_CREATE_RXMAP: |
|
for (i = 0; i < sc->sc_parm->p_nrxdesc; i++) { |
|
if (sc->sc_rxsoft[i].rxs_dmamap != NULL) |
|
bus_dmamap_destroy(sc->sc_dmat, |
|
sc->sc_rxsoft[i].rxs_dmamap); |
|
} |
|
/*FALLTHROUGH*/ |
|
case SIP_ATTACH_CREATE_TXMAP: |
|
for (i = 0; i < SIP_TXQUEUELEN; i++) { |
|
if (sc->sc_txsoft[i].txs_dmamap != NULL) |
|
bus_dmamap_destroy(sc->sc_dmat, |
|
sc->sc_txsoft[i].txs_dmamap); |
|
} |
|
/*FALLTHROUGH*/ |
|
case SIP_ATTACH_LOAD_MAP: |
|
bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap); |
|
/*FALLTHROUGH*/ |
|
case SIP_ATTACH_CREATE_MAP: |
|
bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap); |
|
/*FALLTHROUGH*/ |
|
case SIP_ATTACH_MAP_MEM: |
|
bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_control_data, |
|
sizeof(struct sip_control_data)); |
|
/*FALLTHROUGH*/ |
|
case SIP_ATTACH_ALLOC_MEM: |
|
bus_dmamem_free(sc->sc_dmat, &sc->sc_seg, 1); |
|
/* FALLTHROUGH*/ |
|
case SIP_ATTACH_INTR: |
|
pci_intr_disestablish(sc->sc_pc, sc->sc_ih); |
|
/* FALLTHROUGH*/ |
|
case SIP_ATTACH_MAP: |
|
bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_sz); |
|
break; |
|
default: |
|
break; |
|
} |
|
return; |
|
} |
|
|
|
static bool |
|
sipcom_resume(device_t self PMF_FN_ARGS) |
|
{ |
|
struct sip_softc *sc = device_private(self); |
|
|
|
return sipcom_reset(sc); |
|
} |
|
|
|
static bool |
|
sipcom_suspend(device_t self PMF_FN_ARGS) |
|
{ |
|
struct sip_softc *sc = device_private(self); |
|
|
|
sipcom_rxdrain(sc); |
|
return true; |
|
} |
|
|
|
static void |
|
sipcom_attach(device_t parent, device_t self, void *aux) |
|
{ |
|
struct sip_softc *sc = device_private(self); |
struct pci_attach_args *pa = aux; |
struct pci_attach_args *pa = aux; |
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
pci_chipset_tag_t pc = pa->pa_pc; |
pci_chipset_tag_t pc = pa->pa_pc; |
Line 659 SIP_DECL(attach)(struct device *parent, |
|
Line 993 SIP_DECL(attach)(struct device *parent, |
|
const char *intrstr = NULL; |
const char *intrstr = NULL; |
bus_space_tag_t iot, memt; |
bus_space_tag_t iot, memt; |
bus_space_handle_t ioh, memh; |
bus_space_handle_t ioh, memh; |
bus_dma_segment_t seg; |
bus_size_t iosz, memsz; |
int ioh_valid, memh_valid; |
int ioh_valid, memh_valid; |
int i, rseg, error; |
int i, rseg, error; |
const struct sip_product *sip; |
const struct sip_product *sip; |
u_int8_t enaddr[ETHER_ADDR_LEN]; |
u_int8_t enaddr[ETHER_ADDR_LEN]; |
pcireg_t pmreg; |
pcireg_t pmreg; |
#ifdef DP83820 |
|
pcireg_t memtype; |
pcireg_t memtype; |
u_int32_t reg; |
bus_size_t tx_dmamap_size; |
#endif /* DP83820 */ |
int ntxsegs_alloc; |
|
cfdata_t cf = device_cfdata(self); |
|
|
callout_init(&sc->sc_tick_ch, 0); |
callout_init(&sc->sc_tick_ch, 0); |
|
|
sip = SIP_DECL(lookup)(pa); |
sip = sipcom_lookup(pa, strcmp(cf->cf_name, "gsip") == 0); |
if (sip == NULL) { |
if (sip == NULL) { |
printf("\n"); |
printf("\n"); |
panic(SIP_STR(attach) ": impossible"); |
panic("%s: impossible", __func__); |
|
} |
|
sc->sc_gigabit = sip->sip_gigabit; |
|
|
|
sc->sc_pc = pc; |
|
|
|
if (sc->sc_gigabit) { |
|
sc->sc_rxintr = gsip_rxintr; |
|
sc->sc_parm = &gsip_parm; |
|
} else { |
|
sc->sc_rxintr = sip_rxintr; |
|
sc->sc_parm = &sip_parm; |
} |
} |
|
tx_dmamap_size = sc->sc_parm->p_tx_dmamap_size; |
|
ntxsegs_alloc = sc->sc_parm->p_ntxsegs_alloc; |
|
sc->sc_ntxdesc = SIP_TXQUEUELEN * ntxsegs_alloc; |
|
sc->sc_ntxdesc_mask = sc->sc_ntxdesc - 1; |
|
sc->sc_nrxdesc_mask = sc->sc_parm->p_nrxdesc - 1; |
|
|
sc->sc_rev = PCI_REVISION(pa->pa_class); |
sc->sc_rev = PCI_REVISION(pa->pa_class); |
|
|
printf(": %s, rev %#02x\n", sip->sip_name, sc->sc_rev); |
printf(": %s, rev %#02x\n", sip->sip_name, sc->sc_rev); |
Line 699 SIP_DECL(attach)(struct device *parent, |
|
Line 1050 SIP_DECL(attach)(struct device *parent, |
|
*/ |
*/ |
ioh_valid = (pci_mapreg_map(pa, SIP_PCI_CFGIOA, |
ioh_valid = (pci_mapreg_map(pa, SIP_PCI_CFGIOA, |
PCI_MAPREG_TYPE_IO, 0, |
PCI_MAPREG_TYPE_IO, 0, |
&iot, &ioh, NULL, NULL) == 0); |
&iot, &ioh, NULL, &iosz) == 0); |
#ifdef DP83820 |
if (sc->sc_gigabit) { |
memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SIP_PCI_CFGMA); |
memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SIP_PCI_CFGMA); |
switch (memtype) { |
switch (memtype) { |
case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: |
case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: |
case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: |
case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: |
|
memh_valid = (pci_mapreg_map(pa, SIP_PCI_CFGMA, |
|
memtype, 0, &memt, &memh, NULL, &memsz) == 0); |
|
break; |
|
default: |
|
memh_valid = 0; |
|
} |
|
} else { |
memh_valid = (pci_mapreg_map(pa, SIP_PCI_CFGMA, |
memh_valid = (pci_mapreg_map(pa, SIP_PCI_CFGMA, |
memtype, 0, &memt, &memh, NULL, NULL) == 0); |
PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0, |
break; |
&memt, &memh, NULL, &memsz) == 0); |
default: |
|
memh_valid = 0; |
|
} |
} |
#else |
|
memh_valid = (pci_mapreg_map(pa, SIP_PCI_CFGMA, |
|
PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0, |
|
&memt, &memh, NULL, NULL) == 0); |
|
#endif /* DP83820 */ |
|
|
|
if (memh_valid) { |
if (memh_valid) { |
sc->sc_st = memt; |
sc->sc_st = memt; |
sc->sc_sh = memh; |
sc->sc_sh = memh; |
|
sc->sc_sz = memsz; |
} else if (ioh_valid) { |
} else if (ioh_valid) { |
sc->sc_st = iot; |
sc->sc_st = iot; |
sc->sc_sh = ioh; |
sc->sc_sh = ioh; |
|
sc->sc_sz = iosz; |
} else { |
} else { |
printf("%s: unable to map device registers\n", |
printf("%s: unable to map device registers\n", |
sc->sc_dev.dv_xname); |
sc->sc_dev.dv_xname); |
Line 742 SIP_DECL(attach)(struct device *parent, |
|
Line 1095 SIP_DECL(attach)(struct device *parent, |
|
pmreg | PCI_COMMAND_MASTER_ENABLE); |
pmreg | PCI_COMMAND_MASTER_ENABLE); |
|
|
/* power up chip */ |
/* power up chip */ |
if ((error = pci_activate(pa->pa_pc, pa->pa_tag, sc, |
if ((error = pci_activate(pa->pa_pc, pa->pa_tag, self, NULL)) && |
NULL)) && error != EOPNOTSUPP) { |
error != EOPNOTSUPP) { |
aprint_error("%s: cannot activate %d\n", sc->sc_dev.dv_xname, |
aprint_error("%s: cannot activate %d\n", sc->sc_dev.dv_xname, |
error); |
error); |
return; |
return; |
Line 757 SIP_DECL(attach)(struct device *parent, |
|
Line 1110 SIP_DECL(attach)(struct device *parent, |
|
return; |
return; |
} |
} |
intrstr = pci_intr_string(pc, ih); |
intrstr = pci_intr_string(pc, ih); |
sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, SIP_DECL(intr), sc); |
sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, sipcom_intr, sc); |
if (sc->sc_ih == NULL) { |
if (sc->sc_ih == NULL) { |
printf("%s: unable to establish interrupt", |
printf("%s: unable to establish interrupt", |
sc->sc_dev.dv_xname); |
sc->sc_dev.dv_xname); |
if (intrstr != NULL) |
if (intrstr != NULL) |
printf(" at %s", intrstr); |
printf(" at %s", intrstr); |
printf("\n"); |
printf("\n"); |
return; |
return sipcom_do_detach(self, SIP_ATTACH_MAP); |
} |
} |
printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); |
printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); |
|
|
Line 776 SIP_DECL(attach)(struct device *parent, |
|
Line 1129 SIP_DECL(attach)(struct device *parent, |
|
* DMA map for it. |
* DMA map for it. |
*/ |
*/ |
if ((error = bus_dmamem_alloc(sc->sc_dmat, |
if ((error = bus_dmamem_alloc(sc->sc_dmat, |
sizeof(struct sip_control_data), PAGE_SIZE, 0, &seg, 1, &rseg, |
sizeof(struct sip_control_data), PAGE_SIZE, 0, &sc->sc_seg, 1, |
0)) != 0) { |
&rseg, 0)) != 0) { |
printf("%s: unable to allocate control data, error = %d\n", |
printf("%s: unable to allocate control data, error = %d\n", |
sc->sc_dev.dv_xname, error); |
sc->sc_dev.dv_xname, error); |
goto fail_0; |
return sipcom_do_detach(self, SIP_ATTACH_INTR); |
} |
} |
|
|
if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, |
if ((error = bus_dmamem_map(sc->sc_dmat, &sc->sc_seg, rseg, |
sizeof(struct sip_control_data), (void **)&sc->sc_control_data, |
sizeof(struct sip_control_data), (void **)&sc->sc_control_data, |
BUS_DMA_COHERENT)) != 0) { |
BUS_DMA_COHERENT|BUS_DMA_NOCACHE)) != 0) { |
printf("%s: unable to map control data, error = %d\n", |
printf("%s: unable to map control data, error = %d\n", |
sc->sc_dev.dv_xname, error); |
sc->sc_dev.dv_xname, error); |
goto fail_1; |
sipcom_do_detach(self, SIP_ATTACH_ALLOC_MEM); |
} |
} |
|
|
if ((error = bus_dmamap_create(sc->sc_dmat, |
if ((error = bus_dmamap_create(sc->sc_dmat, |
Line 796 SIP_DECL(attach)(struct device *parent, |
|
Line 1149 SIP_DECL(attach)(struct device *parent, |
|
sizeof(struct sip_control_data), 0, 0, &sc->sc_cddmamap)) != 0) { |
sizeof(struct sip_control_data), 0, 0, &sc->sc_cddmamap)) != 0) { |
printf("%s: unable to create control data DMA map, " |
printf("%s: unable to create control data DMA map, " |
"error = %d\n", sc->sc_dev.dv_xname, error); |
"error = %d\n", sc->sc_dev.dv_xname, error); |
goto fail_2; |
sipcom_do_detach(self, SIP_ATTACH_MAP_MEM); |
} |
} |
|
|
if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap, |
if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap, |
Line 804 SIP_DECL(attach)(struct device *parent, |
|
Line 1157 SIP_DECL(attach)(struct device *parent, |
|
0)) != 0) { |
0)) != 0) { |
printf("%s: unable to load control data DMA map, error = %d\n", |
printf("%s: unable to load control data DMA map, error = %d\n", |
sc->sc_dev.dv_xname, error); |
sc->sc_dev.dv_xname, error); |
goto fail_3; |
sipcom_do_detach(self, SIP_ATTACH_CREATE_MAP); |
} |
} |
|
|
/* |
/* |
* Create the transmit buffer DMA maps. |
* Create the transmit buffer DMA maps. |
*/ |
*/ |
for (i = 0; i < SIP_TXQUEUELEN; i++) { |
for (i = 0; i < SIP_TXQUEUELEN; i++) { |
if ((error = bus_dmamap_create(sc->sc_dmat, TX_DMAMAP_SIZE, |
if ((error = bus_dmamap_create(sc->sc_dmat, tx_dmamap_size, |
SIP_NTXSEGS, MCLBYTES, 0, 0, |
sc->sc_parm->p_ntxsegs, MCLBYTES, 0, 0, |
&sc->sc_txsoft[i].txs_dmamap)) != 0) { |
&sc->sc_txsoft[i].txs_dmamap)) != 0) { |
printf("%s: unable to create tx DMA map %d, " |
printf("%s: unable to create tx DMA map %d, " |
"error = %d\n", sc->sc_dev.dv_xname, i, error); |
"error = %d\n", sc->sc_dev.dv_xname, i, error); |
goto fail_4; |
sipcom_do_detach(self, SIP_ATTACH_CREATE_TXMAP); |
} |
} |
} |
} |
|
|
/* |
/* |
* Create the receive buffer DMA maps. |
* Create the receive buffer DMA maps. |
*/ |
*/ |
for (i = 0; i < SIP_NRXDESC; i++) { |
for (i = 0; i < sc->sc_parm->p_nrxdesc; i++) { |
if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, |
if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, |
MCLBYTES, 0, 0, &sc->sc_rxsoft[i].rxs_dmamap)) != 0) { |
MCLBYTES, 0, 0, &sc->sc_rxsoft[i].rxs_dmamap)) != 0) { |
printf("%s: unable to create rx DMA map %d, " |
printf("%s: unable to create rx DMA map %d, " |
"error = %d\n", sc->sc_dev.dv_xname, i, error); |
"error = %d\n", sc->sc_dev.dv_xname, i, error); |
goto fail_5; |
sipcom_do_detach(self, SIP_ATTACH_CREATE_RXMAP); |
} |
} |
sc->sc_rxsoft[i].rxs_mbuf = NULL; |
sc->sc_rxsoft[i].rxs_mbuf = NULL; |
} |
} |
Line 836 SIP_DECL(attach)(struct device *parent, |
|
Line 1189 SIP_DECL(attach)(struct device *parent, |
|
/* |
/* |
* Reset the chip to a known state. |
* Reset the chip to a known state. |
*/ |
*/ |
SIP_DECL(reset)(sc); |
sipcom_reset(sc); |
|
|
/* |
/* |
* Read the Ethernet address from the EEPROM. This might |
* Read the Ethernet address from the EEPROM. This might |
Line 844 SIP_DECL(attach)(struct device *parent, |
|
Line 1197 SIP_DECL(attach)(struct device *parent, |
|
* in the softc. |
* in the softc. |
*/ |
*/ |
sc->sc_cfg = 0; |
sc->sc_cfg = 0; |
#if !defined(DP83820) |
if (!sc->sc_gigabit) { |
if (SIP_SIS900_REV(sc,SIS_REV_635) || |
if (SIP_SIS900_REV(sc,SIS_REV_635) || |
SIP_SIS900_REV(sc,SIS_REV_900B)) |
SIP_SIS900_REV(sc,SIS_REV_900B)) |
sc->sc_cfg |= (CFG_PESEL | CFG_RNDCNT); |
sc->sc_cfg |= (CFG_PESEL | CFG_RNDCNT); |
|
|
if (SIP_SIS900_REV(sc,SIS_REV_635) || |
if (SIP_SIS900_REV(sc,SIS_REV_635) || |
SIP_SIS900_REV(sc,SIS_REV_960) || |
SIP_SIS900_REV(sc,SIS_REV_960) || |
SIP_SIS900_REV(sc,SIS_REV_900B)) |
SIP_SIS900_REV(sc,SIS_REV_900B)) |
sc->sc_cfg |= (bus_space_read_4(sc->sc_st, sc->sc_sh, |
sc->sc_cfg |= |
SIP_CFG) & CFG_EDBMASTEN); |
(bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_CFG) & |
#endif |
CFG_EDBMASTEN); |
|
} |
|
|
(*sip->sip_variant->sipv_read_macaddr)(sc, pa, enaddr); |
(*sip->sip_variant->sipv_read_macaddr)(sc, pa, enaddr); |
|
|
Line 869 SIP_DECL(attach)(struct device *parent, |
|
Line 1223 SIP_DECL(attach)(struct device *parent, |
|
* NOTE: "Big endian mode" is useless on the SiS900 and |
* NOTE: "Big endian mode" is useless on the SiS900 and |
* friends -- it affects packet data, not descriptors. |
* friends -- it affects packet data, not descriptors. |
*/ |
*/ |
#ifdef DP83820 |
if (sc->sc_gigabit) |
/* |
sipcom_dp83820_attach(sc, pa); |
* Cause the chip to load configuration data from the EEPROM. |
|
*/ |
|
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_PTSCR, PTSCR_EELOAD_EN); |
|
for (i = 0; i < 10000; i++) { |
|
delay(10); |
|
if ((bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_PTSCR) & |
|
PTSCR_EELOAD_EN) == 0) |
|
break; |
|
} |
|
if (bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_PTSCR) & |
|
PTSCR_EELOAD_EN) { |
|
printf("%s: timeout loading configuration from EEPROM\n", |
|
sc->sc_dev.dv_xname); |
|
return; |
|
} |
|
|
|
sc->sc_gpior = bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_GPIOR); |
|
|
|
reg = bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_CFG); |
|
if (reg & CFG_PCI64_DET) { |
|
printf("%s: 64-bit PCI slot detected", sc->sc_dev.dv_xname); |
|
/* |
|
* Check to see if this card is 64-bit. If so, enable 64-bit |
|
* data transfers. |
|
* |
|
* We can't use the DATA64_EN bit in the EEPROM, because |
|
* vendors of 32-bit cards fail to clear that bit in many |
|
* cases (yet the card still detects that it's in a 64-bit |
|
* slot; go figure). |
|
*/ |
|
if (SIP_DECL(check_64bit)(pa)) { |
|
sc->sc_cfg |= CFG_DATA64_EN; |
|
printf(", using 64-bit data transfers"); |
|
} |
|
printf("\n"); |
|
} |
|
|
|
/* |
|
* XXX Need some PCI flags indicating support for |
|
* XXX 64-bit addressing. |
|
*/ |
|
#if 0 |
|
if (reg & CFG_M64ADDR) |
|
sc->sc_cfg |= CFG_M64ADDR; |
|
if (reg & CFG_T64ADDR) |
|
sc->sc_cfg |= CFG_T64ADDR; |
|
#endif |
|
|
|
if (reg & (CFG_TBI_EN|CFG_EXT_125)) { |
|
const char *sep = ""; |
|
printf("%s: using ", sc->sc_dev.dv_xname); |
|
if (reg & CFG_EXT_125) { |
|
sc->sc_cfg |= CFG_EXT_125; |
|
printf("%s125MHz clock", sep); |
|
sep = ", "; |
|
} |
|
if (reg & CFG_TBI_EN) { |
|
sc->sc_cfg |= CFG_TBI_EN; |
|
printf("%sten-bit interface", sep); |
|
sep = ", "; |
|
} |
|
printf("\n"); |
|
} |
|
if ((pa->pa_flags & PCI_FLAGS_MRM_OKAY) == 0 || |
|
(reg & CFG_MRM_DIS) != 0) |
|
sc->sc_cfg |= CFG_MRM_DIS; |
|
if ((pa->pa_flags & PCI_FLAGS_MWI_OKAY) == 0 || |
|
(reg & CFG_MWI_DIS) != 0) |
|
sc->sc_cfg |= CFG_MWI_DIS; |
|
|
|
/* |
|
* Use the extended descriptor format on the DP83820. This |
|
* gives us an interface to VLAN tagging and IPv4/TCP/UDP |
|
* checksumming. |
|
*/ |
|
sc->sc_cfg |= CFG_EXTSTS_EN; |
|
#endif /* DP83820 */ |
|
|
|
/* |
/* |
* Initialize our media structures and probe the MII. |
* Initialize our media structures and probe the MII. |
Line 956 SIP_DECL(attach)(struct device *parent, |
|
Line 1233 SIP_DECL(attach)(struct device *parent, |
|
sc->sc_mii.mii_readreg = sip->sip_variant->sipv_mii_readreg; |
sc->sc_mii.mii_readreg = sip->sip_variant->sipv_mii_readreg; |
sc->sc_mii.mii_writereg = sip->sip_variant->sipv_mii_writereg; |
sc->sc_mii.mii_writereg = sip->sip_variant->sipv_mii_writereg; |
sc->sc_mii.mii_statchg = sip->sip_variant->sipv_mii_statchg; |
sc->sc_mii.mii_statchg = sip->sip_variant->sipv_mii_statchg; |
ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, SIP_DECL(mediachange), |
sc->sc_ethercom.ec_mii = &sc->sc_mii; |
SIP_DECL(mediastatus)); |
ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, ether_mediachange, |
|
sipcom_mediastatus); |
|
|
/* |
/* |
* XXX We cannot handle flow control on the DP83815. |
* XXX We cannot handle flow control on the DP83815. |
Line 979 SIP_DECL(attach)(struct device *parent, |
|
Line 1257 SIP_DECL(attach)(struct device *parent, |
|
ifp->if_softc = sc; |
ifp->if_softc = sc; |
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; |
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; |
sc->sc_if_flags = ifp->if_flags; |
sc->sc_if_flags = ifp->if_flags; |
ifp->if_ioctl = SIP_DECL(ioctl); |
ifp->if_ioctl = sipcom_ioctl; |
ifp->if_start = SIP_DECL(start); |
ifp->if_start = sipcom_start; |
ifp->if_watchdog = SIP_DECL(watchdog); |
ifp->if_watchdog = sipcom_watchdog; |
ifp->if_init = SIP_DECL(init); |
ifp->if_init = sipcom_init; |
ifp->if_stop = SIP_DECL(stop); |
ifp->if_stop = sipcom_stop; |
IFQ_SET_READY(&ifp->if_snd); |
IFQ_SET_READY(&ifp->if_snd); |
|
|
/* |
/* |
Line 991 SIP_DECL(attach)(struct device *parent, |
|
Line 1269 SIP_DECL(attach)(struct device *parent, |
|
*/ |
*/ |
sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; |
sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; |
|
|
#ifdef DP83820 |
if (sc->sc_gigabit) { |
/* |
/* |
* And the DP83820 can do VLAN tagging in hardware, and |
* And the DP83820 can do VLAN tagging in hardware, and |
* support the jumbo Ethernet MTU. |
* support the jumbo Ethernet MTU. |
*/ |
*/ |
sc->sc_ethercom.ec_capabilities |= |
sc->sc_ethercom.ec_capabilities |= |
ETHERCAP_VLAN_HWTAGGING | ETHERCAP_JUMBO_MTU; |
ETHERCAP_VLAN_HWTAGGING | ETHERCAP_JUMBO_MTU; |
|
|
/* |
/* |
* The DP83820 can do IPv4, TCPv4, and UDPv4 checksums |
* The DP83820 can do IPv4, TCPv4, and UDPv4 checksums |
* in hardware. |
* in hardware. |
*/ |
*/ |
ifp->if_capabilities |= |
ifp->if_capabilities |= |
IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | |
IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | |
IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | |
IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | |
IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx; |
IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx; |
#endif /* DP83820 */ |
} |
|
|
/* |
/* |
* Attach the interface. |
* Attach the interface. |
Line 1039 SIP_DECL(attach)(struct device *parent, |
|
Line 1317 SIP_DECL(attach)(struct device *parent, |
|
* may trash the first few outgoing packets if the |
* may trash the first few outgoing packets if the |
* PCI bus is saturated. |
* PCI bus is saturated. |
*/ |
*/ |
#ifdef DP83820 |
if (sc->sc_gigabit) |
sc->sc_tx_drain_thresh = 6400 / 32; /* from FreeBSD nge(4) */ |
sc->sc_tx_drain_thresh = 6400 / 32; /* from FreeBSD nge(4) */ |
#else |
else |
sc->sc_tx_drain_thresh = 1504 / 32; |
sc->sc_tx_drain_thresh = 1504 / 32; |
#endif |
|
|
|
/* |
/* |
* Initialize the Rx FIFO drain threshold. |
* Initialize the Rx FIFO drain threshold. |
Line 1073 SIP_DECL(attach)(struct device *parent, |
|
Line 1350 SIP_DECL(attach)(struct device *parent, |
|
NULL, sc->sc_dev.dv_xname, "rxintr"); |
NULL, sc->sc_dev.dv_xname, "rxintr"); |
evcnt_attach_dynamic(&sc->sc_ev_hiberr, EVCNT_TYPE_INTR, |
evcnt_attach_dynamic(&sc->sc_ev_hiberr, EVCNT_TYPE_INTR, |
NULL, sc->sc_dev.dv_xname, "hiberr"); |
NULL, sc->sc_dev.dv_xname, "hiberr"); |
#ifndef DP83820 |
if (!sc->sc_gigabit) { |
evcnt_attach_dynamic(&sc->sc_ev_rxpause, EVCNT_TYPE_INTR, |
evcnt_attach_dynamic(&sc->sc_ev_rxpause, EVCNT_TYPE_INTR, |
NULL, sc->sc_dev.dv_xname, "rxpause"); |
NULL, sc->sc_dev.dv_xname, "rxpause"); |
#endif /* !DP83820 */ |
} else { |
#ifdef DP83820 |
evcnt_attach_dynamic(&sc->sc_ev_rxpause, EVCNT_TYPE_MISC, |
evcnt_attach_dynamic(&sc->sc_ev_rxpause, EVCNT_TYPE_MISC, |
NULL, sc->sc_dev.dv_xname, "rxpause"); |
NULL, sc->sc_dev.dv_xname, "rxpause"); |
evcnt_attach_dynamic(&sc->sc_ev_txpause, EVCNT_TYPE_MISC, |
evcnt_attach_dynamic(&sc->sc_ev_txpause, EVCNT_TYPE_MISC, |
NULL, sc->sc_dev.dv_xname, "txpause"); |
NULL, sc->sc_dev.dv_xname, "txpause"); |
evcnt_attach_dynamic(&sc->sc_ev_rxipsum, EVCNT_TYPE_MISC, |
evcnt_attach_dynamic(&sc->sc_ev_rxipsum, EVCNT_TYPE_MISC, |
NULL, sc->sc_dev.dv_xname, "rxipsum"); |
NULL, sc->sc_dev.dv_xname, "rxipsum"); |
evcnt_attach_dynamic(&sc->sc_ev_rxtcpsum, EVCNT_TYPE_MISC, |
evcnt_attach_dynamic(&sc->sc_ev_rxtcpsum, EVCNT_TYPE_MISC, |
NULL, sc->sc_dev.dv_xname, "rxtcpsum"); |
NULL, sc->sc_dev.dv_xname, "rxtcpsum"); |
evcnt_attach_dynamic(&sc->sc_ev_rxudpsum, EVCNT_TYPE_MISC, |
evcnt_attach_dynamic(&sc->sc_ev_rxudpsum, EVCNT_TYPE_MISC, |
NULL, sc->sc_dev.dv_xname, "rxudpsum"); |
NULL, sc->sc_dev.dv_xname, "rxudpsum"); |
evcnt_attach_dynamic(&sc->sc_ev_txipsum, EVCNT_TYPE_MISC, |
evcnt_attach_dynamic(&sc->sc_ev_txipsum, EVCNT_TYPE_MISC, |
NULL, sc->sc_dev.dv_xname, "txipsum"); |
NULL, sc->sc_dev.dv_xname, "txipsum"); |
evcnt_attach_dynamic(&sc->sc_ev_txtcpsum, EVCNT_TYPE_MISC, |
evcnt_attach_dynamic(&sc->sc_ev_txtcpsum, EVCNT_TYPE_MISC, |
NULL, sc->sc_dev.dv_xname, "txtcpsum"); |
NULL, sc->sc_dev.dv_xname, "txtcpsum"); |
evcnt_attach_dynamic(&sc->sc_ev_txudpsum, EVCNT_TYPE_MISC, |
evcnt_attach_dynamic(&sc->sc_ev_txudpsum, EVCNT_TYPE_MISC, |
NULL, sc->sc_dev.dv_xname, "txudpsum"); |
NULL, sc->sc_dev.dv_xname, "txudpsum"); |
} |
#endif /* DP83820 */ |
|
#endif /* SIP_EVENT_COUNTERS */ |
#endif /* SIP_EVENT_COUNTERS */ |
|
|
|
if (!pmf_device_register(self, sipcom_suspend, sipcom_resume)) |
|
aprint_error_dev(self, "couldn't establish power handler\n"); |
|
else |
|
pmf_class_network_register(self, ifp); |
|
} |
|
|
|
static inline void |
|
sipcom_set_extsts(struct sip_softc *sc, int lasttx, struct mbuf *m0, |
|
uint64_t capenable) |
|
{ |
|
struct m_tag *mtag; |
|
u_int32_t extsts; |
|
#ifdef DEBUG |
|
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
|
#endif |
/* |
/* |
* Make sure the interface is shutdown during reboot. |
* If VLANs are enabled and the packet has a VLAN tag, set |
|
* up the descriptor to encapsulate the packet for us. |
|
* |
|
* This apparently has to be on the last descriptor of |
|
* the packet. |
*/ |
*/ |
sc->sc_sdhook = shutdownhook_establish(SIP_DECL(shutdown), sc); |
|
if (sc->sc_sdhook == NULL) |
|
printf("%s: WARNING: unable to establish shutdown hook\n", |
|
sc->sc_dev.dv_xname); |
|
return; |
|
|
|
/* |
/* |
* Free any resources we've allocated during the failed attach |
* Byte swapping is tricky. We need to provide the tag |
* attempt. Do this in reverse order and fall through. |
* in a network byte order. On a big-endian machine, |
|
* the byteorder is correct, but we need to swap it |
|
* anyway, because this will be undone by the outside |
|
* htole32(). That's why there must be an |
|
* unconditional swap instead of htons() inside. |
*/ |
*/ |
fail_5: |
if ((mtag = VLAN_OUTPUT_TAG(&sc->sc_ethercom, m0)) != NULL) { |
for (i = 0; i < SIP_NRXDESC; i++) { |
sc->sc_txdescs[lasttx].sipd_extsts |= |
if (sc->sc_rxsoft[i].rxs_dmamap != NULL) |
htole32(EXTSTS_VPKT | |
bus_dmamap_destroy(sc->sc_dmat, |
(bswap16(VLAN_TAG_VALUE(mtag)) & |
sc->sc_rxsoft[i].rxs_dmamap); |
EXTSTS_VTCI)); |
} |
} |
fail_4: |
|
for (i = 0; i < SIP_TXQUEUELEN; i++) { |
|
if (sc->sc_txsoft[i].txs_dmamap != NULL) |
|
bus_dmamap_destroy(sc->sc_dmat, |
|
sc->sc_txsoft[i].txs_dmamap); |
|
} |
|
bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap); |
|
fail_3: |
|
bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap); |
|
fail_2: |
|
bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_control_data, |
|
sizeof(struct sip_control_data)); |
|
fail_1: |
|
bus_dmamem_free(sc->sc_dmat, &seg, rseg); |
|
fail_0: |
|
return; |
|
} |
|
|
|
/* |
|
* sip_shutdown: |
|
* |
|
* Make sure the interface is stopped at reboot time. |
|
*/ |
|
static void |
|
SIP_DECL(shutdown)(void *arg) |
|
{ |
|
struct sip_softc *sc = arg; |
|
|
|
SIP_DECL(stop)(&sc->sc_ethercom.ec_if, 1); |
/* |
|
* If the upper-layer has requested IPv4/TCPv4/UDPv4 |
|
* checksumming, set up the descriptor to do this work |
|
* for us. |
|
* |
|
* This apparently has to be on the first descriptor of |
|
* the packet. |
|
* |
|
* Byte-swap constants so the compiler can optimize. |
|
*/ |
|
extsts = 0; |
|
if (m0->m_pkthdr.csum_flags & M_CSUM_IPv4) { |
|
KDASSERT(ifp->if_capenable & IFCAP_CSUM_IPv4_Tx); |
|
SIP_EVCNT_INCR(&sc->sc_ev_txipsum); |
|
extsts |= htole32(EXTSTS_IPPKT); |
|
} |
|
if (m0->m_pkthdr.csum_flags & M_CSUM_TCPv4) { |
|
KDASSERT(ifp->if_capenable & IFCAP_CSUM_TCPv4_Tx); |
|
SIP_EVCNT_INCR(&sc->sc_ev_txtcpsum); |
|
extsts |= htole32(EXTSTS_TCPPKT); |
|
} else if (m0->m_pkthdr.csum_flags & M_CSUM_UDPv4) { |
|
KDASSERT(ifp->if_capenable & IFCAP_CSUM_UDPv4_Tx); |
|
SIP_EVCNT_INCR(&sc->sc_ev_txudpsum); |
|
extsts |= htole32(EXTSTS_UDPPKT); |
|
} |
|
sc->sc_txdescs[sc->sc_txnext].sipd_extsts |= extsts; |
} |
} |
|
|
/* |
/* |
Line 1153 SIP_DECL(shutdown)(void *arg) |
|
Line 1445 SIP_DECL(shutdown)(void *arg) |
|
* Start packet transmission on the interface. |
* Start packet transmission on the interface. |
*/ |
*/ |
static void |
static void |
SIP_DECL(start)(struct ifnet *ifp) |
sipcom_start(struct ifnet *ifp) |
{ |
{ |
struct sip_softc *sc = ifp->if_softc; |
struct sip_softc *sc = ifp->if_softc; |
struct mbuf *m0; |
struct mbuf *m0; |
#ifndef DP83820 |
|
struct mbuf *m; |
struct mbuf *m; |
#endif |
|
struct sip_txsoft *txs; |
struct sip_txsoft *txs; |
bus_dmamap_t dmamap; |
bus_dmamap_t dmamap; |
int error, nexttx, lasttx, seg; |
int error, nexttx, lasttx, seg; |
Line 1167 SIP_DECL(start)(struct ifnet *ifp) |
|
Line 1457 SIP_DECL(start)(struct ifnet *ifp) |
|
#if 0 |
#if 0 |
int firsttx = sc->sc_txnext; |
int firsttx = sc->sc_txnext; |
#endif |
#endif |
#ifdef DP83820 |
|
struct m_tag *mtag; |
|
u_int32_t extsts; |
|
#endif |
|
|
|
#ifndef DP83820 |
|
/* |
/* |
* If we've been told to pause, don't transmit any more packets. |
* If we've been told to pause, don't transmit any more packets. |
*/ |
*/ |
if (sc->sc_paused) |
if (!sc->sc_gigabit && sc->sc_paused) |
ifp->if_flags |= IFF_OACTIVE; |
ifp->if_flags |= IFF_OACTIVE; |
#endif |
|
|
|
if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) |
if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) |
return; |
return; |
Line 1201 SIP_DECL(start)(struct ifnet *ifp) |
|
Line 1485 SIP_DECL(start)(struct ifnet *ifp) |
|
IFQ_POLL(&ifp->if_snd, m0); |
IFQ_POLL(&ifp->if_snd, m0); |
if (m0 == NULL) |
if (m0 == NULL) |
break; |
break; |
#ifndef DP83820 |
|
m = NULL; |
m = NULL; |
#endif |
|
|
|
dmamap = txs->txs_dmamap; |
dmamap = txs->txs_dmamap; |
|
|
#ifdef DP83820 |
|
/* |
/* |
* Load the DMA map. If this fails, the packet either |
* Load the DMA map. If this fails, the packet either |
* didn't fit in the allotted number of segments, or we |
* didn't fit in the alloted number of segments, or we |
* were short on resources. For the too-many-segments |
* were short on resources. |
* case, we simply report an error and drop the packet, |
|
* since we can't sanely copy a jumbo packet to a single |
|
* buffer. |
|
*/ |
*/ |
error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0, |
error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0, |
BUS_DMA_WRITE|BUS_DMA_NOWAIT); |
BUS_DMA_WRITE|BUS_DMA_NOWAIT); |
if (error) { |
/* In the non-gigabit case, we'll copy and try again. */ |
if (error == EFBIG) { |
if (error != 0 && !sc->sc_gigabit) { |
printf("%s: Tx packet consumes too many " |
|
"DMA segments, dropping...\n", |
|
sc->sc_dev.dv_xname); |
|
IFQ_DEQUEUE(&ifp->if_snd, m0); |
|
m_freem(m0); |
|
continue; |
|
} |
|
/* |
|
* Short on resources, just stop for now. |
|
*/ |
|
break; |
|
} |
|
#else /* DP83820 */ |
|
/* |
|
* Load the DMA map. If this fails, the packet either |
|
* didn't fit in the alloted number of segments, or we |
|
* were short on resources. In this case, we'll copy |
|
* and try again. |
|
*/ |
|
if (bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0, |
|
BUS_DMA_WRITE|BUS_DMA_NOWAIT) != 0) { |
|
MGETHDR(m, M_DONTWAIT, MT_DATA); |
MGETHDR(m, M_DONTWAIT, MT_DATA); |
if (m == NULL) { |
if (m == NULL) { |
printf("%s: unable to allocate Tx mbuf\n", |
printf("%s: unable to allocate Tx mbuf\n", |
Line 1266 SIP_DECL(start)(struct ifnet *ifp) |
|
Line 1523 SIP_DECL(start)(struct ifnet *ifp) |
|
"error = %d\n", sc->sc_dev.dv_xname, error); |
"error = %d\n", sc->sc_dev.dv_xname, error); |
break; |
break; |
} |
} |
|
} else if (error == EFBIG) { |
|
/* |
|
* For the too-many-segments case, we simply |
|
* report an error and drop the packet, |
|
* since we can't sanely copy a jumbo packet |
|
* to a single buffer. |
|
*/ |
|
printf("%s: Tx packet consumes too many " |
|
"DMA segments, dropping...\n", sc->sc_dev.dv_xname); |
|
IFQ_DEQUEUE(&ifp->if_snd, m0); |
|
m_freem(m0); |
|
continue; |
|
} else if (error != 0) { |
|
/* |
|
* Short on resources, just stop for now. |
|
*/ |
|
break; |
} |
} |
#endif /* DP83820 */ |
|
|
|
/* |
/* |
* Ensure we have enough descriptors free to describe |
* Ensure we have enough descriptors free to describe |
Line 1288 SIP_DECL(start)(struct ifnet *ifp) |
|
Line 1561 SIP_DECL(start)(struct ifnet *ifp) |
|
*/ |
*/ |
ifp->if_flags |= IFF_OACTIVE; |
ifp->if_flags |= IFF_OACTIVE; |
bus_dmamap_unload(sc->sc_dmat, dmamap); |
bus_dmamap_unload(sc->sc_dmat, dmamap); |
#ifndef DP83820 |
|
if (m != NULL) |
if (m != NULL) |
m_freem(m); |
m_freem(m); |
#endif |
|
SIP_EVCNT_INCR(&sc->sc_ev_txdstall); |
SIP_EVCNT_INCR(&sc->sc_ev_txdstall); |
break; |
break; |
} |
} |
|
|
IFQ_DEQUEUE(&ifp->if_snd, m0); |
IFQ_DEQUEUE(&ifp->if_snd, m0); |
#ifndef DP83820 |
|
if (m != NULL) { |
if (m != NULL) { |
m_freem(m0); |
m_freem(m0); |
m0 = m; |
m0 = m; |
} |
} |
#endif |
|
|
|
/* |
/* |
* WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET. |
* WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET. |
Line 1317 SIP_DECL(start)(struct ifnet *ifp) |
|
Line 1586 SIP_DECL(start)(struct ifnet *ifp) |
|
*/ |
*/ |
for (nexttx = lasttx = sc->sc_txnext, seg = 0; |
for (nexttx = lasttx = sc->sc_txnext, seg = 0; |
seg < dmamap->dm_nsegs; |
seg < dmamap->dm_nsegs; |
seg++, nexttx = SIP_NEXTTX(nexttx)) { |
seg++, nexttx = sip_nexttx(sc, nexttx)) { |
/* |
/* |
* If this is the first descriptor we're |
* If this is the first descriptor we're |
* enqueueing, don't set the OWN bit just |
* enqueueing, don't set the OWN bit just |
* yet. That could cause a race condition. |
* yet. That could cause a race condition. |
* We'll do it below. |
* We'll do it below. |
*/ |
*/ |
sc->sc_txdescs[nexttx].sipd_bufptr = |
*sipd_bufptr(sc, &sc->sc_txdescs[nexttx]) = |
htole32(dmamap->dm_segs[seg].ds_addr); |
htole32(dmamap->dm_segs[seg].ds_addr); |
sc->sc_txdescs[nexttx].sipd_cmdsts = |
*sipd_cmdsts(sc, &sc->sc_txdescs[nexttx]) = |
htole32((nexttx == sc->sc_txnext ? 0 : CMDSTS_OWN) | |
htole32((nexttx == sc->sc_txnext ? 0 : CMDSTS_OWN) | |
CMDSTS_MORE | dmamap->dm_segs[seg].ds_len); |
CMDSTS_MORE | dmamap->dm_segs[seg].ds_len); |
#ifdef DP83820 |
|
sc->sc_txdescs[nexttx].sipd_extsts = 0; |
sc->sc_txdescs[nexttx].sipd_extsts = 0; |
#endif /* DP83820 */ |
|
lasttx = nexttx; |
lasttx = nexttx; |
} |
} |
|
|
/* Clear the MORE bit on the last segment. */ |
/* Clear the MORE bit on the last segment. */ |
sc->sc_txdescs[lasttx].sipd_cmdsts &= htole32(~CMDSTS_MORE); |
*sipd_cmdsts(sc, &sc->sc_txdescs[lasttx]) &= |
|
htole32(~CMDSTS_MORE); |
|
|
/* |
/* |
* If we're in the interrupt delay window, delay the |
* If we're in the interrupt delay window, delay the |
Line 1344 SIP_DECL(start)(struct ifnet *ifp) |
|
Line 1612 SIP_DECL(start)(struct ifnet *ifp) |
|
*/ |
*/ |
if (++sc->sc_txwin >= (SIP_TXQUEUELEN * 2 / 3)) { |
if (++sc->sc_txwin >= (SIP_TXQUEUELEN * 2 / 3)) { |
SIP_EVCNT_INCR(&sc->sc_ev_txforceintr); |
SIP_EVCNT_INCR(&sc->sc_ev_txforceintr); |
sc->sc_txdescs[lasttx].sipd_cmdsts |= |
*sipd_cmdsts(sc, &sc->sc_txdescs[lasttx]) |= |
htole32(CMDSTS_INTR); |
htole32(CMDSTS_INTR); |
sc->sc_txwin = 0; |
sc->sc_txwin = 0; |
} |
} |
|
|
#ifdef DP83820 |
if (sc->sc_gigabit) |
/* |
sipcom_set_extsts(sc, lasttx, m0, ifp->if_capenable); |
* If VLANs are enabled and the packet has a VLAN tag, set |
|
* up the descriptor to encapsulate the packet for us. |
|
* |
|
* This apparently has to be on the last descriptor of |
|
* the packet. |
|
*/ |
|
|
|
/* |
|
* Byte swapping is tricky. We need to provide the tag |
|
* in a network byte order. On a big-endian machine, |
|
* the byteorder is correct, but we need to swap it |
|
* anyway, because this will be undone by the outside |
|
* htole32(). That's why there must be an |
|
* unconditional swap instead of htons() inside. |
|
*/ |
|
if ((mtag = VLAN_OUTPUT_TAG(&sc->sc_ethercom, m0)) != NULL) { |
|
sc->sc_txdescs[lasttx].sipd_extsts |= |
|
htole32(EXTSTS_VPKT | |
|
(bswap16(VLAN_TAG_VALUE(mtag)) & |
|
EXTSTS_VTCI)); |
|
} |
|
|
|
/* |
|
* If the upper-layer has requested IPv4/TCPv4/UDPv4 |
|
* checksumming, set up the descriptor to do this work |
|
* for us. |
|
* |
|
* This apparently has to be on the first descriptor of |
|
* the packet. |
|
* |
|
* Byte-swap constants so the compiler can optimize. |
|
*/ |
|
extsts = 0; |
|
if (m0->m_pkthdr.csum_flags & M_CSUM_IPv4) { |
|
KDASSERT(ifp->if_capenable & IFCAP_CSUM_IPv4_Tx); |
|
SIP_EVCNT_INCR(&sc->sc_ev_txipsum); |
|
extsts |= htole32(EXTSTS_IPPKT); |
|
} |
|
if (m0->m_pkthdr.csum_flags & M_CSUM_TCPv4) { |
|
KDASSERT(ifp->if_capenable & IFCAP_CSUM_TCPv4_Tx); |
|
SIP_EVCNT_INCR(&sc->sc_ev_txtcpsum); |
|
extsts |= htole32(EXTSTS_TCPPKT); |
|
} else if (m0->m_pkthdr.csum_flags & M_CSUM_UDPv4) { |
|
KDASSERT(ifp->if_capenable & IFCAP_CSUM_UDPv4_Tx); |
|
SIP_EVCNT_INCR(&sc->sc_ev_txudpsum); |
|
extsts |= htole32(EXTSTS_UDPPKT); |
|
} |
|
sc->sc_txdescs[sc->sc_txnext].sipd_extsts |= extsts; |
|
#endif /* DP83820 */ |
|
|
|
/* Sync the descriptors we're using. */ |
/* Sync the descriptors we're using. */ |
SIP_CDTXSYNC(sc, sc->sc_txnext, dmamap->dm_nsegs, |
sip_cdtxsync(sc, sc->sc_txnext, dmamap->dm_nsegs, |
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
|
|
/* |
/* |
* The entire packet is set up. Give the first descrptor |
* The entire packet is set up. Give the first descrptor |
* to the chip now. |
* to the chip now. |
*/ |
*/ |
sc->sc_txdescs[sc->sc_txnext].sipd_cmdsts |= |
*sipd_cmdsts(sc, &sc->sc_txdescs[sc->sc_txnext]) |= |
htole32(CMDSTS_OWN); |
htole32(CMDSTS_OWN); |
SIP_CDTXSYNC(sc, sc->sc_txnext, 1, |
sip_cdtxsync(sc, sc->sc_txnext, 1, |
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
|
|
/* |
/* |
Line 1472 SIP_DECL(start)(struct ifnet *ifp) |
|
Line 1691 SIP_DECL(start)(struct ifnet *ifp) |
|
#endif |
#endif |
|
|
/* Set a watchdog timer in case the chip flakes out. */ |
/* Set a watchdog timer in case the chip flakes out. */ |
#ifdef DP83820 |
|
/* Gigabit autonegotiation takes 5 seconds. */ |
/* Gigabit autonegotiation takes 5 seconds. */ |
ifp->if_timer = 10; |
ifp->if_timer = (sc->sc_gigabit) ? 10 : 5; |
#else |
|
ifp->if_timer = 5; |
|
#endif |
|
} |
} |
} |
} |
|
|
Line 1487 SIP_DECL(start)(struct ifnet *ifp) |
|
Line 1702 SIP_DECL(start)(struct ifnet *ifp) |
|
* Watchdog timer handler. |
* Watchdog timer handler. |
*/ |
*/ |
static void |
static void |
SIP_DECL(watchdog)(struct ifnet *ifp) |
sipcom_watchdog(struct ifnet *ifp) |
{ |
{ |
struct sip_softc *sc = ifp->if_softc; |
struct sip_softc *sc = ifp->if_softc; |
|
|
Line 1497 SIP_DECL(watchdog)(struct ifnet *ifp) |
|
Line 1712 SIP_DECL(watchdog)(struct ifnet *ifp) |
|
* If we manage to sweep them all up, ignore the lack of |
* If we manage to sweep them all up, ignore the lack of |
* interrupt. |
* interrupt. |
*/ |
*/ |
SIP_DECL(txintr)(sc); |
sipcom_txintr(sc); |
|
|
if (sc->sc_txfree != SIP_NTXDESC) { |
if (sc->sc_txfree != sc->sc_ntxdesc) { |
printf("%s: device timeout\n", sc->sc_dev.dv_xname); |
printf("%s: device timeout\n", sc->sc_dev.dv_xname); |
ifp->if_oerrors++; |
ifp->if_oerrors++; |
|
|
/* Reset the interface. */ |
/* Reset the interface. */ |
(void) SIP_DECL(init)(ifp); |
(void) sipcom_init(ifp); |
} else if (ifp->if_flags & IFF_DEBUG) |
} else if (ifp->if_flags & IFF_DEBUG) |
printf("%s: recovered from device timeout\n", |
printf("%s: recovered from device timeout\n", |
sc->sc_dev.dv_xname); |
sc->sc_dev.dv_xname); |
|
|
/* Try to get more packets going. */ |
/* Try to get more packets going. */ |
SIP_DECL(start)(ifp); |
sipcom_start(ifp); |
} |
} |
|
|
/* |
/* |
Line 1519 SIP_DECL(watchdog)(struct ifnet *ifp) |
|
Line 1734 SIP_DECL(watchdog)(struct ifnet *ifp) |
|
* Handle control requests from the operator. |
* Handle control requests from the operator. |
*/ |
*/ |
static int |
static int |
SIP_DECL(ioctl)(struct ifnet *ifp, u_long cmd, void *data) |
sipcom_ioctl(struct ifnet *ifp, u_long cmd, void *data) |
{ |
{ |
struct sip_softc *sc = ifp->if_softc; |
struct sip_softc *sc = ifp->if_softc; |
struct ifreq *ifr = (struct ifreq *)data; |
struct ifreq *ifr = (struct ifreq *)data; |
Line 1533 SIP_DECL(ioctl)(struct ifnet *ifp, u_lon |
|
Line 1748 SIP_DECL(ioctl)(struct ifnet *ifp, u_lon |
|
if (IFM_SUBTYPE(ifr->ifr_media) == IFM_AUTO || |
if (IFM_SUBTYPE(ifr->ifr_media) == IFM_AUTO || |
(ifr->ifr_media & IFM_FDX) == 0) |
(ifr->ifr_media & IFM_FDX) == 0) |
ifr->ifr_media &= ~IFM_ETH_FMASK; |
ifr->ifr_media &= ~IFM_ETH_FMASK; |
#ifdef DP83820 |
|
if (IFM_SUBTYPE(ifr->ifr_media) != IFM_AUTO) { |
|
if ((ifr->ifr_media & IFM_ETH_FMASK) == IFM_FLOW) { |
|
/* We can do both TXPAUSE and RXPAUSE. */ |
|
ifr->ifr_media |= |
|
IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE; |
|
} |
|
sc->sc_flowflags = ifr->ifr_media & IFM_ETH_FMASK; |
|
} |
|
#else |
|
/* XXX */ |
/* XXX */ |
if (SIP_CHIP_MODEL(sc, PCI_VENDOR_NS, PCI_PRODUCT_NS_DP83815)) |
if (SIP_CHIP_MODEL(sc, PCI_VENDOR_NS, PCI_PRODUCT_NS_DP83815)) |
ifr->ifr_media &= ~IFM_ETH_FMASK; |
ifr->ifr_media &= ~IFM_ETH_FMASK; |
|
|
if (IFM_SUBTYPE(ifr->ifr_media) != IFM_AUTO) { |
if (IFM_SUBTYPE(ifr->ifr_media) != IFM_AUTO) { |
if (ifr->ifr_media & IFM_FLOW) { |
if (sc->sc_gigabit && |
|
(ifr->ifr_media & IFM_ETH_FMASK) == IFM_FLOW) { |
|
/* We can do both TXPAUSE and RXPAUSE. */ |
|
ifr->ifr_media |= |
|
IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE; |
|
} else if (ifr->ifr_media & IFM_FLOW) { |
/* |
/* |
* Both TXPAUSE and RXPAUSE must be set. |
* Both TXPAUSE and RXPAUSE must be set. |
* (SiS900 and DP83815 don't have PAUSE_ASYM |
* (SiS900 and DP83815 don't have PAUSE_ASYM |
Line 1561 SIP_DECL(ioctl)(struct ifnet *ifp, u_lon |
|
Line 1771 SIP_DECL(ioctl)(struct ifnet *ifp, u_lon |
|
} |
} |
sc->sc_flowflags = ifr->ifr_media & IFM_ETH_FMASK; |
sc->sc_flowflags = ifr->ifr_media & IFM_ETH_FMASK; |
} |
} |
#endif |
goto ethioctl; |
/* FALLTHROUGH */ |
|
case SIOCGIFMEDIA: |
|
error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); |
|
break; |
|
case SIOCSIFFLAGS: |
case SIOCSIFFLAGS: |
/* If the interface is up and running, only modify the receive |
/* If the interface is up and running, only modify the receive |
* filter when setting promiscuous or debug mode. Otherwise |
* filter when setting promiscuous or debug mode. Otherwise |
Line 1592 SIP_DECL(ioctl)(struct ifnet *ifp, u_lon |
|
Line 1798 SIP_DECL(ioctl)(struct ifnet *ifp, u_lon |
|
#undef RESETIGN |
#undef RESETIGN |
} |
} |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
|
ethioctl: |
default: |
default: |
error = ether_ioctl(ifp, cmd, data); |
if ((error = ether_ioctl(ifp, cmd, data)) != ENETRESET) |
if (error == ENETRESET) { |
break; |
|
|
|
error = 0; |
|
|
|
if (cmd == SIOCSIFCAP) |
|
error = (*ifp->if_init)(ifp); |
|
else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI) |
|
; |
|
else if (ifp->if_flags & IFF_RUNNING) { |
/* |
/* |
* Multicast list has changed; set the hardware filter |
* Multicast list has changed; set the hardware filter |
* accordingly. |
* accordingly. |
*/ |
*/ |
if (ifp->if_flags & IFF_RUNNING) |
(*sc->sc_model->sip_variant->sipv_set_filter)(sc); |
(*sc->sc_model->sip_variant->sipv_set_filter)(sc); |
|
error = 0; |
|
} |
} |
break; |
break; |
} |
} |
|
|
/* Try to get more packets going. */ |
/* Try to get more packets going. */ |
SIP_DECL(start)(ifp); |
sipcom_start(ifp); |
|
|
sc->sc_if_flags = ifp->if_flags; |
sc->sc_if_flags = ifp->if_flags; |
splx(s); |
splx(s); |
Line 1620 SIP_DECL(ioctl)(struct ifnet *ifp, u_lon |
|
Line 1833 SIP_DECL(ioctl)(struct ifnet *ifp, u_lon |
|
* Interrupt service routine. |
* Interrupt service routine. |
*/ |
*/ |
static int |
static int |
SIP_DECL(intr)(void *arg) |
sipcom_intr(void *arg) |
{ |
{ |
struct sip_softc *sc = arg; |
struct sip_softc *sc = arg; |
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
Line 1647 SIP_DECL(intr)(void *arg) |
|
Line 1860 SIP_DECL(intr)(void *arg) |
|
SIP_EVCNT_INCR(&sc->sc_ev_rxintr); |
SIP_EVCNT_INCR(&sc->sc_ev_rxintr); |
|
|
/* Grab any new packets. */ |
/* Grab any new packets. */ |
SIP_DECL(rxintr)(sc); |
(*sc->sc_rxintr)(sc); |
|
|
if (isr & ISR_RXORN) { |
if (isr & ISR_RXORN) { |
printf("%s: receive FIFO overrun\n", |
printf("%s: receive FIFO overrun\n", |
Line 1677 SIP_DECL(intr)(void *arg) |
|
Line 1890 SIP_DECL(intr)(void *arg) |
|
#endif |
#endif |
|
|
/* Sweep up transmit descriptors. */ |
/* Sweep up transmit descriptors. */ |
SIP_DECL(txintr)(sc); |
sipcom_txintr(sc); |
|
|
if (isr & ISR_TXURN) { |
if (isr & ISR_TXURN) { |
u_int32_t thresh; |
u_int32_t thresh; |
|
int txfifo_size = (sc->sc_gigabit) |
|
? DP83820_SIP_TXFIFO_SIZE |
|
: OTHER_SIP_TXFIFO_SIZE; |
|
|
printf("%s: transmit FIFO underrun", |
printf("%s: transmit FIFO underrun", |
sc->sc_dev.dv_xname); |
sc->sc_dev.dv_xname); |
|
|
thresh = sc->sc_tx_drain_thresh + 1; |
thresh = sc->sc_tx_drain_thresh + 1; |
if (thresh <= TXCFG_DRTH && |
if (thresh <= __SHIFTOUT_MASK(sc->sc_bits.b_txcfg_drth_mask) |
(thresh * 32) <= (SIP_TXFIFO_SIZE - |
&& (thresh * 32) <= (txfifo_size - |
(sc->sc_tx_fill_thresh * 32))) { |
(sc->sc_tx_fill_thresh * 32))) { |
printf("; increasing Tx drain " |
printf("; increasing Tx drain " |
"threshold to %u bytes\n", |
"threshold to %u bytes\n", |
thresh * 32); |
thresh * 32); |
sc->sc_tx_drain_thresh = thresh; |
sc->sc_tx_drain_thresh = thresh; |
(void) SIP_DECL(init)(ifp); |
(void) sipcom_init(ifp); |
} else { |
} else { |
(void) SIP_DECL(init)(ifp); |
(void) sipcom_init(ifp); |
printf("\n"); |
printf("\n"); |
} |
} |
} |
} |
} |
} |
|
|
#if !defined(DP83820) |
|
if (sc->sc_imr & (ISR_PAUSE_END|ISR_PAUSE_ST)) { |
if (sc->sc_imr & (ISR_PAUSE_END|ISR_PAUSE_ST)) { |
if (isr & ISR_PAUSE_ST) { |
if (isr & ISR_PAUSE_ST) { |
sc->sc_paused = 1; |
sc->sc_paused = 1; |
Line 1713 SIP_DECL(intr)(void *arg) |
|
Line 1927 SIP_DECL(intr)(void *arg) |
|
ifp->if_flags &= ~IFF_OACTIVE; |
ifp->if_flags &= ~IFF_OACTIVE; |
} |
} |
} |
} |
#endif /* ! DP83820 */ |
|
|
|
if (isr & ISR_HIBERR) { |
if (isr & ISR_HIBERR) { |
int want_init = 0; |
int want_init = 0; |
Line 1730 SIP_DECL(intr)(void *arg) |
|
Line 1943 SIP_DECL(intr)(void *arg) |
|
} \ |
} \ |
} while (/*CONSTCOND*/0) |
} while (/*CONSTCOND*/0) |
|
|
PRINTERR(ISR_DPERR, "parity error"); |
PRINTERR(sc->sc_bits.b_isr_dperr, "parity error"); |
PRINTERR(ISR_SSERR, "system error"); |
PRINTERR(sc->sc_bits.b_isr_sserr, "system error"); |
PRINTERR(ISR_RMABT, "master abort"); |
PRINTERR(sc->sc_bits.b_isr_rmabt, "master abort"); |
PRINTERR(ISR_RTABT, "target abort"); |
PRINTERR(sc->sc_bits.b_isr_rtabt, "target abort"); |
PRINTERR(ISR_RXSOVR, "receive status FIFO overrun"); |
PRINTERR(ISR_RXSOVR, "receive status FIFO overrun"); |
/* |
/* |
* Ignore: |
* Ignore: |
Line 1741 SIP_DECL(intr)(void *arg) |
|
Line 1954 SIP_DECL(intr)(void *arg) |
|
* Rx reset complete |
* Rx reset complete |
*/ |
*/ |
if (want_init) |
if (want_init) |
(void) SIP_DECL(init)(ifp); |
(void) sipcom_init(ifp); |
#undef PRINTERR |
#undef PRINTERR |
} |
} |
} |
} |
Line 1750 SIP_DECL(intr)(void *arg) |
|
Line 1963 SIP_DECL(intr)(void *arg) |
|
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_IER, IER_IE); |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_IER, IER_IE); |
|
|
/* Try to get more packets going. */ |
/* Try to get more packets going. */ |
SIP_DECL(start)(ifp); |
sipcom_start(ifp); |
|
|
return (handled); |
return (handled); |
} |
} |
Line 1761 SIP_DECL(intr)(void *arg) |
|
Line 1974 SIP_DECL(intr)(void *arg) |
|
* Helper; handle transmit interrupts. |
* Helper; handle transmit interrupts. |
*/ |
*/ |
static void |
static void |
SIP_DECL(txintr)(struct sip_softc *sc) |
sipcom_txintr(struct sip_softc *sc) |
{ |
{ |
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
struct sip_txsoft *txs; |
struct sip_txsoft *txs; |
u_int32_t cmdsts; |
u_int32_t cmdsts; |
|
|
#ifndef DP83820 |
|
if (sc->sc_paused == 0) |
if (sc->sc_paused == 0) |
#endif |
|
ifp->if_flags &= ~IFF_OACTIVE; |
ifp->if_flags &= ~IFF_OACTIVE; |
|
|
/* |
/* |
Line 1777 SIP_DECL(txintr)(struct sip_softc *sc) |
|
Line 1988 SIP_DECL(txintr)(struct sip_softc *sc) |
|
* frames which have been transmitted. |
* frames which have been transmitted. |
*/ |
*/ |
while ((txs = SIMPLEQ_FIRST(&sc->sc_txdirtyq)) != NULL) { |
while ((txs = SIMPLEQ_FIRST(&sc->sc_txdirtyq)) != NULL) { |
SIP_CDTXSYNC(sc, txs->txs_firstdesc, txs->txs_dmamap->dm_nsegs, |
sip_cdtxsync(sc, txs->txs_firstdesc, txs->txs_dmamap->dm_nsegs, |
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); |
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); |
|
|
cmdsts = le32toh(sc->sc_txdescs[txs->txs_lastdesc].sipd_cmdsts); |
cmdsts = le32toh(*sipd_cmdsts(sc, &sc->sc_txdescs[txs->txs_lastdesc])); |
if (cmdsts & CMDSTS_OWN) |
if (cmdsts & CMDSTS_OWN) |
break; |
break; |
|
|
Line 1829 SIP_DECL(txintr)(struct sip_softc *sc) |
|
Line 2040 SIP_DECL(txintr)(struct sip_softc *sc) |
|
} |
} |
} |
} |
|
|
#if defined(DP83820) |
|
/* |
/* |
* sip_rxintr: |
* gsip_rxintr: |
* |
* |
* Helper; handle receive interrupts. |
* Helper; handle receive interrupts on gigabit parts. |
*/ |
*/ |
static void |
static void |
SIP_DECL(rxintr)(struct sip_softc *sc) |
gsip_rxintr(struct sip_softc *sc) |
{ |
{ |
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
struct sip_rxsoft *rxs; |
struct sip_rxsoft *rxs; |
Line 1844 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2054 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
u_int32_t cmdsts, extsts; |
u_int32_t cmdsts, extsts; |
int i, len; |
int i, len; |
|
|
for (i = sc->sc_rxptr;; i = SIP_NEXTRX(i)) { |
for (i = sc->sc_rxptr;; i = sip_nextrx(sc, i)) { |
rxs = &sc->sc_rxsoft[i]; |
rxs = &sc->sc_rxsoft[i]; |
|
|
SIP_CDRXSYNC(sc, i, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); |
sip_cdrxsync(sc, i, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); |
|
|
cmdsts = le32toh(sc->sc_rxdescs[i].sipd_cmdsts); |
cmdsts = le32toh(*sipd_cmdsts(sc, &sc->sc_rxdescs[i])); |
extsts = le32toh(sc->sc_rxdescs[i].sipd_extsts); |
extsts = le32toh(sc->sc_rxdescs[i].sipd_extsts); |
len = CMDSTS_SIZE(cmdsts); |
len = CMDSTS_SIZE(sc, cmdsts); |
|
|
/* |
/* |
* NOTE: OWN is set if owned by _consumer_. We're the |
* NOTE: OWN is set if owned by _consumer_. We're the |
Line 1866 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2076 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
} |
} |
|
|
if (__predict_false(sc->sc_rxdiscard)) { |
if (__predict_false(sc->sc_rxdiscard)) { |
SIP_INIT_RXDESC(sc, i); |
sip_init_rxdesc(sc, i); |
if ((cmdsts & CMDSTS_MORE) == 0) { |
if ((cmdsts & CMDSTS_MORE) == 0) { |
/* Reset our state. */ |
/* Reset our state. */ |
sc->sc_rxdiscard = 0; |
sc->sc_rxdiscard = 0; |
Line 1882 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2092 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
/* |
/* |
* Add a new receive buffer to the ring. |
* Add a new receive buffer to the ring. |
*/ |
*/ |
if (SIP_DECL(add_rxbuf)(sc, i) != 0) { |
if (sipcom_add_rxbuf(sc, i) != 0) { |
/* |
/* |
* Failed, throw away what we've done so |
* Failed, throw away what we've done so |
* far, and discard the rest of the packet. |
* far, and discard the rest of the packet. |
Line 1890 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2100 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
ifp->if_ierrors++; |
ifp->if_ierrors++; |
bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0, |
bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0, |
rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); |
rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); |
SIP_INIT_RXDESC(sc, i); |
sip_init_rxdesc(sc, i); |
if (cmdsts & CMDSTS_MORE) |
if (cmdsts & CMDSTS_MORE) |
sc->sc_rxdiscard = 1; |
sc->sc_rxdiscard = 1; |
if (sc->sc_rxhead != NULL) |
if (sc->sc_rxhead != NULL) |
m_freem(sc->sc_rxhead); |
m_freem(sc->sc_rxhead); |
SIP_RXCHAIN_RESET(sc); |
sip_rxchain_reset(sc); |
continue; |
continue; |
} |
} |
|
|
SIP_RXCHAIN_LINK(sc, m); |
sip_rxchain_link(sc, m); |
|
|
m->m_len = len; |
m->m_len = len; |
|
|
Line 1922 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2132 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
len = m->m_len + sc->sc_rxlen; |
len = m->m_len + sc->sc_rxlen; |
m = sc->sc_rxhead; |
m = sc->sc_rxhead; |
|
|
SIP_RXCHAIN_RESET(sc); |
sip_rxchain_reset(sc); |
|
|
/* |
/* |
* If an error occurred, update stats and drop the packet. |
* If an error occurred, update stats and drop the packet. |
Line 1956 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2166 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
* memory consumption when we receive lots |
* memory consumption when we receive lots |
* of small packets. |
* of small packets. |
*/ |
*/ |
if (SIP_DECL(copy_small) != 0 && len <= (MHLEN - 2)) { |
if (gsip_copy_small != 0 && len <= (MHLEN - 2)) { |
struct mbuf *nm; |
struct mbuf *nm; |
MGETHDR(nm, M_DONTWAIT, MT_DATA); |
MGETHDR(nm, M_DONTWAIT, MT_DATA); |
if (nm == NULL) { |
if (nm == NULL) { |
Line 2052 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2262 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
/* Update the receive pointer. */ |
/* Update the receive pointer. */ |
sc->sc_rxptr = i; |
sc->sc_rxptr = i; |
} |
} |
#else /* ! DP83820 */ |
|
/* |
/* |
* sip_rxintr: |
* sip_rxintr: |
* |
* |
* Helper; handle receive interrupts. |
* Helper; handle receive interrupts on 10/100 parts. |
*/ |
*/ |
static void |
static void |
SIP_DECL(rxintr)(struct sip_softc *sc) |
sip_rxintr(struct sip_softc *sc) |
{ |
{ |
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
struct sip_rxsoft *rxs; |
struct sip_rxsoft *rxs; |
Line 2067 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2277 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
u_int32_t cmdsts; |
u_int32_t cmdsts; |
int i, len; |
int i, len; |
|
|
for (i = sc->sc_rxptr;; i = SIP_NEXTRX(i)) { |
for (i = sc->sc_rxptr;; i = sip_nextrx(sc, i)) { |
rxs = &sc->sc_rxsoft[i]; |
rxs = &sc->sc_rxsoft[i]; |
|
|
SIP_CDRXSYNC(sc, i, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); |
sip_cdrxsync(sc, i, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); |
|
|
cmdsts = le32toh(sc->sc_rxdescs[i].sipd_cmdsts); |
cmdsts = le32toh(*sipd_cmdsts(sc, &sc->sc_rxdescs[i])); |
|
|
/* |
/* |
* NOTE: OWN is set if owned by _consumer_. We're the |
* NOTE: OWN is set if owned by _consumer_. We're the |
Line 2115 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2325 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
PRINTERR(CMDSTS_Rx_CRCE, "CRC error"); |
PRINTERR(CMDSTS_Rx_CRCE, "CRC error"); |
PRINTERR(CMDSTS_Rx_FAE, "frame alignment error"); |
PRINTERR(CMDSTS_Rx_FAE, "frame alignment error"); |
#undef PRINTERR |
#undef PRINTERR |
SIP_INIT_RXDESC(sc, i); |
sip_init_rxdesc(sc, i); |
continue; |
continue; |
} |
} |
|
|
Line 2126 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2336 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
* No errors; receive the packet. Note, the SiS 900 |
* No errors; receive the packet. Note, the SiS 900 |
* includes the CRC with every packet. |
* includes the CRC with every packet. |
*/ |
*/ |
len = CMDSTS_SIZE(cmdsts) - ETHER_CRC_LEN; |
len = CMDSTS_SIZE(sc, cmdsts) - ETHER_CRC_LEN; |
|
|
#ifdef __NO_STRICT_ALIGNMENT |
#ifdef __NO_STRICT_ALIGNMENT |
/* |
/* |
Line 2140 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2350 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
* chain. If this fails, we drop the packet and |
* chain. If this fails, we drop the packet and |
* recycle the old buffer. |
* recycle the old buffer. |
*/ |
*/ |
if (SIP_DECL(copy_small) != 0 && len <= MHLEN) { |
if (sip_copy_small != 0 && len <= MHLEN) { |
MGETHDR(m, M_DONTWAIT, MT_DATA); |
MGETHDR(m, M_DONTWAIT, MT_DATA); |
if (m == NULL) |
if (m == NULL) |
goto dropit; |
goto dropit; |
MCLAIM(m, &sc->sc_ethercom.ec_rx_mowner); |
MCLAIM(m, &sc->sc_ethercom.ec_rx_mowner); |
memcpy(mtod(m, void *), |
memcpy(mtod(m, void *), |
mtod(rxs->rxs_mbuf, void *), len); |
mtod(rxs->rxs_mbuf, void *), len); |
SIP_INIT_RXDESC(sc, i); |
sip_init_rxdesc(sc, i); |
bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0, |
bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0, |
rxs->rxs_dmamap->dm_mapsize, |
rxs->rxs_dmamap->dm_mapsize, |
BUS_DMASYNC_PREREAD); |
BUS_DMASYNC_PREREAD); |
} else { |
} else { |
m = rxs->rxs_mbuf; |
m = rxs->rxs_mbuf; |
if (SIP_DECL(add_rxbuf)(sc, i) != 0) { |
if (sipcom_add_rxbuf(sc, i) != 0) { |
dropit: |
dropit: |
ifp->if_ierrors++; |
ifp->if_ierrors++; |
SIP_INIT_RXDESC(sc, i); |
sip_init_rxdesc(sc, i); |
bus_dmamap_sync(sc->sc_dmat, |
bus_dmamap_sync(sc->sc_dmat, |
rxs->rxs_dmamap, 0, |
rxs->rxs_dmamap, 0, |
rxs->rxs_dmamap->dm_mapsize, |
rxs->rxs_dmamap->dm_mapsize, |
Line 2175 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2385 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
if (m == NULL) { |
if (m == NULL) { |
dropit: |
dropit: |
ifp->if_ierrors++; |
ifp->if_ierrors++; |
SIP_INIT_RXDESC(sc, i); |
sip_init_rxdesc(sc, i); |
bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0, |
bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0, |
rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); |
rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); |
continue; |
continue; |
Line 2197 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2407 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
memcpy(mtod(m, void *), mtod(rxs->rxs_mbuf, void *), len); |
memcpy(mtod(m, void *), mtod(rxs->rxs_mbuf, void *), len); |
|
|
/* Allow the receive descriptor to continue using its mbuf. */ |
/* Allow the receive descriptor to continue using its mbuf. */ |
SIP_INIT_RXDESC(sc, i); |
sip_init_rxdesc(sc, i); |
bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0, |
bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0, |
rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); |
rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); |
#endif /* __NO_STRICT_ALIGNMENT */ |
#endif /* __NO_STRICT_ALIGNMENT */ |
Line 2222 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2432 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
/* Update the receive pointer. */ |
/* Update the receive pointer. */ |
sc->sc_rxptr = i; |
sc->sc_rxptr = i; |
} |
} |
#endif /* DP83820 */ |
|
|
|
/* |
/* |
* sip_tick: |
* sip_tick: |
Line 2230 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
Line 2439 SIP_DECL(rxintr)(struct sip_softc *sc) |
|
* One second timer, used to tick the MII. |
* One second timer, used to tick the MII. |
*/ |
*/ |
static void |
static void |
SIP_DECL(tick)(void *arg) |
sipcom_tick(void *arg) |
{ |
{ |
struct sip_softc *sc = arg; |
struct sip_softc *sc = arg; |
int s; |
int s; |
|
|
s = splnet(); |
s = splnet(); |
#ifdef DP83820 |
|
#ifdef SIP_EVENT_COUNTERS |
#ifdef SIP_EVENT_COUNTERS |
/* Read PAUSE related counts from MIB registers. */ |
if (sc->sc_gigabit) { |
sc->sc_ev_rxpause.ev_count += |
/* Read PAUSE related counts from MIB registers. */ |
bus_space_read_4(sc->sc_st, sc->sc_sh, |
sc->sc_ev_rxpause.ev_count += |
SIP_NS_MIB(MIB_RXPauseFrames)) & 0xffff; |
bus_space_read_4(sc->sc_st, sc->sc_sh, |
sc->sc_ev_txpause.ev_count += |
SIP_NS_MIB(MIB_RXPauseFrames)) & 0xffff; |
bus_space_read_4(sc->sc_st, sc->sc_sh, |
sc->sc_ev_txpause.ev_count += |
SIP_NS_MIB(MIB_TXPauseFrames)) & 0xffff; |
bus_space_read_4(sc->sc_st, sc->sc_sh, |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_NS_MIBC, MIBC_ACLR); |
SIP_NS_MIB(MIB_TXPauseFrames)) & 0xffff; |
|
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_NS_MIBC, MIBC_ACLR); |
|
} |
#endif /* SIP_EVENT_COUNTERS */ |
#endif /* SIP_EVENT_COUNTERS */ |
#endif /* DP83820 */ |
|
mii_tick(&sc->sc_mii); |
mii_tick(&sc->sc_mii); |
splx(s); |
splx(s); |
|
|
callout_reset(&sc->sc_tick_ch, hz, SIP_DECL(tick), sc); |
callout_reset(&sc->sc_tick_ch, hz, sipcom_tick, sc); |
} |
} |
|
|
/* |
/* |
Line 2259 SIP_DECL(tick)(void *arg) |
|
Line 2468 SIP_DECL(tick)(void *arg) |
|
* |
* |
* Perform a soft reset on the SiS 900. |
* Perform a soft reset on the SiS 900. |
*/ |
*/ |
static void |
static bool |
SIP_DECL(reset)(struct sip_softc *sc) |
sipcom_reset(struct sip_softc *sc) |
{ |
{ |
bus_space_tag_t st = sc->sc_st; |
bus_space_tag_t st = sc->sc_st; |
bus_space_handle_t sh = sc->sc_sh; |
bus_space_handle_t sh = sc->sc_sh; |
Line 2277 SIP_DECL(reset)(struct sip_softc *sc) |
|
Line 2486 SIP_DECL(reset)(struct sip_softc *sc) |
|
delay(2); |
delay(2); |
} |
} |
|
|
if (i == SIP_TIMEOUT) |
if (i == SIP_TIMEOUT) { |
printf("%s: reset failed to complete\n", sc->sc_dev.dv_xname); |
printf("%s: reset failed to complete\n", sc->sc_dev.dv_xname); |
|
return false; |
|
} |
|
|
delay(1000); |
delay(1000); |
|
|
#ifdef DP83820 |
if (sc->sc_gigabit) { |
|
/* |
|
* Set the general purpose I/O bits. Do it here in case we |
|
* need to have GPIO set up to talk to the media interface. |
|
*/ |
|
bus_space_write_4(st, sh, SIP_GPIOR, sc->sc_gpior); |
|
delay(1000); |
|
} |
|
return true; |
|
} |
|
|
|
static void |
|
sipcom_dp83820_init(struct sip_softc *sc, uint64_t capenable) |
|
{ |
|
u_int32_t reg; |
|
bus_space_tag_t st = sc->sc_st; |
|
bus_space_handle_t sh = sc->sc_sh; |
/* |
/* |
* Set the general purpose I/O bits. Do it here in case we |
* Initialize the VLAN/IP receive control register. |
* need to have GPIO set up to talk to the media interface. |
* We enable checksum computation on all incoming |
|
* packets, and do not reject packets w/ bad checksums. |
*/ |
*/ |
bus_space_write_4(st, sh, SIP_GPIOR, sc->sc_gpior); |
reg = 0; |
delay(1000); |
if (capenable & |
#endif /* DP83820 */ |
(IFCAP_CSUM_IPv4_Rx|IFCAP_CSUM_TCPv4_Rx|IFCAP_CSUM_UDPv4_Rx)) |
|
reg |= VRCR_IPEN; |
|
if (VLAN_ATTACHED(&sc->sc_ethercom)) |
|
reg |= VRCR_VTDEN|VRCR_VTREN; |
|
bus_space_write_4(st, sh, SIP_VRCR, reg); |
|
|
|
/* |
|
* Initialize the VLAN/IP transmit control register. |
|
* We enable outgoing checksum computation on a |
|
* per-packet basis. |
|
*/ |
|
reg = 0; |
|
if (capenable & |
|
(IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_UDPv4_Tx)) |
|
reg |= VTCR_PPCHK; |
|
if (VLAN_ATTACHED(&sc->sc_ethercom)) |
|
reg |= VTCR_VPPTI; |
|
bus_space_write_4(st, sh, SIP_VTCR, reg); |
|
|
|
/* |
|
* If we're using VLANs, initialize the VLAN data register. |
|
* To understand why we bswap the VLAN Ethertype, see section |
|
* 4.2.36 of the DP83820 manual. |
|
*/ |
|
if (VLAN_ATTACHED(&sc->sc_ethercom)) |
|
bus_space_write_4(st, sh, SIP_VDR, bswap16(ETHERTYPE_VLAN)); |
} |
} |
|
|
/* |
/* |
Line 2298 SIP_DECL(reset)(struct sip_softc *sc) |
|
Line 2551 SIP_DECL(reset)(struct sip_softc *sc) |
|
* Initialize the interface. Must be called at splnet(). |
* Initialize the interface. Must be called at splnet(). |
*/ |
*/ |
static int |
static int |
SIP_DECL(init)(struct ifnet *ifp) |
sipcom_init(struct ifnet *ifp) |
{ |
{ |
struct sip_softc *sc = ifp->if_softc; |
struct sip_softc *sc = ifp->if_softc; |
bus_space_tag_t st = sc->sc_st; |
bus_space_tag_t st = sc->sc_st; |
Line 2306 SIP_DECL(init)(struct ifnet *ifp) |
|
Line 2559 SIP_DECL(init)(struct ifnet *ifp) |
|
struct sip_txsoft *txs; |
struct sip_txsoft *txs; |
struct sip_rxsoft *rxs; |
struct sip_rxsoft *rxs; |
struct sip_desc *sipd; |
struct sip_desc *sipd; |
#if defined(DP83820) |
|
u_int32_t reg; |
|
#endif |
|
int i, error = 0; |
int i, error = 0; |
|
|
/* |
if (device_is_active(&sc->sc_dev)) { |
* Cancel any pending I/O. |
/* |
*/ |
* Cancel any pending I/O. |
SIP_DECL(stop)(ifp, 0); |
*/ |
|
sipcom_stop(ifp, 0); |
|
} else if (!pmf_device_resume_self(&sc->sc_dev)) |
|
return 0; |
|
|
/* |
/* |
* Reset the chip to a known state. |
* Reset the chip to a known state. |
*/ |
*/ |
SIP_DECL(reset)(sc); |
if (!sipcom_reset(sc)) |
|
return EBUSY; |
|
|
#if !defined(DP83820) |
|
if (SIP_CHIP_MODEL(sc, PCI_VENDOR_NS, PCI_PRODUCT_NS_DP83815)) { |
if (SIP_CHIP_MODEL(sc, PCI_VENDOR_NS, PCI_PRODUCT_NS_DP83815)) { |
/* |
/* |
* DP83815 manual, page 78: |
* DP83815 manual, page 78: |
Line 2350 SIP_DECL(init)(struct ifnet *ifp) |
|
Line 2603 SIP_DECL(init)(struct ifnet *ifp) |
|
|
|
bus_space_write_4(st, sh, 0x00cc, 0x0000); |
bus_space_write_4(st, sh, 0x00cc, 0x0000); |
} |
} |
#endif /* ! DP83820 */ |
|
|
|
/* |
/* |
* Initialize the transmit descriptor ring. |
* Initialize the transmit descriptor ring. |
*/ |
*/ |
for (i = 0; i < SIP_NTXDESC; i++) { |
for (i = 0; i < sc->sc_ntxdesc; i++) { |
sipd = &sc->sc_txdescs[i]; |
sipd = &sc->sc_txdescs[i]; |
memset(sipd, 0, sizeof(struct sip_desc)); |
memset(sipd, 0, sizeof(struct sip_desc)); |
sipd->sipd_link = htole32(SIP_CDTXADDR(sc, SIP_NEXTTX(i))); |
sipd->sipd_link = htole32(SIP_CDTXADDR(sc, sip_nexttx(sc, i))); |
} |
} |
SIP_CDTXSYNC(sc, 0, SIP_NTXDESC, |
sip_cdtxsync(sc, 0, sc->sc_ntxdesc, |
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
sc->sc_txfree = SIP_NTXDESC; |
sc->sc_txfree = sc->sc_ntxdesc; |
sc->sc_txnext = 0; |
sc->sc_txnext = 0; |
sc->sc_txwin = 0; |
sc->sc_txwin = 0; |
|
|
Line 2381 SIP_DECL(init)(struct ifnet *ifp) |
|
Line 2633 SIP_DECL(init)(struct ifnet *ifp) |
|
* Initialize the receive descriptor and receive job |
* Initialize the receive descriptor and receive job |
* descriptor rings. |
* descriptor rings. |
*/ |
*/ |
for (i = 0; i < SIP_NRXDESC; i++) { |
for (i = 0; i < sc->sc_parm->p_nrxdesc; i++) { |
rxs = &sc->sc_rxsoft[i]; |
rxs = &sc->sc_rxsoft[i]; |
if (rxs->rxs_mbuf == NULL) { |
if (rxs->rxs_mbuf == NULL) { |
if ((error = SIP_DECL(add_rxbuf)(sc, i)) != 0) { |
if ((error = sipcom_add_rxbuf(sc, i)) != 0) { |
printf("%s: unable to allocate or map rx " |
printf("%s: unable to allocate or map rx " |
"buffer %d, error = %d\n", |
"buffer %d, error = %d\n", |
sc->sc_dev.dv_xname, i, error); |
sc->sc_dev.dv_xname, i, error); |
Line 2392 SIP_DECL(init)(struct ifnet *ifp) |
|
Line 2644 SIP_DECL(init)(struct ifnet *ifp) |
|
* XXX Should attempt to run with fewer receive |
* XXX Should attempt to run with fewer receive |
* XXX buffers instead of just failing. |
* XXX buffers instead of just failing. |
*/ |
*/ |
SIP_DECL(rxdrain)(sc); |
sipcom_rxdrain(sc); |
goto out; |
goto out; |
} |
} |
} else |
} else |
SIP_INIT_RXDESC(sc, i); |
sip_init_rxdesc(sc, i); |
} |
} |
sc->sc_rxptr = 0; |
sc->sc_rxptr = 0; |
#ifdef DP83820 |
|
sc->sc_rxdiscard = 0; |
sc->sc_rxdiscard = 0; |
SIP_RXCHAIN_RESET(sc); |
sip_rxchain_reset(sc); |
#endif /* DP83820 */ |
|
|
|
/* |
/* |
* Set the configuration register; it's already initialized |
* Set the configuration register; it's already initialized |
Line 2413 SIP_DECL(init)(struct ifnet *ifp) |
|
Line 2663 SIP_DECL(init)(struct ifnet *ifp) |
|
/* |
/* |
* Initialize the prototype TXCFG register. |
* Initialize the prototype TXCFG register. |
*/ |
*/ |
#if defined(DP83820) |
if (sc->sc_gigabit) { |
sc->sc_txcfg = TXCFG_MXDMA_512; |
sc->sc_txcfg = sc->sc_bits.b_txcfg_mxdma_512; |
sc->sc_rxcfg = RXCFG_MXDMA_512; |
sc->sc_rxcfg = sc->sc_bits.b_rxcfg_mxdma_512; |
#else |
} else if ((SIP_SIS900_REV(sc, SIS_REV_635) || |
if ((SIP_SIS900_REV(sc, SIS_REV_635) || |
|
SIP_SIS900_REV(sc, SIS_REV_960) || |
SIP_SIS900_REV(sc, SIS_REV_960) || |
SIP_SIS900_REV(sc, SIS_REV_900B)) && |
SIP_SIS900_REV(sc, SIS_REV_900B)) && |
(sc->sc_cfg & CFG_EDBMASTEN)) { |
(sc->sc_cfg & CFG_EDBMASTEN)) { |
sc->sc_txcfg = TXCFG_MXDMA_64; |
sc->sc_txcfg = sc->sc_bits.b_txcfg_mxdma_64; |
sc->sc_rxcfg = RXCFG_MXDMA_64; |
sc->sc_rxcfg = sc->sc_bits.b_rxcfg_mxdma_64; |
} else { |
} else { |
sc->sc_txcfg = TXCFG_MXDMA_512; |
sc->sc_txcfg = sc->sc_bits.b_txcfg_mxdma_512; |
sc->sc_rxcfg = RXCFG_MXDMA_512; |
sc->sc_rxcfg = sc->sc_bits.b_rxcfg_mxdma_512; |
} |
} |
#endif /* DP83820 */ |
|
|
|
sc->sc_txcfg |= TXCFG_ATP | |
sc->sc_txcfg |= TXCFG_ATP | |
(sc->sc_tx_fill_thresh << TXCFG_FLTH_SHIFT) | |
__SHIFTIN(sc->sc_tx_fill_thresh, sc->sc_bits.b_txcfg_flth_mask) | |
sc->sc_tx_drain_thresh; |
sc->sc_tx_drain_thresh; |
bus_space_write_4(st, sh, SIP_TXCFG, sc->sc_txcfg); |
bus_space_write_4(st, sh, sc->sc_regs.r_txcfg, sc->sc_txcfg); |
|
|
/* |
/* |
* Initialize the receive drain threshold if we have never |
* Initialize the receive drain threshold if we have never |
Line 2446 SIP_DECL(init)(struct ifnet *ifp) |
|
Line 2694 SIP_DECL(init)(struct ifnet *ifp) |
|
* set this value lower than 2; 14 bytes are required to |
* set this value lower than 2; 14 bytes are required to |
* filter the packet). |
* filter the packet). |
*/ |
*/ |
sc->sc_rx_drain_thresh = RXCFG_DRTH >> RXCFG_DRTH_SHIFT; |
sc->sc_rx_drain_thresh = __SHIFTOUT_MASK(RXCFG_DRTH_MASK); |
} |
} |
|
|
/* |
/* |
* Initialize the prototype RXCFG register. |
* Initialize the prototype RXCFG register. |
*/ |
*/ |
sc->sc_rxcfg |= (sc->sc_rx_drain_thresh << RXCFG_DRTH_SHIFT); |
sc->sc_rxcfg |= __SHIFTIN(sc->sc_rx_drain_thresh, RXCFG_DRTH_MASK); |
#ifdef DP83820 |
|
/* |
/* |
* Accept long packets (including FCS) so we can handle |
* Accept long packets (including FCS) so we can handle |
* 802.1q-tagged frames and jumbo frames properly. |
* 802.1q-tagged frames and jumbo frames properly. |
*/ |
*/ |
if (ifp->if_mtu > ETHERMTU || |
if ((sc->sc_gigabit && ifp->if_mtu > ETHERMTU) || |
(sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU)) |
(sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU)) |
sc->sc_rxcfg |= RXCFG_ALP; |
sc->sc_rxcfg |= RXCFG_ALP; |
|
|
Line 2468 SIP_DECL(init)(struct ifnet *ifp) |
|
Line 2715 SIP_DECL(init)(struct ifnet *ifp) |
|
* evidence that >8109 does not work on some boards, such as the |
* evidence that >8109 does not work on some boards, such as the |
* Planex GN-1000TE). |
* Planex GN-1000TE). |
*/ |
*/ |
if (ifp->if_mtu > 8109 && |
if (sc->sc_gigabit && ifp->if_mtu > 8109 && |
(ifp->if_capenable & |
(ifp->if_capenable & |
(IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_IPv4_Rx| |
(IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_IPv4_Rx| |
IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_TCPv4_Rx| |
IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_TCPv4_Rx| |
Line 2482 SIP_DECL(init)(struct ifnet *ifp) |
|
Line 2729 SIP_DECL(init)(struct ifnet *ifp) |
|
ifp->if_csum_flags_tx = 0; |
ifp->if_csum_flags_tx = 0; |
ifp->if_csum_flags_rx = 0; |
ifp->if_csum_flags_rx = 0; |
} |
} |
#else |
|
/* |
|
* Accept packets >1518 bytes (including FCS) so we can handle |
|
* 802.1q-tagged frames properly. |
|
*/ |
|
if (sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU) |
|
sc->sc_rxcfg |= RXCFG_ALP; |
|
#endif |
|
bus_space_write_4(st, sh, SIP_RXCFG, sc->sc_rxcfg); |
|
|
|
#ifdef DP83820 |
|
/* |
|
* Initialize the VLAN/IP receive control register. |
|
* We enable checksum computation on all incoming |
|
* packets, and do not reject packets w/ bad checksums. |
|
*/ |
|
reg = 0; |
|
if (ifp->if_capenable & |
|
(IFCAP_CSUM_IPv4_Rx|IFCAP_CSUM_TCPv4_Rx|IFCAP_CSUM_UDPv4_Rx)) |
|
reg |= VRCR_IPEN; |
|
if (VLAN_ATTACHED(&sc->sc_ethercom)) |
|
reg |= VRCR_VTDEN|VRCR_VTREN; |
|
bus_space_write_4(st, sh, SIP_VRCR, reg); |
|
|
|
/* |
bus_space_write_4(st, sh, sc->sc_regs.r_rxcfg, sc->sc_rxcfg); |
* Initialize the VLAN/IP transmit control register. |
|
* We enable outgoing checksum computation on a |
|
* per-packet basis. |
|
*/ |
|
reg = 0; |
|
if (ifp->if_capenable & |
|
(IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_UDPv4_Tx)) |
|
reg |= VTCR_PPCHK; |
|
if (VLAN_ATTACHED(&sc->sc_ethercom)) |
|
reg |= VTCR_VPPTI; |
|
bus_space_write_4(st, sh, SIP_VTCR, reg); |
|
|
|
/* |
if (sc->sc_gigabit) |
* If we're using VLANs, initialize the VLAN data register. |
sipcom_dp83820_init(sc, ifp->if_capenable); |
* To understand why we bswap the VLAN Ethertype, see section |
|
* 4.2.36 of the DP83820 manual. |
|
*/ |
|
if (VLAN_ATTACHED(&sc->sc_ethercom)) |
|
bus_space_write_4(st, sh, SIP_VDR, bswap16(ETHERTYPE_VLAN)); |
|
#endif /* DP83820 */ |
|
|
|
/* |
/* |
* Give the transmit and receive rings to the chip. |
* Give the transmit and receive rings to the chip. |
Line 2537 SIP_DECL(init)(struct ifnet *ifp) |
|
Line 2744 SIP_DECL(init)(struct ifnet *ifp) |
|
/* |
/* |
* Initialize the interrupt mask. |
* Initialize the interrupt mask. |
*/ |
*/ |
sc->sc_imr = ISR_DPERR|ISR_SSERR|ISR_RMABT|ISR_RTABT|ISR_RXSOVR| |
sc->sc_imr = sc->sc_bits.b_isr_dperr | |
|
sc->sc_bits.b_isr_sserr | |
|
sc->sc_bits.b_isr_rmabt | |
|
sc->sc_bits.b_isr_rtabt | ISR_RXSOVR | |
ISR_TXURN|ISR_TXDESC|ISR_TXIDLE|ISR_RXORN|ISR_RXIDLE|ISR_RXDESC; |
ISR_TXURN|ISR_TXDESC|ISR_TXIDLE|ISR_RXORN|ISR_RXIDLE|ISR_RXDESC; |
bus_space_write_4(st, sh, SIP_IMR, sc->sc_imr); |
bus_space_write_4(st, sh, SIP_IMR, sc->sc_imr); |
|
|
/* Set up the receive filter. */ |
/* Set up the receive filter. */ |
(*sc->sc_model->sip_variant->sipv_set_filter)(sc); |
(*sc->sc_model->sip_variant->sipv_set_filter)(sc); |
|
|
#ifdef DP83820 |
|
/* |
/* |
* Tune sc_rx_flow_thresh. |
* Tune sc_rx_flow_thresh. |
* XXX "More than 8KB" is too short for jumbo frames. |
* XXX "More than 8KB" is too short for jumbo frames. |
Line 2553 SIP_DECL(init)(struct ifnet *ifp) |
|
Line 2762 SIP_DECL(init)(struct ifnet *ifp) |
|
sc->sc_rx_flow_thresh = (PCR_PS_STHI_8 | PCR_PS_STLO_4 | |
sc->sc_rx_flow_thresh = (PCR_PS_STHI_8 | PCR_PS_STLO_4 | |
PCR_PS_FFHI_8 | PCR_PS_FFLO_4 | |
PCR_PS_FFHI_8 | PCR_PS_FFLO_4 | |
(PCR_PAUSE_CNT & PCR_PAUSE_CNT_MASK)); |
(PCR_PAUSE_CNT & PCR_PAUSE_CNT_MASK)); |
#endif |
|
|
|
/* |
/* |
* Set the current media. Do this after initializing the prototype |
* Set the current media. Do this after initializing the prototype |
* IMR, since sip_mii_statchg() modifies the IMR for 802.3x flow |
* IMR, since sip_mii_statchg() modifies the IMR for 802.3x flow |
* control. |
* control. |
*/ |
*/ |
mii_mediachg(&sc->sc_mii); |
if ((error = ether_mediachange(ifp)) != 0) |
|
goto out; |
|
|
#ifdef DP83820 |
|
/* |
/* |
* Set the interrupt hold-off timer to 100us. |
* Set the interrupt hold-off timer to 100us. |
*/ |
*/ |
bus_space_write_4(st, sh, SIP_IHR, 0x01); |
if (sc->sc_gigabit) |
#endif |
bus_space_write_4(st, sh, SIP_IHR, 0x01); |
|
|
/* |
/* |
* Enable interrupts. |
* Enable interrupts. |
Line 2582 SIP_DECL(init)(struct ifnet *ifp) |
|
Line 2790 SIP_DECL(init)(struct ifnet *ifp) |
|
/* |
/* |
* Start the one second MII clock. |
* Start the one second MII clock. |
*/ |
*/ |
callout_reset(&sc->sc_tick_ch, hz, SIP_DECL(tick), sc); |
callout_reset(&sc->sc_tick_ch, hz, sipcom_tick, sc); |
|
|
/* |
/* |
* ...all done! |
* ...all done! |
Line 2606 SIP_DECL(init)(struct ifnet *ifp) |
|
Line 2814 SIP_DECL(init)(struct ifnet *ifp) |
|
* Drain the receive queue. |
* Drain the receive queue. |
*/ |
*/ |
static void |
static void |
SIP_DECL(rxdrain)(struct sip_softc *sc) |
sipcom_rxdrain(struct sip_softc *sc) |
{ |
{ |
struct sip_rxsoft *rxs; |
struct sip_rxsoft *rxs; |
int i; |
int i; |
|
|
for (i = 0; i < SIP_NRXDESC; i++) { |
for (i = 0; i < sc->sc_parm->p_nrxdesc; i++) { |
rxs = &sc->sc_rxsoft[i]; |
rxs = &sc->sc_rxsoft[i]; |
if (rxs->rxs_mbuf != NULL) { |
if (rxs->rxs_mbuf != NULL) { |
bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmamap); |
bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmamap); |
Line 2627 SIP_DECL(rxdrain)(struct sip_softc *sc) |
|
Line 2835 SIP_DECL(rxdrain)(struct sip_softc *sc) |
|
* Stop transmission on the interface. |
* Stop transmission on the interface. |
*/ |
*/ |
static void |
static void |
SIP_DECL(stop)(struct ifnet *ifp, int disable) |
sipcom_stop(struct ifnet *ifp, int disable) |
{ |
{ |
struct sip_softc *sc = ifp->if_softc; |
struct sip_softc *sc = ifp->if_softc; |
bus_space_tag_t st = sc->sc_st; |
bus_space_tag_t st = sc->sc_st; |
Line 2659 SIP_DECL(stop)(struct ifnet *ifp, int di |
|
Line 2867 SIP_DECL(stop)(struct ifnet *ifp, int di |
|
while ((txs = SIMPLEQ_FIRST(&sc->sc_txdirtyq)) != NULL) { |
while ((txs = SIMPLEQ_FIRST(&sc->sc_txdirtyq)) != NULL) { |
if ((ifp->if_flags & IFF_DEBUG) != 0 && |
if ((ifp->if_flags & IFF_DEBUG) != 0 && |
SIMPLEQ_NEXT(txs, txs_q) == NULL && |
SIMPLEQ_NEXT(txs, txs_q) == NULL && |
(le32toh(sc->sc_txdescs[txs->txs_lastdesc].sipd_cmdsts) & |
(le32toh(*sipd_cmdsts(sc, &sc->sc_txdescs[txs->txs_lastdesc])) & |
CMDSTS_INTR) == 0) |
CMDSTS_INTR) == 0) |
printf("%s: sip_stop: last descriptor does not " |
printf("%s: sip_stop: last descriptor does not " |
"have INTR bit set\n", sc->sc_dev.dv_xname); |
"have INTR bit set\n", sc->sc_dev.dv_xname); |
Line 2672 SIP_DECL(stop)(struct ifnet *ifp, int di |
|
Line 2880 SIP_DECL(stop)(struct ifnet *ifp, int di |
|
} |
} |
#endif |
#endif |
cmdsts |= /* DEBUG */ |
cmdsts |= /* DEBUG */ |
le32toh(sc->sc_txdescs[txs->txs_lastdesc].sipd_cmdsts); |
le32toh(*sipd_cmdsts(sc, &sc->sc_txdescs[txs->txs_lastdesc])); |
bus_dmamap_unload(sc->sc_dmat, txs->txs_dmamap); |
bus_dmamap_unload(sc->sc_dmat, txs->txs_dmamap); |
m_freem(txs->txs_mbuf); |
m_freem(txs->txs_mbuf); |
txs->txs_mbuf = NULL; |
txs->txs_mbuf = NULL; |
SIMPLEQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q); |
SIMPLEQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q); |
} |
} |
|
|
if (disable) |
|
SIP_DECL(rxdrain)(sc); |
|
|
|
/* |
/* |
* Mark the interface down and cancel the watchdog timer. |
* Mark the interface down and cancel the watchdog timer. |
*/ |
*/ |
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); |
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); |
ifp->if_timer = 0; |
ifp->if_timer = 0; |
|
|
|
if (disable) |
|
pmf_device_suspend_self(&sc->sc_dev); |
|
|
if ((ifp->if_flags & IFF_DEBUG) != 0 && |
if ((ifp->if_flags & IFF_DEBUG) != 0 && |
(cmdsts & CMDSTS_INTR) == 0 && sc->sc_txfree != SIP_NTXDESC) |
(cmdsts & CMDSTS_INTR) == 0 && sc->sc_txfree != sc->sc_ntxdesc) |
printf("%s: sip_stop: no INTR bits set in dirty tx " |
printf("%s: sip_stop: no INTR bits set in dirty tx " |
"descriptors\n", sc->sc_dev.dv_xname); |
"descriptors\n", sc->sc_dev.dv_xname); |
} |
} |
Line 2700 SIP_DECL(stop)(struct ifnet *ifp, int di |
|
Line 2908 SIP_DECL(stop)(struct ifnet *ifp, int di |
|
* Read data from the serial EEPROM. |
* Read data from the serial EEPROM. |
*/ |
*/ |
static void |
static void |
SIP_DECL(read_eeprom)(struct sip_softc *sc, int word, int wordcnt, |
sipcom_read_eeprom(struct sip_softc *sc, int word, int wordcnt, |
u_int16_t *data) |
u_int16_t *data) |
{ |
{ |
bus_space_tag_t st = sc->sc_st; |
bus_space_tag_t st = sc->sc_st; |
Line 2761 SIP_DECL(read_eeprom)(struct sip_softc * |
|
Line 2969 SIP_DECL(read_eeprom)(struct sip_softc * |
|
} |
} |
|
|
/* |
/* |
* sip_add_rxbuf: |
* sipcom_add_rxbuf: |
* |
* |
* Add a receive buffer to the indicated descriptor. |
* Add a receive buffer to the indicated descriptor. |
*/ |
*/ |
static int |
static int |
SIP_DECL(add_rxbuf)(struct sip_softc *sc, int idx) |
sipcom_add_rxbuf(struct sip_softc *sc, int idx) |
{ |
{ |
struct sip_rxsoft *rxs = &sc->sc_rxsoft[idx]; |
struct sip_rxsoft *rxs = &sc->sc_rxsoft[idx]; |
struct mbuf *m; |
struct mbuf *m; |
Line 2783 SIP_DECL(add_rxbuf)(struct sip_softc *sc |
|
Line 2991 SIP_DECL(add_rxbuf)(struct sip_softc *sc |
|
return (ENOBUFS); |
return (ENOBUFS); |
} |
} |
|
|
#if defined(DP83820) |
/* XXX I don't believe this is necessary. --dyoung */ |
m->m_len = SIP_RXBUF_LEN; |
if (sc->sc_gigabit) |
#endif /* DP83820 */ |
m->m_len = sc->sc_parm->p_rxbuf_len; |
|
|
if (rxs->rxs_mbuf != NULL) |
if (rxs->rxs_mbuf != NULL) |
bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmamap); |
bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmamap); |
Line 2798 SIP_DECL(add_rxbuf)(struct sip_softc *sc |
|
Line 3006 SIP_DECL(add_rxbuf)(struct sip_softc *sc |
|
if (error) { |
if (error) { |
printf("%s: can't load rx DMA map %d, error = %d\n", |
printf("%s: can't load rx DMA map %d, error = %d\n", |
sc->sc_dev.dv_xname, idx, error); |
sc->sc_dev.dv_xname, idx, error); |
panic("sip_add_rxbuf"); /* XXX */ |
panic("%s", __func__); /* XXX */ |
} |
} |
|
|
bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0, |
bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0, |
rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); |
rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); |
|
|
SIP_INIT_RXDESC(sc, idx); |
sip_init_rxdesc(sc, idx); |
|
|
return (0); |
return (0); |
} |
} |
|
|
#if !defined(DP83820) |
|
/* |
/* |
* sip_sis900_set_filter: |
* sip_sis900_set_filter: |
* |
* |
* Set up the receive filter. |
* Set up the receive filter. |
*/ |
*/ |
static void |
static void |
SIP_DECL(sis900_set_filter)(struct sip_softc *sc) |
sipcom_sis900_set_filter(struct sip_softc *sc) |
{ |
{ |
bus_space_tag_t st = sc->sc_st; |
bus_space_tag_t st = sc->sc_st; |
bus_space_handle_t sh = sc->sc_sh; |
bus_space_handle_t sh = sc->sc_sh; |
struct ethercom *ec = &sc->sc_ethercom; |
struct ethercom *ec = &sc->sc_ethercom; |
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
struct ether_multi *enm; |
struct ether_multi *enm; |
u_int8_t *cp; |
const u_int8_t *cp; |
struct ether_multistep step; |
struct ether_multistep step; |
u_int32_t crc, mchash[16]; |
u_int32_t crc, mchash[16]; |
|
|
Line 2917 SIP_DECL(sis900_set_filter)(struct sip_s |
|
Line 3124 SIP_DECL(sis900_set_filter)(struct sip_s |
|
/* |
/* |
* Disable receive filter, and program the node address. |
* Disable receive filter, and program the node address. |
*/ |
*/ |
cp = LLADDR(ifp->if_sadl); |
cp = CLLADDR(ifp->if_sadl); |
FILTER_EMIT(RFCR_RFADDR_NODE0, (cp[1] << 8) | cp[0]); |
FILTER_EMIT(RFCR_RFADDR_NODE0, (cp[1] << 8) | cp[0]); |
FILTER_EMIT(RFCR_RFADDR_NODE2, (cp[3] << 8) | cp[2]); |
FILTER_EMIT(RFCR_RFADDR_NODE2, (cp[3] << 8) | cp[2]); |
FILTER_EMIT(RFCR_RFADDR_NODE4, (cp[5] << 8) | cp[4]); |
FILTER_EMIT(RFCR_RFADDR_NODE4, (cp[5] << 8) | cp[4]); |
Line 2954 SIP_DECL(sis900_set_filter)(struct sip_s |
|
Line 3161 SIP_DECL(sis900_set_filter)(struct sip_s |
|
*/ |
*/ |
bus_space_write_4(st, sh, SIP_RFCR, sc->sc_rfcr); |
bus_space_write_4(st, sh, SIP_RFCR, sc->sc_rfcr); |
} |
} |
#endif /* ! DP83820 */ |
|
|
|
/* |
/* |
* sip_dp83815_set_filter: |
* sip_dp83815_set_filter: |
Line 2962 SIP_DECL(sis900_set_filter)(struct sip_s |
|
Line 3168 SIP_DECL(sis900_set_filter)(struct sip_s |
|
* Set up the receive filter. |
* Set up the receive filter. |
*/ |
*/ |
static void |
static void |
SIP_DECL(dp83815_set_filter)(struct sip_softc *sc) |
sipcom_dp83815_set_filter(struct sip_softc *sc) |
{ |
{ |
bus_space_tag_t st = sc->sc_st; |
bus_space_tag_t st = sc->sc_st; |
bus_space_handle_t sh = sc->sc_sh; |
bus_space_handle_t sh = sc->sc_sh; |
struct ethercom *ec = &sc->sc_ethercom; |
struct ethercom *ec = &sc->sc_ethercom; |
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
struct ether_multi *enm; |
struct ether_multi *enm; |
u_int8_t *cp; |
const u_int8_t *cp; |
struct ether_multistep step; |
struct ether_multistep step; |
u_int32_t crc, hash, slot, bit; |
u_int32_t crc, hash, slot, bit; |
#ifdef DP83820 |
#define MCHASH_NWORDS_83820 128 |
#define MCHASH_NWORDS 128 |
#define MCHASH_NWORDS_83815 32 |
#else |
#define MCHASH_NWORDS MAX(MCHASH_NWORDS_83820, MCHASH_NWORDS_83815) |
#define MCHASH_NWORDS 32 |
|
#endif /* DP83820 */ |
|
u_int16_t mchash[MCHASH_NWORDS]; |
u_int16_t mchash[MCHASH_NWORDS]; |
int i; |
int i; |
|
|
Line 2996 SIP_DECL(dp83815_set_filter)(struct sip_ |
|
Line 3200 SIP_DECL(dp83815_set_filter)(struct sip_ |
|
goto allmulti; |
goto allmulti; |
} |
} |
|
|
#ifdef DP83820 |
|
/* |
/* |
* Set up the DP83820 multicast address filter by passing all multicast |
* Set up the DP83820/DP83815 multicast address filter by |
* addresses through a CRC generator, and then using the high-order |
* passing all multicast addresses through a CRC generator, |
* 11 bits as an index into the 2048 bit multicast hash table. The |
* and then using the high-order 11/9 bits as an index into |
* high-order 7 bits select the slot, while the low-order 4 bits |
* the 2048/512 bit multicast hash table. The high-order |
* select the bit within the slot. Note that only the low 16-bits |
* 7/5 bits select the slot, while the low-order 4 bits |
* of each filter word are used, and there are 128 filter words. |
* select the bit within the slot. Note that only the low |
*/ |
* 16-bits of each filter word are used, and there are |
#else |
* 128/32 filter words. |
/* |
|
* Set up the DP83815 multicast address filter by passing all multicast |
|
* addresses through a CRC generator, and then using the high-order |
|
* 9 bits as an index into the 512 bit multicast hash table. The |
|
* high-order 5 bits select the slot, while the low-order 4 bits |
|
* select the bit within the slot. Note that only the low 16-bits |
|
* of each filter word are used, and there are 32 filter words. |
|
*/ |
*/ |
#endif /* DP83820 */ |
|
|
|
memset(mchash, 0, sizeof(mchash)); |
memset(mchash, 0, sizeof(mchash)); |
|
|
Line 3037 SIP_DECL(dp83815_set_filter)(struct sip_ |
|
Line 3232 SIP_DECL(dp83815_set_filter)(struct sip_ |
|
|
|
crc = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); |
crc = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); |
|
|
#ifdef DP83820 |
if (sc->sc_gigabit) { |
/* Just want the 11 most significant bits. */ |
/* Just want the 11 most significant bits. */ |
hash = crc >> 21; |
hash = crc >> 21; |
#else |
} else { |
/* Just want the 9 most significant bits. */ |
/* Just want the 9 most significant bits. */ |
hash = crc >> 23; |
hash = crc >> 23; |
#endif /* DP83820 */ |
} |
|
|
slot = hash >> 4; |
slot = hash >> 4; |
bit = hash & 0xf; |
bit = hash & 0xf; |
Line 3070 SIP_DECL(dp83815_set_filter)(struct sip_ |
|
Line 3265 SIP_DECL(dp83815_set_filter)(struct sip_ |
|
/* |
/* |
* Disable receive filter, and program the node address. |
* Disable receive filter, and program the node address. |
*/ |
*/ |
cp = LLADDR(ifp->if_sadl); |
cp = CLLADDR(ifp->if_sadl); |
FILTER_EMIT(RFCR_NS_RFADDR_PMATCH0, (cp[1] << 8) | cp[0]); |
FILTER_EMIT(RFCR_NS_RFADDR_PMATCH0, (cp[1] << 8) | cp[0]); |
FILTER_EMIT(RFCR_NS_RFADDR_PMATCH2, (cp[3] << 8) | cp[2]); |
FILTER_EMIT(RFCR_NS_RFADDR_PMATCH2, (cp[3] << 8) | cp[2]); |
FILTER_EMIT(RFCR_NS_RFADDR_PMATCH4, (cp[5] << 8) | cp[4]); |
FILTER_EMIT(RFCR_NS_RFADDR_PMATCH4, (cp[5] << 8) | cp[4]); |
|
|
if ((ifp->if_flags & IFF_ALLMULTI) == 0) { |
if ((ifp->if_flags & IFF_ALLMULTI) == 0) { |
|
int nwords = |
|
sc->sc_gigabit ? MCHASH_NWORDS_83820 : MCHASH_NWORDS_83815; |
/* |
/* |
* Program the multicast hash table. |
* Program the multicast hash table. |
*/ |
*/ |
for (i = 0; i < MCHASH_NWORDS; i++) { |
for (i = 0; i < nwords; i++) { |
FILTER_EMIT(RFCR_NS_RFADDR_FILTMEM + (i * 2), |
FILTER_EMIT(sc->sc_parm->p_filtmem + (i * 2), mchash[i]); |
mchash[i]); |
|
} |
} |
} |
} |
#undef FILTER_EMIT |
#undef FILTER_EMIT |
#undef MCHASH_NWORDS |
#undef MCHASH_NWORDS |
|
#undef MCHASH_NWORDS_83815 |
|
#undef MCHASH_NWORDS_83820 |
|
|
/* |
/* |
* Re-enable the receiver filter. |
* Re-enable the receiver filter. |
Line 3093 SIP_DECL(dp83815_set_filter)(struct sip_ |
|
Line 3291 SIP_DECL(dp83815_set_filter)(struct sip_ |
|
bus_space_write_4(st, sh, SIP_RFCR, sc->sc_rfcr); |
bus_space_write_4(st, sh, SIP_RFCR, sc->sc_rfcr); |
} |
} |
|
|
#if defined(DP83820) |
|
/* |
/* |
* sip_dp83820_mii_readreg: [mii interface function] |
* sip_dp83820_mii_readreg: [mii interface function] |
* |
* |
* Read a PHY register on the MII of the DP83820. |
* Read a PHY register on the MII of the DP83820. |
*/ |
*/ |
static int |
static int |
SIP_DECL(dp83820_mii_readreg)(struct device *self, int phy, int reg) |
sipcom_dp83820_mii_readreg(device_t self, int phy, int reg) |
{ |
{ |
struct sip_softc *sc = (void *) self; |
struct sip_softc *sc = device_private(self); |
|
|
if (sc->sc_cfg & CFG_TBI_EN) { |
if (sc->sc_cfg & CFG_TBI_EN) { |
bus_addr_t tbireg; |
bus_addr_t tbireg; |
Line 3155 SIP_DECL(dp83820_mii_readreg)(struct dev |
|
Line 3352 SIP_DECL(dp83820_mii_readreg)(struct dev |
|
return (rv); |
return (rv); |
} |
} |
|
|
return (mii_bitbang_readreg(self, &SIP_DECL(mii_bitbang_ops), |
return mii_bitbang_readreg(self, &sipcom_mii_bitbang_ops, phy, reg); |
phy, reg)); |
|
} |
} |
|
|
/* |
/* |
Line 3165 SIP_DECL(dp83820_mii_readreg)(struct dev |
|
Line 3361 SIP_DECL(dp83820_mii_readreg)(struct dev |
|
* Write a PHY register on the MII of the DP83820. |
* Write a PHY register on the MII of the DP83820. |
*/ |
*/ |
static void |
static void |
SIP_DECL(dp83820_mii_writereg)(struct device *self, int phy, int reg, int val) |
sipcom_dp83820_mii_writereg(device_t self, int phy, int reg, int val) |
{ |
{ |
struct sip_softc *sc = (void *) self; |
struct sip_softc *sc = device_private(self); |
|
|
if (sc->sc_cfg & CFG_TBI_EN) { |
if (sc->sc_cfg & CFG_TBI_EN) { |
bus_addr_t tbireg; |
bus_addr_t tbireg; |
Line 3187 SIP_DECL(dp83820_mii_writereg)(struct de |
|
Line 3383 SIP_DECL(dp83820_mii_writereg)(struct de |
|
return; |
return; |
} |
} |
|
|
mii_bitbang_writereg(self, &SIP_DECL(mii_bitbang_ops), |
mii_bitbang_writereg(self, &sipcom_mii_bitbang_ops, phy, reg, val); |
phy, reg, val); |
|
} |
} |
|
|
/* |
/* |
Line 3197 SIP_DECL(dp83820_mii_writereg)(struct de |
|
Line 3392 SIP_DECL(dp83820_mii_writereg)(struct de |
|
* Callback from MII layer when media changes. |
* Callback from MII layer when media changes. |
*/ |
*/ |
static void |
static void |
SIP_DECL(dp83820_mii_statchg)(struct device *self) |
sipcom_dp83820_mii_statchg(device_t self) |
{ |
{ |
struct sip_softc *sc = (struct sip_softc *) self; |
struct sip_softc *sc = device_private(self); |
struct mii_data *mii = &sc->sc_mii; |
struct mii_data *mii = &sc->sc_mii; |
u_int32_t cfg, pcr; |
u_int32_t cfg, pcr; |
|
|
Line 3249 SIP_DECL(dp83820_mii_statchg)(struct dev |
|
Line 3444 SIP_DECL(dp83820_mii_statchg)(struct dev |
|
} |
} |
|
|
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_CFG, cfg); |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_CFG, cfg); |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_TXCFG, sc->sc_txcfg); |
bus_space_write_4(sc->sc_st, sc->sc_sh, sc->sc_regs.r_txcfg, |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_RXCFG, sc->sc_rxcfg); |
sc->sc_txcfg); |
|
bus_space_write_4(sc->sc_st, sc->sc_sh, sc->sc_regs.r_rxcfg, |
|
sc->sc_rxcfg); |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_NS_PCR, pcr); |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_NS_PCR, pcr); |
} |
} |
#endif /* ! DP83820 */ |
|
|
|
/* |
/* |
* sip_mii_bitbang_read: [mii bit-bang interface function] |
* sip_mii_bitbang_read: [mii bit-bang interface function] |
Line 3261 SIP_DECL(dp83820_mii_statchg)(struct dev |
|
Line 3457 SIP_DECL(dp83820_mii_statchg)(struct dev |
|
* Read the MII serial port for the MII bit-bang module. |
* Read the MII serial port for the MII bit-bang module. |
*/ |
*/ |
static u_int32_t |
static u_int32_t |
SIP_DECL(mii_bitbang_read)(struct device *self) |
sipcom_mii_bitbang_read(device_t self) |
{ |
{ |
struct sip_softc *sc = (void *) self; |
struct sip_softc *sc = device_private(self); |
|
|
return (bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_EROMAR)); |
return (bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_EROMAR)); |
} |
} |
Line 3274 SIP_DECL(mii_bitbang_read)(struct device |
|
Line 3470 SIP_DECL(mii_bitbang_read)(struct device |
|
* Write the MII serial port for the MII bit-bang module. |
* Write the MII serial port for the MII bit-bang module. |
*/ |
*/ |
static void |
static void |
SIP_DECL(mii_bitbang_write)(struct device *self, u_int32_t val) |
sipcom_mii_bitbang_write(device_t self, u_int32_t val) |
{ |
{ |
struct sip_softc *sc = (void *) self; |
struct sip_softc *sc = device_private(self); |
|
|
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_EROMAR, val); |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_EROMAR, val); |
} |
} |
|
|
#ifndef DP83820 |
|
/* |
/* |
* sip_sis900_mii_readreg: [mii interface function] |
* sip_sis900_mii_readreg: [mii interface function] |
* |
* |
* Read a PHY register on the MII. |
* Read a PHY register on the MII. |
*/ |
*/ |
static int |
static int |
SIP_DECL(sis900_mii_readreg)(struct device *self, int phy, int reg) |
sipcom_sis900_mii_readreg(device_t self, int phy, int reg) |
{ |
{ |
struct sip_softc *sc = (struct sip_softc *) self; |
struct sip_softc *sc = device_private(self); |
u_int32_t enphy; |
u_int32_t enphy; |
|
|
/* |
/* |
Line 3298 SIP_DECL(sis900_mii_readreg)(struct devi |
|
Line 3493 SIP_DECL(sis900_mii_readreg)(struct devi |
|
* operations. |
* operations. |
*/ |
*/ |
if (sc->sc_model->sip_product == PCI_PRODUCT_SIS_900) |
if (sc->sc_model->sip_product == PCI_PRODUCT_SIS_900) |
return (mii_bitbang_readreg(self, &SIP_DECL(mii_bitbang_ops), |
return mii_bitbang_readreg(self, &sipcom_mii_bitbang_ops, |
phy, reg)); |
phy, reg); |
|
|
#ifndef SIS900_MII_RESTRICT |
#ifndef SIS900_MII_RESTRICT |
/* |
/* |
Line 3325 SIP_DECL(sis900_mii_readreg)(struct devi |
|
Line 3520 SIP_DECL(sis900_mii_readreg)(struct devi |
|
* Write a PHY register on the MII. |
* Write a PHY register on the MII. |
*/ |
*/ |
static void |
static void |
SIP_DECL(sis900_mii_writereg)(struct device *self, int phy, int reg, int val) |
sipcom_sis900_mii_writereg(device_t self, int phy, int reg, int val) |
{ |
{ |
struct sip_softc *sc = (struct sip_softc *) self; |
struct sip_softc *sc = device_private(self); |
u_int32_t enphy; |
u_int32_t enphy; |
|
|
if (sc->sc_model->sip_product == PCI_PRODUCT_SIS_900) { |
if (sc->sc_model->sip_product == PCI_PRODUCT_SIS_900) { |
mii_bitbang_writereg(self, &SIP_DECL(mii_bitbang_ops), |
mii_bitbang_writereg(self, &sipcom_mii_bitbang_ops, |
phy, reg, val); |
phy, reg, val); |
return; |
return; |
} |
} |
Line 3359 SIP_DECL(sis900_mii_writereg)(struct dev |
|
Line 3554 SIP_DECL(sis900_mii_writereg)(struct dev |
|
* Callback from MII layer when media changes. |
* Callback from MII layer when media changes. |
*/ |
*/ |
static void |
static void |
SIP_DECL(sis900_mii_statchg)(struct device *self) |
sipcom_sis900_mii_statchg(device_t self) |
{ |
{ |
struct sip_softc *sc = (struct sip_softc *) self; |
struct sip_softc *sc = device_private(self); |
struct mii_data *mii = &sc->sc_mii; |
struct mii_data *mii = &sc->sc_mii; |
u_int32_t flowctl; |
u_int32_t flowctl; |
|
|
Line 3402 SIP_DECL(sis900_mii_statchg)(struct devi |
|
Line 3597 SIP_DECL(sis900_mii_statchg)(struct devi |
|
flowctl = 0; |
flowctl = 0; |
} |
} |
|
|
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_TXCFG, sc->sc_txcfg); |
bus_space_write_4(sc->sc_st, sc->sc_sh, sc->sc_regs.r_txcfg, |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_RXCFG, sc->sc_rxcfg); |
sc->sc_txcfg); |
|
bus_space_write_4(sc->sc_st, sc->sc_sh, sc->sc_regs.r_rxcfg, |
|
sc->sc_rxcfg); |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_IMR, sc->sc_imr); |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_IMR, sc->sc_imr); |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_FLOWCTL, flowctl); |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_FLOWCTL, flowctl); |
} |
} |
Line 3414 SIP_DECL(sis900_mii_statchg)(struct devi |
|
Line 3611 SIP_DECL(sis900_mii_statchg)(struct devi |
|
* Read a PHY register on the MII. |
* Read a PHY register on the MII. |
*/ |
*/ |
static int |
static int |
SIP_DECL(dp83815_mii_readreg)(struct device *self, int phy, int reg) |
sipcom_dp83815_mii_readreg(device_t self, int phy, int reg) |
{ |
{ |
struct sip_softc *sc = (struct sip_softc *) self; |
struct sip_softc *sc = device_private(self); |
u_int32_t val; |
u_int32_t val; |
|
|
/* |
/* |
Line 3449 SIP_DECL(dp83815_mii_readreg)(struct dev |
|
Line 3646 SIP_DECL(dp83815_mii_readreg)(struct dev |
|
* Write a PHY register to the MII. |
* Write a PHY register to the MII. |
*/ |
*/ |
static void |
static void |
SIP_DECL(dp83815_mii_writereg)(struct device *self, int phy, int reg, int val) |
sipcom_dp83815_mii_writereg(device_t self, int phy, int reg, int val) |
{ |
{ |
struct sip_softc *sc = (struct sip_softc *) self; |
struct sip_softc *sc = device_private(self); |
|
|
/* |
/* |
* The DP83815 only has an internal PHY. Only allow |
* The DP83815 only has an internal PHY. Only allow |
Line 3469 SIP_DECL(dp83815_mii_writereg)(struct de |
|
Line 3666 SIP_DECL(dp83815_mii_writereg)(struct de |
|
* Callback from MII layer when media changes. |
* Callback from MII layer when media changes. |
*/ |
*/ |
static void |
static void |
SIP_DECL(dp83815_mii_statchg)(struct device *self) |
sipcom_dp83815_mii_statchg(device_t self) |
{ |
{ |
struct sip_softc *sc = (struct sip_softc *) self; |
struct sip_softc *sc = device_private(self); |
|
|
/* |
/* |
* Update TXCFG for full-duplex operation. |
* Update TXCFG for full-duplex operation. |
Line 3494 SIP_DECL(dp83815_mii_statchg)(struct dev |
|
Line 3691 SIP_DECL(dp83815_mii_statchg)(struct dev |
|
* XXX 802.3x flow control. |
* XXX 802.3x flow control. |
*/ |
*/ |
|
|
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_TXCFG, sc->sc_txcfg); |
bus_space_write_4(sc->sc_st, sc->sc_sh, sc->sc_regs.r_txcfg, |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_RXCFG, sc->sc_rxcfg); |
sc->sc_txcfg); |
|
bus_space_write_4(sc->sc_st, sc->sc_sh, sc->sc_regs.r_rxcfg, |
|
sc->sc_rxcfg); |
|
|
/* |
/* |
* Some DP83815s experience problems when used with short |
* Some DP83815s experience problems when used with short |
Line 3525 SIP_DECL(dp83815_mii_statchg)(struct dev |
|
Line 3724 SIP_DECL(dp83815_mii_statchg)(struct dev |
|
bus_space_write_4(sc->sc_st, sc->sc_sh, 0x00cc, 0); |
bus_space_write_4(sc->sc_st, sc->sc_sh, 0x00cc, 0); |
} |
} |
} |
} |
#endif /* DP83820 */ |
|
|
|
#if defined(DP83820) |
|
static void |
static void |
SIP_DECL(dp83820_read_macaddr)(struct sip_softc *sc, |
sipcom_dp83820_read_macaddr(struct sip_softc *sc, |
const struct pci_attach_args *pa, u_int8_t *enaddr) |
const struct pci_attach_args *pa, u_int8_t *enaddr) |
{ |
{ |
u_int16_t eeprom_data[SIP_DP83820_EEPROM_LENGTH / 2]; |
u_int16_t eeprom_data[SIP_DP83820_EEPROM_LENGTH / 2]; |
Line 3541 SIP_DECL(dp83820_read_macaddr)(struct si |
|
Line 3738 SIP_DECL(dp83820_read_macaddr)(struct si |
|
* the DP83820 manual, section 4.2.4. |
* the DP83820 manual, section 4.2.4. |
*/ |
*/ |
|
|
SIP_DECL(read_eeprom)(sc, 0, |
sipcom_read_eeprom(sc, 0, __arraycount(eeprom_data), eeprom_data); |
sizeof(eeprom_data) / sizeof(eeprom_data[0]), eeprom_data); |
|
|
|
match = eeprom_data[SIP_DP83820_EEPROM_CHECKSUM / 2] >> 8; |
match = eeprom_data[SIP_DP83820_EEPROM_CHECKSUM / 2] >> 8; |
match = ~(match - 1); |
match = ~(match - 1); |
Line 3563 SIP_DECL(dp83820_read_macaddr)(struct si |
|
Line 3759 SIP_DECL(dp83820_read_macaddr)(struct si |
|
enaddr[4] = eeprom_data[SIP_DP83820_EEPROM_PMATCH0 / 2] & 0xff; |
enaddr[4] = eeprom_data[SIP_DP83820_EEPROM_PMATCH0 / 2] & 0xff; |
enaddr[5] = eeprom_data[SIP_DP83820_EEPROM_PMATCH0 / 2] >> 8; |
enaddr[5] = eeprom_data[SIP_DP83820_EEPROM_PMATCH0 / 2] >> 8; |
} |
} |
#else /* ! DP83820 */ |
|
static void |
static void |
SIP_DECL(sis900_eeprom_delay)(struct sip_softc *sc) |
sipcom_sis900_eeprom_delay(struct sip_softc *sc) |
{ |
{ |
int i; |
int i; |
|
|
Line 3578 SIP_DECL(sis900_eeprom_delay)(struct sip |
|
Line 3774 SIP_DECL(sis900_eeprom_delay)(struct sip |
|
} |
} |
|
|
static void |
static void |
SIP_DECL(sis900_read_macaddr)(struct sip_softc *sc, |
sipcom_sis900_read_macaddr(struct sip_softc *sc, |
const struct pci_attach_args *pa, u_int8_t *enaddr) |
const struct pci_attach_args *pa, u_int8_t *enaddr) |
{ |
{ |
u_int16_t myea[ETHER_ADDR_LEN / 2]; |
u_int16_t myea[ETHER_ADDR_LEN / 2]; |
Line 3636 SIP_DECL(sis900_read_macaddr)(struct sip |
|
Line 3832 SIP_DECL(sis900_read_macaddr)(struct sip |
|
* XXX-cube This is ugly. I'll look for docs about it. |
* XXX-cube This is ugly. I'll look for docs about it. |
*/ |
*/ |
SIS_SET_EROMAR(sc, EROMAR_EECS); |
SIS_SET_EROMAR(sc, EROMAR_EECS); |
SIP_DECL(sis900_eeprom_delay)(sc); |
sipcom_sis900_eeprom_delay(sc); |
for (i = 0; i <= 25; i++) { /* Yes, 26 times. */ |
for (i = 0; i <= 25; i++) { /* Yes, 26 times. */ |
SIS_SET_EROMAR(sc, EROMAR_EESK); |
SIS_SET_EROMAR(sc, EROMAR_EESK); |
SIP_DECL(sis900_eeprom_delay)(sc); |
sipcom_sis900_eeprom_delay(sc); |
SIS_CLR_EROMAR(sc, EROMAR_EESK); |
SIS_CLR_EROMAR(sc, EROMAR_EESK); |
SIP_DECL(sis900_eeprom_delay)(sc); |
sipcom_sis900_eeprom_delay(sc); |
} |
} |
SIS_CLR_EROMAR(sc, EROMAR_EECS); |
SIS_CLR_EROMAR(sc, EROMAR_EECS); |
SIP_DECL(sis900_eeprom_delay)(sc); |
sipcom_sis900_eeprom_delay(sc); |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_EROMAR, 0); |
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_EROMAR, 0); |
|
|
if (bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_EROMAR) & EROMAR_GNT) { |
if (bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_EROMAR) & EROMAR_GNT) { |
SIP_DECL(read_eeprom)(sc, SIP_EEPROM_ETHERNET_ID0 >> 1, |
sipcom_read_eeprom(sc, SIP_EEPROM_ETHERNET_ID0 >> 1, |
sizeof(myea) / sizeof(myea[0]), myea); |
sizeof(myea) / sizeof(myea[0]), myea); |
break; |
break; |
} |
} |
Line 3666 SIP_DECL(sis900_read_macaddr)(struct sip |
|
Line 3862 SIP_DECL(sis900_read_macaddr)(struct sip |
|
} break; |
} break; |
|
|
default: |
default: |
SIP_DECL(read_eeprom)(sc, SIP_EEPROM_ETHERNET_ID0 >> 1, |
sipcom_read_eeprom(sc, SIP_EEPROM_ETHERNET_ID0 >> 1, |
sizeof(myea) / sizeof(myea[0]), myea); |
sizeof(myea) / sizeof(myea[0]), myea); |
} |
} |
|
|
Line 3683 static const u_int8_t bbr4[] = {0,8,4,12 |
|
Line 3879 static const u_int8_t bbr4[] = {0,8,4,12 |
|
#define bbr(v) ((bbr4[(v)&0xf] << 4) | bbr4[((v)>>4) & 0xf]) |
#define bbr(v) ((bbr4[(v)&0xf] << 4) | bbr4[((v)>>4) & 0xf]) |
|
|
static void |
static void |
SIP_DECL(dp83815_read_macaddr)(struct sip_softc *sc, |
sipcom_dp83815_read_macaddr(struct sip_softc *sc, |
const struct pci_attach_args *pa, u_int8_t *enaddr) |
const struct pci_attach_args *pa, u_int8_t *enaddr) |
{ |
{ |
u_int16_t eeprom_data[SIP_DP83815_EEPROM_LENGTH / 2], *ea; |
u_int16_t eeprom_data[SIP_DP83815_EEPROM_LENGTH / 2], *ea; |
u_int8_t cksum, *e, match; |
u_int8_t cksum, *e, match; |
int i; |
int i; |
|
|
SIP_DECL(read_eeprom)(sc, 0, sizeof(eeprom_data) / |
sipcom_read_eeprom(sc, 0, sizeof(eeprom_data) / |
sizeof(eeprom_data[0]), eeprom_data); |
sizeof(eeprom_data[0]), eeprom_data); |
|
|
match = eeprom_data[SIP_DP83815_EEPROM_CHECKSUM/2] >> 8; |
match = eeprom_data[SIP_DP83815_EEPROM_CHECKSUM/2] >> 8; |
Line 3735 SIP_DECL(dp83815_read_macaddr)(struct si |
|
Line 3931 SIP_DECL(dp83815_read_macaddr)(struct si |
|
for (i = 0; i < 6 ;i++) |
for (i = 0; i < 6 ;i++) |
enaddr[i] = bbr(enaddr[i]); |
enaddr[i] = bbr(enaddr[i]); |
} |
} |
#endif /* DP83820 */ |
|
|
|
/* |
/* |
* sip_mediastatus: [ifmedia interface function] |
* sip_mediastatus: [ifmedia interface function] |
Line 3743 SIP_DECL(dp83815_read_macaddr)(struct si |
|
Line 3938 SIP_DECL(dp83815_read_macaddr)(struct si |
|
* Get the current interface media status. |
* Get the current interface media status. |
*/ |
*/ |
static void |
static void |
SIP_DECL(mediastatus)(struct ifnet *ifp, struct ifmediareq *ifmr) |
sipcom_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) |
{ |
{ |
struct sip_softc *sc = ifp->if_softc; |
struct sip_softc *sc = ifp->if_softc; |
|
|
mii_pollstat(&sc->sc_mii); |
ether_mediastatus(ifp, ifmr); |
ifmr->ifm_status = sc->sc_mii.mii_media_status; |
ifmr->ifm_active = (ifmr->ifm_active & ~IFM_ETH_FMASK) | |
ifmr->ifm_active = (sc->sc_mii.mii_media_active & ~IFM_ETH_FMASK) | |
|
sc->sc_flowflags; |
sc->sc_flowflags; |
} |
} |
|
|
/* |
|
* sip_mediachange: [ifmedia interface function] |
|
* |
|
* Set hardware to newly-selected media. |
|
*/ |
|
static int |
|
SIP_DECL(mediachange)(struct ifnet *ifp) |
|
{ |
|
struct sip_softc *sc = ifp->if_softc; |
|
|
|
if (ifp->if_flags & IFF_UP) |
|
mii_mediachg(&sc->sc_mii); |
|
return (0); |
|
} |
|