Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/sk/if_sk.c
Show First 20 Lines • Show All 195 Lines • ▼ Show 20 Lines | |||||
static int sk_probe(device_t); | static int sk_probe(device_t); | ||||
static int sk_attach(device_t); | static int sk_attach(device_t); | ||||
static void sk_tick(void *); | static void sk_tick(void *); | ||||
static void sk_yukon_tick(void *); | static void sk_yukon_tick(void *); | ||||
static void sk_intr(void *); | static void sk_intr(void *); | ||||
static void sk_intr_xmac(struct sk_if_softc *); | static void sk_intr_xmac(struct sk_if_softc *); | ||||
static void sk_intr_bcom(struct sk_if_softc *); | static void sk_intr_bcom(struct sk_if_softc *); | ||||
static void sk_intr_yukon(struct sk_if_softc *); | static void sk_intr_yukon(struct sk_if_softc *); | ||||
static __inline void sk_rxcksum(struct ifnet *, struct mbuf *, u_int32_t); | static __inline void sk_rxcksum(if_t, struct mbuf *, u_int32_t); | ||||
static __inline int sk_rxvalid(struct sk_softc *, u_int32_t, u_int32_t); | static __inline int sk_rxvalid(struct sk_softc *, u_int32_t, u_int32_t); | ||||
static void sk_rxeof(struct sk_if_softc *); | static void sk_rxeof(struct sk_if_softc *); | ||||
static void sk_jumbo_rxeof(struct sk_if_softc *); | static void sk_jumbo_rxeof(struct sk_if_softc *); | ||||
static void sk_txeof(struct sk_if_softc *); | static void sk_txeof(struct sk_if_softc *); | ||||
static void sk_txcksum(struct ifnet *, struct mbuf *, struct sk_tx_desc *); | static void sk_txcksum(if_t, struct mbuf *, struct sk_tx_desc *); | ||||
static int sk_encap(struct sk_if_softc *, struct mbuf **); | static int sk_encap(struct sk_if_softc *, struct mbuf **); | ||||
static void sk_start(struct ifnet *); | static void sk_start(if_t); | ||||
static void sk_start_locked(struct ifnet *); | static void sk_start_locked(if_t); | ||||
static int sk_ioctl(struct ifnet *, u_long, caddr_t); | static int sk_ioctl(if_t, u_long, caddr_t); | ||||
static void sk_init(void *); | static void sk_init(void *); | ||||
static void sk_init_locked(struct sk_if_softc *); | static void sk_init_locked(struct sk_if_softc *); | ||||
static void sk_init_xmac(struct sk_if_softc *); | static void sk_init_xmac(struct sk_if_softc *); | ||||
static void sk_init_yukon(struct sk_if_softc *); | static void sk_init_yukon(struct sk_if_softc *); | ||||
static void sk_stop(struct sk_if_softc *); | static void sk_stop(struct sk_if_softc *); | ||||
static void sk_watchdog(void *); | static void sk_watchdog(void *); | ||||
static int sk_ifmedia_upd(struct ifnet *); | static int sk_ifmedia_upd(if_t); | ||||
static void sk_ifmedia_sts(struct ifnet *, struct ifmediareq *); | static void sk_ifmedia_sts(if_t, struct ifmediareq *); | ||||
static void sk_reset(struct sk_softc *); | static void sk_reset(struct sk_softc *); | ||||
static __inline void sk_discard_rxbuf(struct sk_if_softc *, int); | static __inline void sk_discard_rxbuf(struct sk_if_softc *, int); | ||||
static __inline void sk_discard_jumbo_rxbuf(struct sk_if_softc *, int); | static __inline void sk_discard_jumbo_rxbuf(struct sk_if_softc *, int); | ||||
static int sk_newbuf(struct sk_if_softc *, int); | static int sk_newbuf(struct sk_if_softc *, int); | ||||
static int sk_jumbo_newbuf(struct sk_if_softc *, int); | static int sk_jumbo_newbuf(struct sk_if_softc *, int); | ||||
static void sk_dmamap_cb(void *, bus_dma_segment_t *, int, int); | static void sk_dmamap_cb(void *, bus_dma_segment_t *, int, int); | ||||
static int sk_dma_alloc(struct sk_if_softc *); | static int sk_dma_alloc(struct sk_if_softc *); | ||||
static int sk_dma_jumbo_alloc(struct sk_if_softc *); | static int sk_dma_jumbo_alloc(struct sk_if_softc *); | ||||
▲ Show 20 Lines • Show All 511 Lines • ▼ Show 20 Lines | sk_add_maddr_genesis(void *arg, struct sockaddr_dl *sdl, u_int cnt) | ||||
ctx->mode |= XM_MODE_RX_USE_HASH; | ctx->mode |= XM_MODE_RX_USE_HASH; | ||||
return (1); | return (1); | ||||
} | } | ||||
static void | static void | ||||
sk_rxfilter_genesis(struct sk_if_softc *sc_if) | sk_rxfilter_genesis(struct sk_if_softc *sc_if) | ||||
{ | { | ||||
struct ifnet *ifp = sc_if->sk_ifp; | if_t ifp = sc_if->sk_ifp; | ||||
struct sk_add_maddr_genesis_ctx ctx = { sc_if, { 0, 0 } }; | struct sk_add_maddr_genesis_ctx ctx = { sc_if, { 0, 0 } }; | ||||
int i; | int i; | ||||
u_int16_t dummy[] = { 0, 0, 0 }; | u_int16_t dummy[] = { 0, 0, 0 }; | ||||
SK_IF_LOCK_ASSERT(sc_if); | SK_IF_LOCK_ASSERT(sc_if); | ||||
ctx.mode = SK_XM_READ_4(sc_if, XM_MODE); | ctx.mode = SK_XM_READ_4(sc_if, XM_MODE); | ||||
ctx.mode &= ~(XM_MODE_RX_PROMISC | XM_MODE_RX_USE_HASH | | ctx.mode &= ~(XM_MODE_RX_PROMISC | XM_MODE_RX_USE_HASH | | ||||
XM_MODE_RX_USE_PERFECT); | XM_MODE_RX_USE_PERFECT); | ||||
/* First, zot all the existing perfect filters. */ | /* First, zot all the existing perfect filters. */ | ||||
for (i = 1; i < XM_RXFILT_MAX; i++) | for (i = 1; i < XM_RXFILT_MAX; i++) | ||||
sk_setfilt(sc_if, dummy, i); | sk_setfilt(sc_if, dummy, i); | ||||
/* Now program new ones. */ | /* Now program new ones. */ | ||||
if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { | if (if_getflags(ifp) & IFF_ALLMULTI || if_getflags(ifp) & IFF_PROMISC) { | ||||
if (ifp->if_flags & IFF_ALLMULTI) | if (if_getflags(ifp) & IFF_ALLMULTI) | ||||
ctx.mode |= XM_MODE_RX_USE_HASH; | ctx.mode |= XM_MODE_RX_USE_HASH; | ||||
if (ifp->if_flags & IFF_PROMISC) | if (if_getflags(ifp) & IFF_PROMISC) | ||||
ctx.mode |= XM_MODE_RX_PROMISC; | ctx.mode |= XM_MODE_RX_PROMISC; | ||||
ctx.hashes[0] = 0xFFFFFFFF; | ctx.hashes[0] = 0xFFFFFFFF; | ||||
ctx.hashes[1] = 0xFFFFFFFF; | ctx.hashes[1] = 0xFFFFFFFF; | ||||
} else | } else | ||||
/* XXX want to maintain reverse semantics */ | /* XXX want to maintain reverse semantics */ | ||||
if_foreach_llmaddr(ifp, sk_add_maddr_genesis, &ctx); | if_foreach_llmaddr(ifp, sk_add_maddr_genesis, &ctx); | ||||
SK_XM_WRITE_4(sc_if, XM_MODE, ctx.mode); | SK_XM_WRITE_4(sc_if, XM_MODE, ctx.mode); | ||||
Show All 13 Lines | sk_hash_maddr_yukon(void *arg, struct sockaddr_dl *sdl, u_int cnt) | ||||
hashes[crc >> 5] |= 1 << (crc & 0x1f); | hashes[crc >> 5] |= 1 << (crc & 0x1f); | ||||
return (1); | return (1); | ||||
} | } | ||||
static void | static void | ||||
sk_rxfilter_yukon(struct sk_if_softc *sc_if) | sk_rxfilter_yukon(struct sk_if_softc *sc_if) | ||||
{ | { | ||||
struct ifnet *ifp; | if_t ifp; | ||||
uint32_t hashes[2] = { 0, 0 }, mode; | uint32_t hashes[2] = { 0, 0 }, mode; | ||||
SK_IF_LOCK_ASSERT(sc_if); | SK_IF_LOCK_ASSERT(sc_if); | ||||
ifp = sc_if->sk_ifp; | ifp = sc_if->sk_ifp; | ||||
mode = SK_YU_READ_2(sc_if, YUKON_RCR); | mode = SK_YU_READ_2(sc_if, YUKON_RCR); | ||||
if (ifp->if_flags & IFF_PROMISC) | if (if_getflags(ifp) & IFF_PROMISC) | ||||
mode &= ~(YU_RCR_UFLEN | YU_RCR_MUFLEN); | mode &= ~(YU_RCR_UFLEN | YU_RCR_MUFLEN); | ||||
else if (ifp->if_flags & IFF_ALLMULTI) { | else if (if_getflags(ifp) & IFF_ALLMULTI) { | ||||
mode |= YU_RCR_UFLEN | YU_RCR_MUFLEN; | mode |= YU_RCR_UFLEN | YU_RCR_MUFLEN; | ||||
hashes[0] = 0xFFFFFFFF; | hashes[0] = 0xFFFFFFFF; | ||||
hashes[1] = 0xFFFFFFFF; | hashes[1] = 0xFFFFFFFF; | ||||
} else { | } else { | ||||
mode |= YU_RCR_UFLEN; | mode |= YU_RCR_UFLEN; | ||||
if_foreach_llmaddr(ifp, sk_hash_maddr_yukon, hashes); | if_foreach_llmaddr(ifp, sk_hash_maddr_yukon, hashes); | ||||
if (hashes[0] != 0 || hashes[1] != 0) | if (hashes[0] != 0 || hashes[1] != 0) | ||||
mode |= YU_RCR_MUFLEN; | mode |= YU_RCR_MUFLEN; | ||||
▲ Show 20 Lines • Show All 232 Lines • ▼ Show 20 Lines | sk_jumbo_newbuf(sc_if, idx) | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Set media options. | * Set media options. | ||||
*/ | */ | ||||
static int | static int | ||||
sk_ifmedia_upd(ifp) | sk_ifmedia_upd(ifp) | ||||
struct ifnet *ifp; | if_t ifp; | ||||
{ | { | ||||
struct sk_if_softc *sc_if = ifp->if_softc; | struct sk_if_softc *sc_if = if_getsoftc(ifp); | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
mii = device_get_softc(sc_if->sk_miibus); | mii = device_get_softc(sc_if->sk_miibus); | ||||
sk_init(sc_if); | sk_init(sc_if); | ||||
mii_mediachg(mii); | mii_mediachg(mii); | ||||
return(0); | return(0); | ||||
} | } | ||||
/* | /* | ||||
* Report current media status. | * Report current media status. | ||||
*/ | */ | ||||
static void | static void | ||||
sk_ifmedia_sts(ifp, ifmr) | sk_ifmedia_sts(ifp, ifmr) | ||||
struct ifnet *ifp; | if_t ifp; | ||||
struct ifmediareq *ifmr; | struct ifmediareq *ifmr; | ||||
{ | { | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
sc_if = ifp->if_softc; | sc_if = if_getsoftc(ifp); | ||||
mii = device_get_softc(sc_if->sk_miibus); | mii = device_get_softc(sc_if->sk_miibus); | ||||
mii_pollstat(mii); | mii_pollstat(mii); | ||||
ifmr->ifm_active = mii->mii_media_active; | ifmr->ifm_active = mii->mii_media_active; | ||||
ifmr->ifm_status = mii->mii_media_status; | ifmr->ifm_status = mii->mii_media_status; | ||||
return; | return; | ||||
} | } | ||||
static int | static int | ||||
sk_ioctl(ifp, command, data) | sk_ioctl(ifp, command, data) | ||||
struct ifnet *ifp; | if_t ifp; | ||||
u_long command; | u_long command; | ||||
caddr_t data; | caddr_t data; | ||||
{ | { | ||||
struct sk_if_softc *sc_if = ifp->if_softc; | struct sk_if_softc *sc_if = if_getsoftc(ifp); | ||||
struct ifreq *ifr = (struct ifreq *) data; | struct ifreq *ifr = (struct ifreq *) data; | ||||
int error, mask; | int error, mask; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
error = 0; | error = 0; | ||||
switch(command) { | switch(command) { | ||||
case SIOCSIFMTU: | case SIOCSIFMTU: | ||||
if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > SK_JUMBO_MTU) | if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > SK_JUMBO_MTU) | ||||
error = EINVAL; | error = EINVAL; | ||||
else if (ifp->if_mtu != ifr->ifr_mtu) { | else if (if_getmtu(ifp) != ifr->ifr_mtu) { | ||||
if (sc_if->sk_jumbo_disable != 0 && | if (sc_if->sk_jumbo_disable != 0 && | ||||
ifr->ifr_mtu > SK_MAX_FRAMELEN) | ifr->ifr_mtu > SK_MAX_FRAMELEN) | ||||
error = EINVAL; | error = EINVAL; | ||||
else { | else { | ||||
SK_IF_LOCK(sc_if); | SK_IF_LOCK(sc_if); | ||||
ifp->if_mtu = ifr->ifr_mtu; | if_setmtu(ifp, ifr->ifr_mtu); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { | ||||
ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); | ||||
sk_init_locked(sc_if); | sk_init_locked(sc_if); | ||||
} | } | ||||
SK_IF_UNLOCK(sc_if); | SK_IF_UNLOCK(sc_if); | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case SIOCSIFFLAGS: | case SIOCSIFFLAGS: | ||||
SK_IF_LOCK(sc_if); | SK_IF_LOCK(sc_if); | ||||
if (ifp->if_flags & IFF_UP) { | if (if_getflags(ifp) & IFF_UP) { | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { | ||||
if ((ifp->if_flags ^ sc_if->sk_if_flags) | if ((if_getflags(ifp) ^ sc_if->sk_if_flags) | ||||
& (IFF_PROMISC | IFF_ALLMULTI)) | & (IFF_PROMISC | IFF_ALLMULTI)) | ||||
sk_rxfilter(sc_if); | sk_rxfilter(sc_if); | ||||
} else | } else | ||||
sk_init_locked(sc_if); | sk_init_locked(sc_if); | ||||
} else { | } else { | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) | ||||
sk_stop(sc_if); | sk_stop(sc_if); | ||||
} | } | ||||
sc_if->sk_if_flags = ifp->if_flags; | sc_if->sk_if_flags = if_getflags(ifp); | ||||
SK_IF_UNLOCK(sc_if); | SK_IF_UNLOCK(sc_if); | ||||
break; | break; | ||||
case SIOCADDMULTI: | case SIOCADDMULTI: | ||||
case SIOCDELMULTI: | case SIOCDELMULTI: | ||||
SK_IF_LOCK(sc_if); | SK_IF_LOCK(sc_if); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) | ||||
sk_rxfilter(sc_if); | sk_rxfilter(sc_if); | ||||
SK_IF_UNLOCK(sc_if); | SK_IF_UNLOCK(sc_if); | ||||
break; | break; | ||||
case SIOCGIFMEDIA: | case SIOCGIFMEDIA: | ||||
case SIOCSIFMEDIA: | case SIOCSIFMEDIA: | ||||
mii = device_get_softc(sc_if->sk_miibus); | mii = device_get_softc(sc_if->sk_miibus); | ||||
error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); | error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); | ||||
break; | break; | ||||
case SIOCSIFCAP: | case SIOCSIFCAP: | ||||
SK_IF_LOCK(sc_if); | SK_IF_LOCK(sc_if); | ||||
if (sc_if->sk_softc->sk_type == SK_GENESIS) { | if (sc_if->sk_softc->sk_type == SK_GENESIS) { | ||||
SK_IF_UNLOCK(sc_if); | SK_IF_UNLOCK(sc_if); | ||||
break; | break; | ||||
} | } | ||||
mask = ifr->ifr_reqcap ^ ifp->if_capenable; | mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); | ||||
if ((mask & IFCAP_TXCSUM) != 0 && | if ((mask & IFCAP_TXCSUM) != 0 && | ||||
(IFCAP_TXCSUM & ifp->if_capabilities) != 0) { | (IFCAP_TXCSUM & if_getcapabilities(ifp)) != 0) { | ||||
ifp->if_capenable ^= IFCAP_TXCSUM; | if_togglecapenable(ifp, IFCAP_TXCSUM); | ||||
if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) | if ((if_getcapenable(ifp) & IFCAP_TXCSUM) != 0) | ||||
ifp->if_hwassist |= SK_CSUM_FEATURES; | if_sethwassistbits(ifp, SK_CSUM_FEATURES, 0); | ||||
else | else | ||||
ifp->if_hwassist &= ~SK_CSUM_FEATURES; | if_sethwassistbits(ifp, 0, SK_CSUM_FEATURES); | ||||
} | } | ||||
if ((mask & IFCAP_RXCSUM) != 0 && | if ((mask & IFCAP_RXCSUM) != 0 && | ||||
(IFCAP_RXCSUM & ifp->if_capabilities) != 0) | (IFCAP_RXCSUM & if_getcapabilities(ifp)) != 0) | ||||
ifp->if_capenable ^= IFCAP_RXCSUM; | if_togglecapenable(ifp, IFCAP_RXCSUM); | ||||
SK_IF_UNLOCK(sc_if); | SK_IF_UNLOCK(sc_if); | ||||
break; | break; | ||||
default: | default: | ||||
error = ether_ioctl(ifp, command, data); | error = ether_ioctl(ifp, command, data); | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | |||||
* Single port cards will have only one logical interface of course. | * Single port cards will have only one logical interface of course. | ||||
*/ | */ | ||||
static int | static int | ||||
sk_attach(dev) | sk_attach(dev) | ||||
device_t dev; | device_t dev; | ||||
{ | { | ||||
struct sk_softc *sc; | struct sk_softc *sc; | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
u_int32_t r; | u_int32_t r; | ||||
int error, i, phy, port; | int error, i, phy, port; | ||||
u_char eaddr[6]; | u_char eaddr[6]; | ||||
u_char inv_mac[] = {0, 0, 0, 0, 0, 0}; | u_char inv_mac[] = {0, 0, 0, 0, 0, 0}; | ||||
if (dev == NULL) | if (dev == NULL) | ||||
return(EINVAL); | return(EINVAL); | ||||
Show All 21 Lines | sk_attach(dev) | ||||
sk_dma_jumbo_alloc(sc_if); | sk_dma_jumbo_alloc(sc_if); | ||||
ifp = sc_if->sk_ifp = if_alloc(IFT_ETHER); | ifp = sc_if->sk_ifp = if_alloc(IFT_ETHER); | ||||
if (ifp == NULL) { | if (ifp == NULL) { | ||||
device_printf(sc_if->sk_if_dev, "can not if_alloc()\n"); | device_printf(sc_if->sk_if_dev, "can not if_alloc()\n"); | ||||
error = ENOSPC; | error = ENOSPC; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
ifp->if_softc = sc_if; | if_setsoftc(ifp, sc_if); | ||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | ||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); | ||||
/* | /* | ||||
* SK_GENESIS has a bug in checksum offload - From linux. | * SK_GENESIS has a bug in checksum offload - From linux. | ||||
*/ | */ | ||||
if (sc_if->sk_softc->sk_type != SK_GENESIS) { | if (sc_if->sk_softc->sk_type != SK_GENESIS) { | ||||
ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_RXCSUM; | if_setcapabilities(ifp, IFCAP_TXCSUM | IFCAP_RXCSUM); | ||||
ifp->if_hwassist = 0; | if_sethwassist(ifp, 0); | ||||
} else { | } else { | ||||
ifp->if_capabilities = 0; | if_setcapabilities(ifp, 0); | ||||
ifp->if_hwassist = 0; | if_sethwassist(ifp, 0); | ||||
} | } | ||||
ifp->if_capenable = ifp->if_capabilities; | if_setcapenable(ifp, if_getcapabilities(ifp)); | ||||
/* | /* | ||||
* Some revision of Yukon controller generates corrupted | * Some revision of Yukon controller generates corrupted | ||||
* frame when TX checksum offloading is enabled. The | * frame when TX checksum offloading is enabled. The | ||||
* frame has a valid checksum value so payload might be | * frame has a valid checksum value so payload might be | ||||
* modified during TX checksum calculation. Disable TX | * modified during TX checksum calculation. Disable TX | ||||
* checksum offloading but give users chance to enable it | * checksum offloading but give users chance to enable it | ||||
* when they know their controller works without problems | * when they know their controller works without problems | ||||
* with TX checksum offloading. | * with TX checksum offloading. | ||||
*/ | */ | ||||
ifp->if_capenable &= ~IFCAP_TXCSUM; | if_setcapenablebit(ifp, 0, IFCAP_TXCSUM); | ||||
ifp->if_ioctl = sk_ioctl; | if_setioctlfn(ifp, sk_ioctl); | ||||
ifp->if_start = sk_start; | if_setstartfn(ifp, sk_start); | ||||
ifp->if_init = sk_init; | if_setinitfn(ifp, sk_init); | ||||
IFQ_SET_MAXLEN(&ifp->if_snd, SK_TX_RING_CNT - 1); | if_setsendqlen(ifp, SK_TX_RING_CNT - 1); | ||||
ifp->if_snd.ifq_drv_maxlen = SK_TX_RING_CNT - 1; | if_setsendqready(ifp); | ||||
IFQ_SET_READY(&ifp->if_snd); | |||||
/* | /* | ||||
* Get station address for this interface. Note that | * Get station address for this interface. Note that | ||||
* dual port cards actually come with three station | * dual port cards actually come with three station | ||||
* addresses: one for each port, plus an extra. The | * addresses: one for each port, plus an extra. The | ||||
* extra one is used by the SysKonnect driver software | * extra one is used by the SysKonnect driver software | ||||
* as a 'virtual' station address for when both ports | * as a 'virtual' station address for when both ports | ||||
* are operating in failover mode. Currently we don't | * are operating in failover mode. Currently we don't | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | sk_attach(dev) | ||||
SK_IF_LOCK(sc_if); | SK_IF_LOCK(sc_if); | ||||
/* | /* | ||||
* The hardware should be ready for VLAN_MTU by default: | * The hardware should be ready for VLAN_MTU by default: | ||||
* XMAC II has 0x8100 in VLAN Tag Level 1 register initially; | * XMAC II has 0x8100 in VLAN Tag Level 1 register initially; | ||||
* YU_SMR_MFL_VLAN is set by this driver in Yukon. | * YU_SMR_MFL_VLAN is set by this driver in Yukon. | ||||
* | * | ||||
*/ | */ | ||||
ifp->if_capabilities |= IFCAP_VLAN_MTU; | if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0); | ||||
ifp->if_capenable |= IFCAP_VLAN_MTU; | if_setcapenablebit(ifp, IFCAP_VLAN_MTU, 0); | ||||
/* | /* | ||||
* Tell the upper layer(s) we support long frames. | * Tell the upper layer(s) we support long frames. | ||||
* Must appear after the call to ether_ifattach() because | * Must appear after the call to ether_ifattach() because | ||||
* ether_ifattach() sets ifi_hdrlen to the default value. | * ether_ifattach() sets ifi_hdrlen to the default value. | ||||
*/ | */ | ||||
ifp->if_hdrlen = sizeof(struct ether_vlan_header); | if_setifheaderlen(ifp, sizeof(struct ether_vlan_header)); | ||||
/* | /* | ||||
* Do miibus setup. | * Do miibus setup. | ||||
*/ | */ | ||||
phy = MII_PHY_ANY; | phy = MII_PHY_ANY; | ||||
switch (sc->sk_type) { | switch (sc->sk_type) { | ||||
case SK_GENESIS: | case SK_GENESIS: | ||||
sk_init_xmac(sc_if); | sk_init_xmac(sc_if); | ||||
▲ Show 20 Lines • Show All 307 Lines • ▼ Show 20 Lines | |||||
* to be careful about only freeing resources that have actually been | * to be careful about only freeing resources that have actually been | ||||
* allocated. | * allocated. | ||||
*/ | */ | ||||
static int | static int | ||||
sk_detach(dev) | sk_detach(dev) | ||||
device_t dev; | device_t dev; | ||||
{ | { | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
sc_if = device_get_softc(dev); | sc_if = device_get_softc(dev); | ||||
KASSERT(mtx_initialized(&sc_if->sk_softc->sk_mtx), | KASSERT(mtx_initialized(&sc_if->sk_softc->sk_mtx), | ||||
("sk mutex not initialized in sk_detach")); | ("sk mutex not initialized in sk_detach")); | ||||
SK_IF_LOCK(sc_if); | SK_IF_LOCK(sc_if); | ||||
ifp = sc_if->sk_ifp; | ifp = sc_if->sk_ifp; | ||||
/* These should only be active if attach_xmac succeeded */ | /* These should only be active if attach_xmac succeeded */ | ||||
▲ Show 20 Lines • Show All 496 Lines • ▼ Show 20 Lines | if (sc_if->sk_cdata.sk_jumbo_rx_tag) { | ||||
} | } | ||||
bus_dma_tag_destroy(sc_if->sk_cdata.sk_jumbo_rx_tag); | bus_dma_tag_destroy(sc_if->sk_cdata.sk_jumbo_rx_tag); | ||||
sc_if->sk_cdata.sk_jumbo_rx_tag = NULL; | sc_if->sk_cdata.sk_jumbo_rx_tag = NULL; | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
sk_txcksum(ifp, m, f) | sk_txcksum(ifp, m, f) | ||||
struct ifnet *ifp; | if_t ifp; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
struct sk_tx_desc *f; | struct sk_tx_desc *f; | ||||
{ | { | ||||
struct ip *ip; | struct ip *ip; | ||||
u_int16_t offset; | u_int16_t offset; | ||||
u_int8_t *p; | u_int8_t *p; | ||||
offset = sizeof(struct ip) + ETHER_HDR_LEN; | offset = sizeof(struct ip) + ETHER_HDR_LEN; | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | if (nseg == 0) { | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
if (sc_if->sk_cdata.sk_tx_cnt + nseg >= SK_TX_RING_CNT) { | if (sc_if->sk_cdata.sk_tx_cnt + nseg >= SK_TX_RING_CNT) { | ||||
bus_dmamap_unload(sc_if->sk_cdata.sk_tx_tag, txd->tx_dmamap); | bus_dmamap_unload(sc_if->sk_cdata.sk_tx_tag, txd->tx_dmamap); | ||||
return (ENOBUFS); | return (ENOBUFS); | ||||
} | } | ||||
m = *m_head; | m = *m_head; | ||||
if ((m->m_pkthdr.csum_flags & sc_if->sk_ifp->if_hwassist) != 0) | if ((m->m_pkthdr.csum_flags & if_gethwassist(sc_if->sk_ifp)) != 0) | ||||
cflags = SK_OPCODE_CSUM; | cflags = SK_OPCODE_CSUM; | ||||
else | else | ||||
cflags = SK_OPCODE_DEFAULT; | cflags = SK_OPCODE_DEFAULT; | ||||
si = frag = sc_if->sk_cdata.sk_tx_prod; | si = frag = sc_if->sk_cdata.sk_tx_prod; | ||||
for (i = 0; i < nseg; i++) { | for (i = 0; i < nseg; i++) { | ||||
f = &sc_if->sk_rdata.sk_tx_ring[frag]; | f = &sc_if->sk_rdata.sk_tx_ring[frag]; | ||||
f->sk_data_lo = htole32(SK_ADDR_LO(txsegs[i].ds_addr)); | f->sk_data_lo = htole32(SK_ADDR_LO(txsegs[i].ds_addr)); | ||||
f->sk_data_hi = htole32(SK_ADDR_HI(txsegs[i].ds_addr)); | f->sk_data_hi = htole32(SK_ADDR_HI(txsegs[i].ds_addr)); | ||||
Show All 30 Lines | bus_dmamap_sync(sc_if->sk_cdata.sk_tx_ring_tag, | ||||
sc_if->sk_cdata.sk_tx_ring_map, | sc_if->sk_cdata.sk_tx_ring_map, | ||||
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
sk_start(ifp) | sk_start(ifp) | ||||
struct ifnet *ifp; | if_t ifp; | ||||
{ | { | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
sc_if = ifp->if_softc; | sc_if = if_getsoftc(ifp); | ||||
SK_IF_LOCK(sc_if); | SK_IF_LOCK(sc_if); | ||||
sk_start_locked(ifp); | sk_start_locked(ifp); | ||||
SK_IF_UNLOCK(sc_if); | SK_IF_UNLOCK(sc_if); | ||||
return; | return; | ||||
} | } | ||||
static void | static void | ||||
sk_start_locked(ifp) | sk_start_locked(ifp) | ||||
struct ifnet *ifp; | if_t ifp; | ||||
{ | { | ||||
struct sk_softc *sc; | struct sk_softc *sc; | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
struct mbuf *m_head; | struct mbuf *m_head; | ||||
int enq; | int enq; | ||||
sc_if = ifp->if_softc; | sc_if = if_getsoftc(ifp); | ||||
sc = sc_if->sk_softc; | sc = sc_if->sk_softc; | ||||
SK_IF_LOCK_ASSERT(sc_if); | SK_IF_LOCK_ASSERT(sc_if); | ||||
for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && | for (enq = 0; !if_sendq_empty(ifp) && | ||||
sc_if->sk_cdata.sk_tx_cnt < SK_TX_RING_CNT - 1; ) { | sc_if->sk_cdata.sk_tx_cnt < SK_TX_RING_CNT - 1; ) { | ||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); | m_head = if_dequeue(ifp); | ||||
if (m_head == NULL) | if (m_head == NULL) | ||||
break; | break; | ||||
/* | /* | ||||
* Pack the data into the transmit ring. If we | * Pack the data into the transmit ring. If we | ||||
* don't have room, set the OACTIVE flag and wait | * don't have room, set the OACTIVE flag and wait | ||||
* for the NIC to drain the ring. | * for the NIC to drain the ring. | ||||
*/ | */ | ||||
if (sk_encap(sc_if, &m_head)) { | if (sk_encap(sc_if, &m_head)) { | ||||
if (m_head == NULL) | if (m_head == NULL) | ||||
break; | break; | ||||
IFQ_DRV_PREPEND(&ifp->if_snd, m_head); | if_sendq_prepend(ifp, m_head); | ||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); | ||||
break; | break; | ||||
} | } | ||||
enq++; | enq++; | ||||
/* | /* | ||||
* If there's a BPF listener, bounce a copy of this frame | * If there's a BPF listener, bounce a copy of this frame | ||||
* to him. | * to him. | ||||
*/ | */ | ||||
Show All 9 Lines | sk_start_locked(ifp) | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
sk_watchdog(arg) | sk_watchdog(arg) | ||||
void *arg; | void *arg; | ||||
{ | { | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
ifp = arg; | ifp = arg; | ||||
sc_if = ifp->if_softc; | sc_if = if_getsoftc(ifp); | ||||
SK_IF_LOCK_ASSERT(sc_if); | SK_IF_LOCK_ASSERT(sc_if); | ||||
if (sc_if->sk_watchdog_timer == 0 || --sc_if->sk_watchdog_timer) | if (sc_if->sk_watchdog_timer == 0 || --sc_if->sk_watchdog_timer) | ||||
goto done; | goto done; | ||||
/* | /* | ||||
* Reclaim first as there is a possibility of losing Tx completion | * Reclaim first as there is a possibility of losing Tx completion | ||||
* interrupts. | * interrupts. | ||||
*/ | */ | ||||
sk_txeof(sc_if); | sk_txeof(sc_if); | ||||
if (sc_if->sk_cdata.sk_tx_cnt != 0) { | if (sc_if->sk_cdata.sk_tx_cnt != 0) { | ||||
if_printf(sc_if->sk_ifp, "watchdog timeout\n"); | if_printf(sc_if->sk_ifp, "watchdog timeout\n"); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | ||||
ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); | ||||
sk_init_locked(sc_if); | sk_init_locked(sc_if); | ||||
} | } | ||||
done: | done: | ||||
callout_reset(&sc_if->sk_watchdog_ch, hz, sk_watchdog, ifp); | callout_reset(&sc_if->sk_watchdog_ch, hz, sk_watchdog, ifp); | ||||
return; | return; | ||||
} | } | ||||
Show All 21 Lines | |||||
} | } | ||||
static int | static int | ||||
skc_suspend(dev) | skc_suspend(dev) | ||||
device_t dev; | device_t dev; | ||||
{ | { | ||||
struct sk_softc *sc; | struct sk_softc *sc; | ||||
struct sk_if_softc *sc_if0, *sc_if1; | struct sk_if_softc *sc_if0, *sc_if1; | ||||
struct ifnet *ifp0 = NULL, *ifp1 = NULL; | if_t ifp0 = NULL, ifp1 = NULL; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
SK_LOCK(sc); | SK_LOCK(sc); | ||||
sc_if0 = sc->sk_if[SK_PORT_A]; | sc_if0 = sc->sk_if[SK_PORT_A]; | ||||
sc_if1 = sc->sk_if[SK_PORT_B]; | sc_if1 = sc->sk_if[SK_PORT_B]; | ||||
if (sc_if0 != NULL) | if (sc_if0 != NULL) | ||||
Show All 12 Lines | |||||
} | } | ||||
static int | static int | ||||
skc_resume(dev) | skc_resume(dev) | ||||
device_t dev; | device_t dev; | ||||
{ | { | ||||
struct sk_softc *sc; | struct sk_softc *sc; | ||||
struct sk_if_softc *sc_if0, *sc_if1; | struct sk_if_softc *sc_if0, *sc_if1; | ||||
struct ifnet *ifp0 = NULL, *ifp1 = NULL; | if_t ifp0 = NULL, ifp1 = NULL; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
SK_LOCK(sc); | SK_LOCK(sc); | ||||
sc_if0 = sc->sk_if[SK_PORT_A]; | sc_if0 = sc->sk_if[SK_PORT_A]; | ||||
sc_if1 = sc->sk_if[SK_PORT_B]; | sc_if1 = sc->sk_if[SK_PORT_B]; | ||||
if (sc_if0 != NULL) | if (sc_if0 != NULL) | ||||
ifp0 = sc_if0->sk_ifp; | ifp0 = sc_if0->sk_ifp; | ||||
if (sc_if1 != NULL) | if (sc_if1 != NULL) | ||||
ifp1 = sc_if1->sk_ifp; | ifp1 = sc_if1->sk_ifp; | ||||
if (ifp0 != NULL && ifp0->if_flags & IFF_UP) | if (ifp0 != NULL && if_getflags(ifp0) & IFF_UP) | ||||
sk_init_locked(sc_if0); | sk_init_locked(sc_if0); | ||||
if (ifp1 != NULL && ifp1->if_flags & IFF_UP) | if (ifp1 != NULL && if_getflags(ifp1) & IFF_UP) | ||||
sk_init_locked(sc_if1); | sk_init_locked(sc_if1); | ||||
sc->sk_suspended = 0; | sc->sk_suspended = 0; | ||||
SK_UNLOCK(sc); | SK_UNLOCK(sc); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* According to the data sheet from SK-NET GENESIS the hardware can compute | * According to the data sheet from SK-NET GENESIS the hardware can compute | ||||
* two Rx checksums at the same time(Each checksum start position is | * two Rx checksums at the same time(Each checksum start position is | ||||
* programmed in Rx descriptors). However it seems that TCP/UDP checksum | * programmed in Rx descriptors). However it seems that TCP/UDP checksum | ||||
* does not work at least on my Yukon hardware. I tried every possible ways | * does not work at least on my Yukon hardware. I tried every possible ways | ||||
* to get correct checksum value but couldn't get correct one. So TCP/UDP | * to get correct checksum value but couldn't get correct one. So TCP/UDP | ||||
* checksum offload was disabled at the moment and only IP checksum offload | * checksum offload was disabled at the moment and only IP checksum offload | ||||
* was enabled. | * was enabled. | ||||
* As nomral IP header size is 20 bytes I can't expect it would give an | * As nomral IP header size is 20 bytes I can't expect it would give an | ||||
* increase in throughput. However it seems it doesn't hurt performance in | * increase in throughput. However it seems it doesn't hurt performance in | ||||
* my testing. If there is a more detailed information for checksum secret | * my testing. If there is a more detailed information for checksum secret | ||||
* of the hardware in question please contact yongari@FreeBSD.org to add | * of the hardware in question please contact yongari@FreeBSD.org to add | ||||
* TCP/UDP checksum offload support. | * TCP/UDP checksum offload support. | ||||
*/ | */ | ||||
static __inline void | static __inline void | ||||
sk_rxcksum(ifp, m, csum) | sk_rxcksum(ifp, m, csum) | ||||
struct ifnet *ifp; | if_t ifp; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
u_int32_t csum; | u_int32_t csum; | ||||
{ | { | ||||
struct ether_header *eh; | struct ether_header *eh; | ||||
struct ip *ip; | struct ip *ip; | ||||
int32_t hlen, len, pktlen; | int32_t hlen, len, pktlen; | ||||
u_int16_t csum1, csum2, ipcsum; | u_int16_t csum1, csum2, ipcsum; | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
sk_rxeof(sc_if) | sk_rxeof(sc_if) | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
{ | { | ||||
struct sk_softc *sc; | struct sk_softc *sc; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
struct sk_rx_desc *cur_rx; | struct sk_rx_desc *cur_rx; | ||||
struct sk_rxdesc *rxd; | struct sk_rxdesc *rxd; | ||||
int cons, prog; | int cons, prog; | ||||
u_int32_t csum, rxstat, sk_ctl; | u_int32_t csum, rxstat, sk_ctl; | ||||
sc = sc_if->sk_softc; | sc = sc_if->sk_softc; | ||||
ifp = sc_if->sk_ifp; | ifp = sc_if->sk_ifp; | ||||
Show All 29 Lines | if (sk_newbuf(sc_if, cons) != 0) { | ||||
if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); | if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); | ||||
/* reuse old buffer */ | /* reuse old buffer */ | ||||
sk_discard_rxbuf(sc_if, cons); | sk_discard_rxbuf(sc_if, cons); | ||||
continue; | continue; | ||||
} | } | ||||
m->m_pkthdr.rcvif = ifp; | m->m_pkthdr.rcvif = ifp; | ||||
m->m_pkthdr.len = m->m_len = SK_RXBYTES(sk_ctl); | m->m_pkthdr.len = m->m_len = SK_RXBYTES(sk_ctl); | ||||
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); | if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); | ||||
if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) | if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) | ||||
sk_rxcksum(ifp, m, csum); | sk_rxcksum(ifp, m, csum); | ||||
SK_IF_UNLOCK(sc_if); | SK_IF_UNLOCK(sc_if); | ||||
(*ifp->if_input)(ifp, m); | if_input(ifp, m); | ||||
SK_IF_LOCK(sc_if); | SK_IF_LOCK(sc_if); | ||||
} | } | ||||
if (prog > 0) { | if (prog > 0) { | ||||
sc_if->sk_cdata.sk_rx_cons = cons; | sc_if->sk_cdata.sk_rx_cons = cons; | ||||
bus_dmamap_sync(sc_if->sk_cdata.sk_rx_ring_tag, | bus_dmamap_sync(sc_if->sk_cdata.sk_rx_ring_tag, | ||||
sc_if->sk_cdata.sk_rx_ring_map, | sc_if->sk_cdata.sk_rx_ring_map, | ||||
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
sk_jumbo_rxeof(sc_if) | sk_jumbo_rxeof(sc_if) | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
{ | { | ||||
struct sk_softc *sc; | struct sk_softc *sc; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
struct sk_rx_desc *cur_rx; | struct sk_rx_desc *cur_rx; | ||||
struct sk_rxdesc *jrxd; | struct sk_rxdesc *jrxd; | ||||
int cons, prog; | int cons, prog; | ||||
u_int32_t csum, rxstat, sk_ctl; | u_int32_t csum, rxstat, sk_ctl; | ||||
sc = sc_if->sk_softc; | sc = sc_if->sk_softc; | ||||
ifp = sc_if->sk_ifp; | ifp = sc_if->sk_ifp; | ||||
Show All 30 Lines | if (sk_jumbo_newbuf(sc_if, cons) != 0) { | ||||
if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); | if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); | ||||
/* reuse old buffer */ | /* reuse old buffer */ | ||||
sk_discard_jumbo_rxbuf(sc_if, cons); | sk_discard_jumbo_rxbuf(sc_if, cons); | ||||
continue; | continue; | ||||
} | } | ||||
m->m_pkthdr.rcvif = ifp; | m->m_pkthdr.rcvif = ifp; | ||||
m->m_pkthdr.len = m->m_len = SK_RXBYTES(sk_ctl); | m->m_pkthdr.len = m->m_len = SK_RXBYTES(sk_ctl); | ||||
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); | if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); | ||||
if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) | if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) | ||||
sk_rxcksum(ifp, m, csum); | sk_rxcksum(ifp, m, csum); | ||||
SK_IF_UNLOCK(sc_if); | SK_IF_UNLOCK(sc_if); | ||||
(*ifp->if_input)(ifp, m); | if_input(ifp, m); | ||||
SK_IF_LOCK(sc_if); | SK_IF_LOCK(sc_if); | ||||
} | } | ||||
if (prog > 0) { | if (prog > 0) { | ||||
sc_if->sk_cdata.sk_jumbo_rx_cons = cons; | sc_if->sk_cdata.sk_jumbo_rx_cons = cons; | ||||
bus_dmamap_sync(sc_if->sk_cdata.sk_jumbo_rx_ring_tag, | bus_dmamap_sync(sc_if->sk_cdata.sk_jumbo_rx_ring_tag, | ||||
sc_if->sk_cdata.sk_jumbo_rx_ring_map, | sc_if->sk_cdata.sk_jumbo_rx_ring_map, | ||||
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
sk_txeof(sc_if) | sk_txeof(sc_if) | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
{ | { | ||||
struct sk_txdesc *txd; | struct sk_txdesc *txd; | ||||
struct sk_tx_desc *cur_tx; | struct sk_tx_desc *cur_tx; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
u_int32_t idx, sk_ctl; | u_int32_t idx, sk_ctl; | ||||
ifp = sc_if->sk_ifp; | ifp = sc_if->sk_ifp; | ||||
txd = STAILQ_FIRST(&sc_if->sk_cdata.sk_txbusyq); | txd = STAILQ_FIRST(&sc_if->sk_cdata.sk_txbusyq); | ||||
if (txd == NULL) | if (txd == NULL) | ||||
return; | return; | ||||
bus_dmamap_sync(sc_if->sk_cdata.sk_tx_ring_tag, | bus_dmamap_sync(sc_if->sk_cdata.sk_tx_ring_tag, | ||||
sc_if->sk_cdata.sk_tx_ring_map, BUS_DMASYNC_POSTREAD); | sc_if->sk_cdata.sk_tx_ring_map, BUS_DMASYNC_POSTREAD); | ||||
/* | /* | ||||
* Go through our tx ring and free mbufs for those | * Go through our tx ring and free mbufs for those | ||||
* frames that have been sent. | * frames that have been sent. | ||||
*/ | */ | ||||
for (idx = sc_if->sk_cdata.sk_tx_cons;; SK_INC(idx, SK_TX_RING_CNT)) { | for (idx = sc_if->sk_cdata.sk_tx_cons;; SK_INC(idx, SK_TX_RING_CNT)) { | ||||
if (sc_if->sk_cdata.sk_tx_cnt <= 0) | if (sc_if->sk_cdata.sk_tx_cnt <= 0) | ||||
break; | break; | ||||
cur_tx = &sc_if->sk_rdata.sk_tx_ring[idx]; | cur_tx = &sc_if->sk_rdata.sk_tx_ring[idx]; | ||||
sk_ctl = le32toh(cur_tx->sk_ctl); | sk_ctl = le32toh(cur_tx->sk_ctl); | ||||
if (sk_ctl & SK_TXCTL_OWN) | if (sk_ctl & SK_TXCTL_OWN) | ||||
break; | break; | ||||
sc_if->sk_cdata.sk_tx_cnt--; | sc_if->sk_cdata.sk_tx_cnt--; | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); | ||||
if ((sk_ctl & SK_TXCTL_LASTFRAG) == 0) | if ((sk_ctl & SK_TXCTL_LASTFRAG) == 0) | ||||
continue; | continue; | ||||
bus_dmamap_sync(sc_if->sk_cdata.sk_tx_tag, txd->tx_dmamap, | bus_dmamap_sync(sc_if->sk_cdata.sk_tx_tag, txd->tx_dmamap, | ||||
BUS_DMASYNC_POSTWRITE); | BUS_DMASYNC_POSTWRITE); | ||||
bus_dmamap_unload(sc_if->sk_cdata.sk_tx_tag, txd->tx_dmamap); | bus_dmamap_unload(sc_if->sk_cdata.sk_tx_tag, txd->tx_dmamap); | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | ||||
m_freem(txd->tx_m); | m_freem(txd->tx_m); | ||||
Show All 11 Lines | |||||
} | } | ||||
static void | static void | ||||
sk_tick(xsc_if) | sk_tick(xsc_if) | ||||
void *xsc_if; | void *xsc_if; | ||||
{ | { | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
int i; | int i; | ||||
sc_if = xsc_if; | sc_if = xsc_if; | ||||
ifp = sc_if->sk_ifp; | ifp = sc_if->sk_ifp; | ||||
mii = device_get_softc(sc_if->sk_miibus); | mii = device_get_softc(sc_if->sk_miibus); | ||||
if (!(ifp->if_flags & IFF_UP)) | if (!(if_getflags(ifp) & IFF_UP)) | ||||
return; | return; | ||||
if (sc_if->sk_phytype == SK_PHYTYPE_BCOM) { | if (sc_if->sk_phytype == SK_PHYTYPE_BCOM) { | ||||
sk_intr_bcom(sc_if); | sk_intr_bcom(sc_if); | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
Show All 34 Lines | sk_yukon_tick(xsc_if) | ||||
callout_reset(&sc_if->sk_tick_ch, hz, sk_yukon_tick, sc_if); | callout_reset(&sc_if->sk_tick_ch, hz, sk_yukon_tick, sc_if); | ||||
} | } | ||||
static void | static void | ||||
sk_intr_bcom(sc_if) | sk_intr_bcom(sc_if) | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
{ | { | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
int status; | int status; | ||||
mii = device_get_softc(sc_if->sk_miibus); | mii = device_get_softc(sc_if->sk_miibus); | ||||
ifp = sc_if->sk_ifp; | ifp = sc_if->sk_ifp; | ||||
SK_XM_CLRBIT_2(sc_if, XM_MMUCMD, XM_MMUCMD_TX_ENB|XM_MMUCMD_RX_ENB); | SK_XM_CLRBIT_2(sc_if, XM_MMUCMD, XM_MMUCMD_TX_ENB|XM_MMUCMD_RX_ENB); | ||||
/* | /* | ||||
* Read the PHY interrupt register to make sure | * Read the PHY interrupt register to make sure | ||||
* we clear any pending interrupts. | * we clear any pending interrupts. | ||||
*/ | */ | ||||
status = sk_xmac_miibus_readreg(sc_if, SK_PHYADDR_BCOM, BRGPHY_MII_ISR); | status = sk_xmac_miibus_readreg(sc_if, SK_PHYADDR_BCOM, BRGPHY_MII_ISR); | ||||
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { | if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) { | ||||
sk_init_xmac(sc_if); | sk_init_xmac(sc_if); | ||||
return; | return; | ||||
} | } | ||||
if (status & (BRGPHY_ISR_LNK_CHG|BRGPHY_ISR_AN_PR)) { | if (status & (BRGPHY_ISR_LNK_CHG|BRGPHY_ISR_AN_PR)) { | ||||
int lstat; | int lstat; | ||||
lstat = sk_xmac_miibus_readreg(sc_if, SK_PHYADDR_BCOM, | lstat = sk_xmac_miibus_readreg(sc_if, SK_PHYADDR_BCOM, | ||||
BRGPHY_MII_AUXSTS); | BRGPHY_MII_AUXSTS); | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
sk_intr(xsc) | sk_intr(xsc) | ||||
void *xsc; | void *xsc; | ||||
{ | { | ||||
struct sk_softc *sc = xsc; | struct sk_softc *sc = xsc; | ||||
struct sk_if_softc *sc_if0, *sc_if1; | struct sk_if_softc *sc_if0, *sc_if1; | ||||
struct ifnet *ifp0 = NULL, *ifp1 = NULL; | if_t ifp0 = NULL, ifp1 = NULL; | ||||
u_int32_t status; | u_int32_t status; | ||||
SK_LOCK(sc); | SK_LOCK(sc); | ||||
status = CSR_READ_4(sc, SK_ISSR); | status = CSR_READ_4(sc, SK_ISSR); | ||||
if (status == 0 || status == 0xffffffff || sc->sk_suspended) | if (status == 0 || status == 0xffffffff || sc->sk_suspended) | ||||
goto done_locked; | goto done_locked; | ||||
sc_if0 = sc->sk_if[SK_PORT_A]; | sc_if0 = sc->sk_if[SK_PORT_A]; | ||||
sc_if1 = sc->sk_if[SK_PORT_B]; | sc_if1 = sc->sk_if[SK_PORT_B]; | ||||
if (sc_if0 != NULL) | if (sc_if0 != NULL) | ||||
ifp0 = sc_if0->sk_ifp; | ifp0 = sc_if0->sk_ifp; | ||||
if (sc_if1 != NULL) | if (sc_if1 != NULL) | ||||
ifp1 = sc_if1->sk_ifp; | ifp1 = sc_if1->sk_ifp; | ||||
for (; (status &= sc->sk_intrmask) != 0;) { | for (; (status &= sc->sk_intrmask) != 0;) { | ||||
/* Handle receive interrupts first. */ | /* Handle receive interrupts first. */ | ||||
if (status & SK_ISR_RX1_EOF) { | if (status & SK_ISR_RX1_EOF) { | ||||
if (ifp0->if_mtu > SK_MAX_FRAMELEN) | if (if_getmtu(ifp0) > SK_MAX_FRAMELEN) | ||||
sk_jumbo_rxeof(sc_if0); | sk_jumbo_rxeof(sc_if0); | ||||
else | else | ||||
sk_rxeof(sc_if0); | sk_rxeof(sc_if0); | ||||
CSR_WRITE_4(sc, SK_BMU_RX_CSR0, | CSR_WRITE_4(sc, SK_BMU_RX_CSR0, | ||||
SK_RXBMU_CLR_IRQ_EOF|SK_RXBMU_RX_START); | SK_RXBMU_CLR_IRQ_EOF|SK_RXBMU_RX_START); | ||||
} | } | ||||
if (status & SK_ISR_RX2_EOF) { | if (status & SK_ISR_RX2_EOF) { | ||||
if (ifp1->if_mtu > SK_MAX_FRAMELEN) | if (if_getflags(ifp1) > SK_MAX_FRAMELEN) | ||||
sk_jumbo_rxeof(sc_if1); | sk_jumbo_rxeof(sc_if1); | ||||
else | else | ||||
sk_rxeof(sc_if1); | sk_rxeof(sc_if1); | ||||
CSR_WRITE_4(sc, SK_BMU_RX_CSR1, | CSR_WRITE_4(sc, SK_BMU_RX_CSR1, | ||||
SK_RXBMU_CLR_IRQ_EOF|SK_RXBMU_RX_START); | SK_RXBMU_CLR_IRQ_EOF|SK_RXBMU_RX_START); | ||||
} | } | ||||
/* Then transmit interrupts. */ | /* Then transmit interrupts. */ | ||||
if (status & SK_ISR_TX1_S_EOF) { | if (status & SK_ISR_TX1_S_EOF) { | ||||
sk_txeof(sc_if0); | sk_txeof(sc_if0); | ||||
CSR_WRITE_4(sc, SK_BMU_TXS_CSR0, SK_TXBMU_CLR_IRQ_EOF); | CSR_WRITE_4(sc, SK_BMU_TXS_CSR0, SK_TXBMU_CLR_IRQ_EOF); | ||||
} | } | ||||
if (status & SK_ISR_TX2_S_EOF) { | if (status & SK_ISR_TX2_S_EOF) { | ||||
sk_txeof(sc_if1); | sk_txeof(sc_if1); | ||||
CSR_WRITE_4(sc, SK_BMU_TXS_CSR1, SK_TXBMU_CLR_IRQ_EOF); | CSR_WRITE_4(sc, SK_BMU_TXS_CSR1, SK_TXBMU_CLR_IRQ_EOF); | ||||
} | } | ||||
/* Then MAC interrupts. */ | /* Then MAC interrupts. */ | ||||
if (status & SK_ISR_MAC1 && | if (status & SK_ISR_MAC1 && | ||||
ifp0->if_drv_flags & IFF_DRV_RUNNING) { | if_getdrvflags(ifp0) & IFF_DRV_RUNNING) { | ||||
if (sc->sk_type == SK_GENESIS) | if (sc->sk_type == SK_GENESIS) | ||||
sk_intr_xmac(sc_if0); | sk_intr_xmac(sc_if0); | ||||
else | else | ||||
sk_intr_yukon(sc_if0); | sk_intr_yukon(sc_if0); | ||||
} | } | ||||
if (status & SK_ISR_MAC2 && | if (status & SK_ISR_MAC2 && | ||||
ifp1->if_drv_flags & IFF_DRV_RUNNING) { | if_getdrvflags(ifp1) & IFF_DRV_RUNNING) { | ||||
if (sc->sk_type == SK_GENESIS) | if (sc->sk_type == SK_GENESIS) | ||||
sk_intr_xmac(sc_if1); | sk_intr_xmac(sc_if1); | ||||
else | else | ||||
sk_intr_yukon(sc_if1); | sk_intr_yukon(sc_if1); | ||||
} | } | ||||
if (status & SK_ISR_EXTERNAL_REG) { | if (status & SK_ISR_EXTERNAL_REG) { | ||||
if (ifp0 != NULL && | if (ifp0 != NULL && | ||||
sc_if0->sk_phytype == SK_PHYTYPE_BCOM) | sc_if0->sk_phytype == SK_PHYTYPE_BCOM) | ||||
sk_intr_bcom(sc_if0); | sk_intr_bcom(sc_if0); | ||||
if (ifp1 != NULL && | if (ifp1 != NULL && | ||||
sc_if1->sk_phytype == SK_PHYTYPE_BCOM) | sc_if1->sk_phytype == SK_PHYTYPE_BCOM) | ||||
sk_intr_bcom(sc_if1); | sk_intr_bcom(sc_if1); | ||||
} | } | ||||
status = CSR_READ_4(sc, SK_ISSR); | status = CSR_READ_4(sc, SK_ISSR); | ||||
} | } | ||||
CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask); | CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask); | ||||
if (ifp0 != NULL && !IFQ_DRV_IS_EMPTY(&ifp0->if_snd)) | if (ifp0 != NULL && !if_sendq_empty(ifp0)) | ||||
sk_start_locked(ifp0); | sk_start_locked(ifp0); | ||||
if (ifp1 != NULL && !IFQ_DRV_IS_EMPTY(&ifp1->if_snd)) | if (ifp1 != NULL && !if_sendq_empty(ifp1)) | ||||
sk_start_locked(ifp1); | sk_start_locked(ifp1); | ||||
done_locked: | done_locked: | ||||
SK_UNLOCK(sc); | SK_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
sk_init_xmac(sc_if) | sk_init_xmac(sc_if) | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
{ | { | ||||
struct sk_softc *sc; | struct sk_softc *sc; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
u_int16_t eaddr[(ETHER_ADDR_LEN+1)/2]; | u_int16_t eaddr[(ETHER_ADDR_LEN+1)/2]; | ||||
static const struct sk_bcom_hack bhack[] = { | static const struct sk_bcom_hack bhack[] = { | ||||
{ 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 }, | { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 }, | ||||
{ 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 }, | { 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 }, | ||||
{ 0x15, 0x0232 }, { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 }, | { 0x15, 0x0232 }, { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 }, | ||||
{ 0, 0 } }; | { 0, 0 } }; | ||||
SK_IF_LOCK_ASSERT(sc_if); | SK_IF_LOCK_ASSERT(sc_if); | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | if (sk_xmac_miibus_readreg(sc_if, SK_PHYADDR_BCOM, 0x03) | ||||
sk_xmac_miibus_writereg(sc_if, SK_PHYADDR_BCOM, | sk_xmac_miibus_writereg(sc_if, SK_PHYADDR_BCOM, | ||||
bhack[i].reg, bhack[i].val); | bhack[i].reg, bhack[i].val); | ||||
i++; | i++; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* Set station address */ | /* Set station address */ | ||||
bcopy(IF_LLADDR(sc_if->sk_ifp), eaddr, ETHER_ADDR_LEN); | bcopy(if_getlladdr(sc_if->sk_ifp), eaddr, ETHER_ADDR_LEN); | ||||
SK_XM_WRITE_2(sc_if, XM_PAR0, eaddr[0]); | SK_XM_WRITE_2(sc_if, XM_PAR0, eaddr[0]); | ||||
SK_XM_WRITE_2(sc_if, XM_PAR1, eaddr[1]); | SK_XM_WRITE_2(sc_if, XM_PAR1, eaddr[1]); | ||||
SK_XM_WRITE_2(sc_if, XM_PAR2, eaddr[2]); | SK_XM_WRITE_2(sc_if, XM_PAR2, eaddr[2]); | ||||
SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_USE_STATION); | SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_USE_STATION); | ||||
if (ifp->if_flags & IFF_BROADCAST) { | if (if_getflags(ifp) & IFF_BROADCAST) { | ||||
SK_XM_CLRBIT_4(sc_if, XM_MODE, XM_MODE_RX_NOBROAD); | SK_XM_CLRBIT_4(sc_if, XM_MODE, XM_MODE_RX_NOBROAD); | ||||
} else { | } else { | ||||
SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_NOBROAD); | SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_NOBROAD); | ||||
} | } | ||||
/* We don't need the FCS appended to the packet. */ | /* We don't need the FCS appended to the packet. */ | ||||
SK_XM_SETBIT_2(sc_if, XM_RXCMD, XM_RXCMD_STRIPFCS); | SK_XM_SETBIT_2(sc_if, XM_RXCMD, XM_RXCMD_STRIPFCS); | ||||
Show All 9 Lines | sk_init_xmac(sc_if) | ||||
* in 'store and forward' mode. For this to work, the | * in 'store and forward' mode. For this to work, the | ||||
* entire frame has to fit into the FIFO, but that means | * entire frame has to fit into the FIFO, but that means | ||||
* that jumbo frames larger than 8192 bytes will be | * that jumbo frames larger than 8192 bytes will be | ||||
* truncated. Disabling all bad frame filtering causes | * truncated. Disabling all bad frame filtering causes | ||||
* the RX FIFO to operate in streaming mode, in which | * the RX FIFO to operate in streaming mode, in which | ||||
* case the XMAC will start transferring frames out of the | * case the XMAC will start transferring frames out of the | ||||
* RX FIFO as soon as the FIFO threshold is reached. | * RX FIFO as soon as the FIFO threshold is reached. | ||||
*/ | */ | ||||
if (ifp->if_mtu > SK_MAX_FRAMELEN) { | if (if_getmtu(ifp) > SK_MAX_FRAMELEN) { | ||||
SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_BADFRAMES| | SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_BADFRAMES| | ||||
XM_MODE_RX_GIANTS|XM_MODE_RX_RUNTS|XM_MODE_RX_CRCERRS| | XM_MODE_RX_GIANTS|XM_MODE_RX_RUNTS|XM_MODE_RX_CRCERRS| | ||||
XM_MODE_RX_INRANGELEN); | XM_MODE_RX_INRANGELEN); | ||||
SK_XM_SETBIT_2(sc_if, XM_RXCMD, XM_RXCMD_BIGPKTOK); | SK_XM_SETBIT_2(sc_if, XM_RXCMD, XM_RXCMD_BIGPKTOK); | ||||
} else | } else | ||||
SK_XM_CLRBIT_2(sc_if, XM_RXCMD, XM_RXCMD_BIGPKTOK); | SK_XM_CLRBIT_2(sc_if, XM_RXCMD, XM_RXCMD_BIGPKTOK); | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
sk_init_yukon(sc_if) | sk_init_yukon(sc_if) | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
{ | { | ||||
u_int32_t phy, v; | u_int32_t phy, v; | ||||
u_int16_t reg; | u_int16_t reg; | ||||
struct sk_softc *sc; | struct sk_softc *sc; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
u_int8_t *eaddr; | u_int8_t *eaddr; | ||||
int i; | int i; | ||||
SK_IF_LOCK_ASSERT(sc_if); | SK_IF_LOCK_ASSERT(sc_if); | ||||
sc = sc_if->sk_softc; | sc = sc_if->sk_softc; | ||||
ifp = sc_if->sk_ifp; | ifp = sc_if->sk_ifp; | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | sk_init_yukon(sc_if) | ||||
SK_YU_WRITE_2(sc_if, YUKON_RCR, YU_RCR_CRCR); | SK_YU_WRITE_2(sc_if, YUKON_RCR, YU_RCR_CRCR); | ||||
/* transmit parameter register */ | /* transmit parameter register */ | ||||
SK_YU_WRITE_2(sc_if, YUKON_TPR, YU_TPR_JAM_LEN(0x3) | | SK_YU_WRITE_2(sc_if, YUKON_TPR, YU_TPR_JAM_LEN(0x3) | | ||||
YU_TPR_JAM_IPG(0xb) | YU_TPR_JAM2DATA_IPG(0x1a) ); | YU_TPR_JAM_IPG(0xb) | YU_TPR_JAM2DATA_IPG(0x1a) ); | ||||
/* serial mode register */ | /* serial mode register */ | ||||
reg = YU_SMR_DATA_BLIND(0x1c) | YU_SMR_MFL_VLAN | YU_SMR_IPG_DATA(0x1e); | reg = YU_SMR_DATA_BLIND(0x1c) | YU_SMR_MFL_VLAN | YU_SMR_IPG_DATA(0x1e); | ||||
if (ifp->if_mtu > SK_MAX_FRAMELEN) | if (if_getmtu(ifp) > SK_MAX_FRAMELEN) | ||||
reg |= YU_SMR_MFL_JUMBO; | reg |= YU_SMR_MFL_JUMBO; | ||||
SK_YU_WRITE_2(sc_if, YUKON_SMR, reg); | SK_YU_WRITE_2(sc_if, YUKON_SMR, reg); | ||||
/* Setup Yukon's station address */ | /* Setup Yukon's station address */ | ||||
eaddr = IF_LLADDR(sc_if->sk_ifp); | eaddr = if_getlladdr(sc_if->sk_ifp); | ||||
for (i = 0; i < 3; i++) | for (i = 0; i < 3; i++) | ||||
SK_YU_WRITE_2(sc_if, SK_MAC0_0 + i * 4, | SK_YU_WRITE_2(sc_if, SK_MAC0_0 + i * 4, | ||||
eaddr[i * 2] | eaddr[i * 2 + 1] << 8); | eaddr[i * 2] | eaddr[i * 2 + 1] << 8); | ||||
/* Set GMAC source address of flow control. */ | /* Set GMAC source address of flow control. */ | ||||
for (i = 0; i < 3; i++) | for (i = 0; i < 3; i++) | ||||
SK_YU_WRITE_2(sc_if, YUKON_SAL1 + i * 4, | SK_YU_WRITE_2(sc_if, YUKON_SAL1 + i * 4, | ||||
eaddr[i * 2] | eaddr[i * 2 + 1] << 8); | eaddr[i * 2] | eaddr[i * 2 + 1] << 8); | ||||
/* Set GMAC virtual address. */ | /* Set GMAC virtual address. */ | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | sk_init(xsc) | ||||
return; | return; | ||||
} | } | ||||
static void | static void | ||||
sk_init_locked(sc_if) | sk_init_locked(sc_if) | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
{ | { | ||||
struct sk_softc *sc; | struct sk_softc *sc; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
u_int16_t reg; | u_int16_t reg; | ||||
u_int32_t imr; | u_int32_t imr; | ||||
int error; | int error; | ||||
SK_IF_LOCK_ASSERT(sc_if); | SK_IF_LOCK_ASSERT(sc_if); | ||||
ifp = sc_if->sk_ifp; | ifp = sc_if->sk_ifp; | ||||
sc = sc_if->sk_softc; | sc = sc_if->sk_softc; | ||||
mii = device_get_softc(sc_if->sk_miibus); | mii = device_get_softc(sc_if->sk_miibus); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) | ||||
return; | return; | ||||
/* Cancel pending I/O and free all RX/TX buffers. */ | /* Cancel pending I/O and free all RX/TX buffers. */ | ||||
sk_stop(sc_if); | sk_stop(sc_if); | ||||
if (sc->sk_type == SK_GENESIS) { | if (sc->sk_type == SK_GENESIS) { | ||||
/* Configure LINK_SYNC LED */ | /* Configure LINK_SYNC LED */ | ||||
SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_ON); | SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_ON); | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | sk_init_locked(sc_if) | ||||
SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_START, sc_if->sk_tx_ramstart); | SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_START, sc_if->sk_tx_ramstart); | ||||
SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_WR_PTR, sc_if->sk_tx_ramstart); | SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_WR_PTR, sc_if->sk_tx_ramstart); | ||||
SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_RD_PTR, sc_if->sk_tx_ramstart); | SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_RD_PTR, sc_if->sk_tx_ramstart); | ||||
SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_END, sc_if->sk_tx_ramend); | SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_END, sc_if->sk_tx_ramend); | ||||
SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_ON); | SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_ON); | ||||
/* Configure BMUs */ | /* Configure BMUs */ | ||||
SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, SK_RXBMU_ONLINE); | SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, SK_RXBMU_ONLINE); | ||||
if (ifp->if_mtu > SK_MAX_FRAMELEN) { | if (if_getmtu(ifp) > SK_MAX_FRAMELEN) { | ||||
SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_CURADDR_LO, | SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_CURADDR_LO, | ||||
SK_ADDR_LO(SK_JUMBO_RX_RING_ADDR(sc_if, 0))); | SK_ADDR_LO(SK_JUMBO_RX_RING_ADDR(sc_if, 0))); | ||||
SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_CURADDR_HI, | SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_CURADDR_HI, | ||||
SK_ADDR_HI(SK_JUMBO_RX_RING_ADDR(sc_if, 0))); | SK_ADDR_HI(SK_JUMBO_RX_RING_ADDR(sc_if, 0))); | ||||
} else { | } else { | ||||
SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_CURADDR_LO, | SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_CURADDR_LO, | ||||
SK_ADDR_LO(SK_RX_RING_ADDR(sc_if, 0))); | SK_ADDR_LO(SK_RX_RING_ADDR(sc_if, 0))); | ||||
SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_CURADDR_HI, | SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_CURADDR_HI, | ||||
SK_ADDR_HI(SK_RX_RING_ADDR(sc_if, 0))); | SK_ADDR_HI(SK_RX_RING_ADDR(sc_if, 0))); | ||||
} | } | ||||
SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_BMU_CSR, SK_TXBMU_ONLINE); | SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_BMU_CSR, SK_TXBMU_ONLINE); | ||||
SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_CURADDR_LO, | SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_CURADDR_LO, | ||||
SK_ADDR_LO(SK_TX_RING_ADDR(sc_if, 0))); | SK_ADDR_LO(SK_TX_RING_ADDR(sc_if, 0))); | ||||
SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_CURADDR_HI, | SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_CURADDR_HI, | ||||
SK_ADDR_HI(SK_TX_RING_ADDR(sc_if, 0))); | SK_ADDR_HI(SK_TX_RING_ADDR(sc_if, 0))); | ||||
/* Init descriptors */ | /* Init descriptors */ | ||||
if (ifp->if_mtu > SK_MAX_FRAMELEN) | if (if_getmtu(ifp) > SK_MAX_FRAMELEN) | ||||
error = sk_init_jumbo_rx_ring(sc_if); | error = sk_init_jumbo_rx_ring(sc_if); | ||||
else | else | ||||
error = sk_init_rx_ring(sc_if); | error = sk_init_rx_ring(sc_if); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(sc_if->sk_if_dev, | device_printf(sc_if->sk_if_dev, | ||||
"initialization failed: no memory for rx buffers\n"); | "initialization failed: no memory for rx buffers\n"); | ||||
sk_stop(sc_if); | sk_stop(sc_if); | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | #endif | ||||
SK_YU_WRITE_2(sc_if, YUKON_GPCR, reg); | SK_YU_WRITE_2(sc_if, YUKON_GPCR, reg); | ||||
} | } | ||||
/* Activate descriptor polling timer */ | /* Activate descriptor polling timer */ | ||||
SK_IF_WRITE_4(sc_if, 0, SK_DPT_TIMER_CTRL, SK_DPT_TCTL_START); | SK_IF_WRITE_4(sc_if, 0, SK_DPT_TIMER_CTRL, SK_DPT_TCTL_START); | ||||
/* start transfer of Tx descriptors */ | /* start transfer of Tx descriptors */ | ||||
CSR_WRITE_4(sc, sc_if->sk_tx_bmu, SK_TXBMU_TX_START); | CSR_WRITE_4(sc, sc_if->sk_tx_bmu, SK_TXBMU_TX_START); | ||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); | ||||
switch (sc->sk_type) { | switch (sc->sk_type) { | ||||
case SK_YUKON: | case SK_YUKON: | ||||
case SK_YUKON_LITE: | case SK_YUKON_LITE: | ||||
case SK_YUKON_LP: | case SK_YUKON_LP: | ||||
callout_reset(&sc_if->sk_tick_ch, hz, sk_yukon_tick, sc_if); | callout_reset(&sc_if->sk_tick_ch, hz, sk_yukon_tick, sc_if); | ||||
break; | break; | ||||
} | } | ||||
callout_reset(&sc_if->sk_watchdog_ch, hz, sk_watchdog, ifp); | callout_reset(&sc_if->sk_watchdog_ch, hz, sk_watchdog, ifp); | ||||
return; | return; | ||||
} | } | ||||
static void | static void | ||||
sk_stop(sc_if) | sk_stop(sc_if) | ||||
struct sk_if_softc *sc_if; | struct sk_if_softc *sc_if; | ||||
{ | { | ||||
int i; | int i; | ||||
struct sk_softc *sc; | struct sk_softc *sc; | ||||
struct sk_txdesc *txd; | struct sk_txdesc *txd; | ||||
struct sk_rxdesc *rxd; | struct sk_rxdesc *rxd; | ||||
struct sk_rxdesc *jrxd; | struct sk_rxdesc *jrxd; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
u_int32_t val; | u_int32_t val; | ||||
SK_IF_LOCK_ASSERT(sc_if); | SK_IF_LOCK_ASSERT(sc_if); | ||||
sc = sc_if->sk_softc; | sc = sc_if->sk_softc; | ||||
ifp = sc_if->sk_ifp; | ifp = sc_if->sk_ifp; | ||||
callout_stop(&sc_if->sk_tick_ch); | callout_stop(&sc_if->sk_tick_ch); | ||||
callout_stop(&sc_if->sk_watchdog_ch); | callout_stop(&sc_if->sk_watchdog_ch); | ||||
▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | if (txd->tx_m != NULL) { | ||||
txd->tx_dmamap, BUS_DMASYNC_POSTWRITE); | txd->tx_dmamap, BUS_DMASYNC_POSTWRITE); | ||||
bus_dmamap_unload(sc_if->sk_cdata.sk_tx_tag, | bus_dmamap_unload(sc_if->sk_cdata.sk_tx_tag, | ||||
txd->tx_dmamap); | txd->tx_dmamap); | ||||
m_freem(txd->tx_m); | m_freem(txd->tx_m); | ||||
txd->tx_m = NULL; | txd->tx_m = NULL; | ||||
} | } | ||||
} | } | ||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE); | if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)); | ||||
return; | return; | ||||
} | } | ||||
static int | static int | ||||
sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) | sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) | ||||
{ | { | ||||
int error, value; | int error, value; | ||||
Show All 18 Lines |