Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/smc/if_smc.c
Show First 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | static const char *smc_chip_ids[16] = { | ||||
/* 7 */ "SMSC LAN91C100", | /* 7 */ "SMSC LAN91C100", | ||||
/* 8 */ "SMSC LAN91C100FD", | /* 8 */ "SMSC LAN91C100FD", | ||||
/* 9 */ "SMSC LAN91C110FD or LAN91C111FD", | /* 9 */ "SMSC LAN91C110FD or LAN91C111FD", | ||||
NULL, NULL, NULL, | NULL, NULL, NULL, | ||||
NULL, NULL, NULL | NULL, NULL, NULL | ||||
}; | }; | ||||
static void smc_init(void *); | static void smc_init(void *); | ||||
static void smc_start(struct ifnet *); | static void smc_start(if_t); | ||||
static void smc_stop(struct smc_softc *); | static void smc_stop(struct smc_softc *); | ||||
static int smc_ioctl(struct ifnet *, u_long, caddr_t); | static int smc_ioctl(if_t, u_long, caddr_t); | ||||
static void smc_init_locked(struct smc_softc *); | static void smc_init_locked(struct smc_softc *); | ||||
static void smc_start_locked(struct ifnet *); | static void smc_start_locked(if_t); | ||||
static void smc_reset(struct smc_softc *); | static void smc_reset(struct smc_softc *); | ||||
static int smc_mii_ifmedia_upd(struct ifnet *); | static int smc_mii_ifmedia_upd(if_t); | ||||
static void smc_mii_ifmedia_sts(struct ifnet *, struct ifmediareq *); | static void smc_mii_ifmedia_sts(if_t, struct ifmediareq *); | ||||
static void smc_mii_tick(void *); | static void smc_mii_tick(void *); | ||||
static void smc_mii_mediachg(struct smc_softc *); | static void smc_mii_mediachg(struct smc_softc *); | ||||
static int smc_mii_mediaioctl(struct smc_softc *, struct ifreq *, u_long); | static int smc_mii_mediaioctl(struct smc_softc *, struct ifreq *, u_long); | ||||
static void smc_task_intr(void *, int); | static void smc_task_intr(void *, int); | ||||
static void smc_task_rx(void *, int); | static void smc_task_rx(void *, int); | ||||
static void smc_task_tx(void *, int); | static void smc_task_tx(void *, int); | ||||
▲ Show 20 Lines • Show All 178 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
smc_attach(device_t dev) | smc_attach(device_t dev) | ||||
{ | { | ||||
int type, error; | int type, error; | ||||
uint16_t val; | uint16_t val; | ||||
u_char eaddr[ETHER_ADDR_LEN]; | u_char eaddr[ETHER_ADDR_LEN]; | ||||
struct smc_softc *sc; | struct smc_softc *sc; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
error = 0; | error = 0; | ||||
sc->smc_dev = dev; | sc->smc_dev = dev; | ||||
ifp = sc->smc_ifp = if_alloc(IFT_ETHER); | ifp = sc->smc_ifp = if_alloc(IFT_ETHER); | ||||
if (ifp == NULL) { | if (ifp == NULL) { | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | smc_attach(device_t dev) | ||||
eaddr[0] = smc_read_1(sc, IAR0); | eaddr[0] = smc_read_1(sc, IAR0); | ||||
eaddr[1] = smc_read_1(sc, IAR1); | eaddr[1] = smc_read_1(sc, IAR1); | ||||
eaddr[2] = smc_read_1(sc, IAR2); | eaddr[2] = smc_read_1(sc, IAR2); | ||||
eaddr[3] = smc_read_1(sc, IAR3); | eaddr[3] = smc_read_1(sc, IAR3); | ||||
eaddr[4] = smc_read_1(sc, IAR4); | eaddr[4] = smc_read_1(sc, IAR4); | ||||
eaddr[5] = smc_read_1(sc, IAR5); | eaddr[5] = smc_read_1(sc, IAR5); | ||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | ||||
ifp->if_softc = sc; | if_setsoftc(ifp, sc); | ||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); | ||||
ifp->if_init = smc_init; | if_setinitfn(ifp, smc_init); | ||||
ifp->if_ioctl = smc_ioctl; | if_setioctlfn(ifp, smc_ioctl); | ||||
ifp->if_start = smc_start; | if_setstartfn(ifp, smc_start); | ||||
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); | if_setsendqlen(ifp, ifqmaxlen); | ||||
IFQ_SET_READY(&ifp->if_snd); | if_setsendqready(ifp); | ||||
ifp->if_capabilities = ifp->if_capenable = 0; | if_setcapabilities(ifp, if_getcapenable(ifp) ); | ||||
#ifdef DEVICE_POLLING | #ifdef DEVICE_POLLING | ||||
ifp->if_capabilities |= IFCAP_POLLING; | if_setcapabilitiesbit(ifp, IFCAP_POLLING, 0); | ||||
#endif | #endif | ||||
ether_ifattach(ifp, eaddr); | ether_ifattach(ifp, eaddr); | ||||
/* Set up taskqueue */ | /* Set up taskqueue */ | ||||
TASK_INIT(&sc->smc_intr, SMC_INTR_PRIORITY, smc_task_intr, ifp); | TASK_INIT(&sc->smc_intr, SMC_INTR_PRIORITY, smc_task_intr, ifp); | ||||
NET_TASK_INIT(&sc->smc_rx, SMC_RX_PRIORITY, smc_task_rx, ifp); | NET_TASK_INIT(&sc->smc_rx, SMC_RX_PRIORITY, smc_task_rx, ifp); | ||||
TASK_INIT(&sc->smc_tx, SMC_TX_PRIORITY, smc_task_tx, ifp); | TASK_INIT(&sc->smc_tx, SMC_TX_PRIORITY, smc_task_tx, ifp); | ||||
Show All 32 Lines | smc_detach(device_t dev) | ||||
if (sc->smc_ifp != NULL) { | if (sc->smc_ifp != NULL) { | ||||
ether_ifdetach(sc->smc_ifp); | ether_ifdetach(sc->smc_ifp); | ||||
} | } | ||||
callout_drain(&sc->smc_watchdog); | callout_drain(&sc->smc_watchdog); | ||||
callout_drain(&sc->smc_mii_tick_ch); | callout_drain(&sc->smc_mii_tick_ch); | ||||
#ifdef DEVICE_POLLING | #ifdef DEVICE_POLLING | ||||
if (sc->smc_ifp->if_capenable & IFCAP_POLLING) | if (sc->smc_if_getcapenable(ifp) & IFCAP_POLLING) | ||||
ether_poll_deregister(sc->smc_ifp); | ether_poll_deregister(sc->smc_ifp); | ||||
#endif | #endif | ||||
if (sc->smc_ih != NULL) | if (sc->smc_ih != NULL) | ||||
bus_teardown_intr(sc->smc_dev, sc->smc_irq, sc->smc_ih); | bus_teardown_intr(sc->smc_dev, sc->smc_irq, sc->smc_ih); | ||||
if (sc->smc_tq != NULL) { | if (sc->smc_tq != NULL) { | ||||
taskqueue_drain(sc->smc_tq, &sc->smc_intr); | taskqueue_drain(sc->smc_tq, &sc->smc_intr); | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | driver_t smc_driver = { | ||||
"smc", | "smc", | ||||
smc_methods, | smc_methods, | ||||
sizeof(struct smc_softc), | sizeof(struct smc_softc), | ||||
}; | }; | ||||
DRIVER_MODULE(miibus, smc, miibus_driver, 0, 0); | DRIVER_MODULE(miibus, smc, miibus_driver, 0, 0); | ||||
static void | static void | ||||
smc_start(struct ifnet *ifp) | smc_start(if_t ifp) | ||||
{ | { | ||||
struct smc_softc *sc; | struct smc_softc *sc; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
SMC_LOCK(sc); | SMC_LOCK(sc); | ||||
smc_start_locked(ifp); | smc_start_locked(ifp); | ||||
SMC_UNLOCK(sc); | SMC_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
smc_start_locked(struct ifnet *ifp) | smc_start_locked(if_t ifp) | ||||
{ | { | ||||
struct smc_softc *sc; | struct smc_softc *sc; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
u_int len, npages, spin_count; | u_int len, npages, spin_count; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
SMC_ASSERT_LOCKED(sc); | SMC_ASSERT_LOCKED(sc); | ||||
if (ifp->if_drv_flags & IFF_DRV_OACTIVE) | if (if_getdrvflags(ifp) & IFF_DRV_OACTIVE) | ||||
return; | return; | ||||
if (IFQ_IS_EMPTY(&ifp->if_snd)) | if (if_sendq_empty(ifp)) | ||||
return; | return; | ||||
/* | /* | ||||
* Grab the next packet. If it's too big, drop it. | * Grab the next packet. If it's too big, drop it. | ||||
*/ | */ | ||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m); | m = if_dequeue(ifp); | ||||
len = m_length(m, NULL); | len = m_length(m, NULL); | ||||
len += (len & 1); | len += (len & 1); | ||||
if (len > ETHER_MAX_LEN - ETHER_CRC_LEN) { | if (len > ETHER_MAX_LEN - ETHER_CRC_LEN) { | ||||
if_printf(ifp, "large packet discarded\n"); | if_printf(ifp, "large packet discarded\n"); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | ||||
m_freem(m); | m_freem(m); | ||||
return; /* XXX readcheck? */ | return; /* XXX readcheck? */ | ||||
} | } | ||||
/* | /* | ||||
* Flag that we're busy. | * Flag that we're busy. | ||||
*/ | */ | ||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); | ||||
sc->smc_pending = m; | sc->smc_pending = m; | ||||
/* | /* | ||||
* Work out how many 256 byte "pages" we need. We have to include the | * Work out how many 256 byte "pages" we need. We have to include the | ||||
* control data for the packet in this calculation. | * control data for the packet in this calculation. | ||||
*/ | */ | ||||
npages = (len + PKT_CTRL_DATA_LEN) >> 8; | npages = (len + PKT_CTRL_DATA_LEN) >> 8; | ||||
if (npages == 0) | if (npages == 0) | ||||
Show All 18 Lines | smc_start_locked(if_t ifp) | ||||
} while (--spin_count); | } while (--spin_count); | ||||
/* | /* | ||||
* If the allocation is taking too long, unmask the alloc interrupt | * If the allocation is taking too long, unmask the alloc interrupt | ||||
* and wait. | * and wait. | ||||
*/ | */ | ||||
if (spin_count == 0) { | if (spin_count == 0) { | ||||
sc->smc_mask |= ALLOC_INT; | sc->smc_mask |= ALLOC_INT; | ||||
if ((ifp->if_capenable & IFCAP_POLLING) == 0) | if ((if_getcapenable(ifp) & IFCAP_POLLING) == 0) | ||||
smc_write_1(sc, MSK, sc->smc_mask); | smc_write_1(sc, MSK, sc->smc_mask); | ||||
return; | return; | ||||
} | } | ||||
taskqueue_enqueue(sc->smc_tq, &sc->smc_tx); | taskqueue_enqueue(sc->smc_tq, &sc->smc_tx); | ||||
} | } | ||||
static void | static void | ||||
smc_task_tx(void *context, int pending) | smc_task_tx(void *context, int pending) | ||||
{ | { | ||||
struct ifnet *ifp; | if_t ifp; | ||||
struct smc_softc *sc; | struct smc_softc *sc; | ||||
struct mbuf *m, *m0; | struct mbuf *m, *m0; | ||||
u_int packet, len; | u_int packet, len; | ||||
int last_len; | int last_len; | ||||
uint8_t *data; | uint8_t *data; | ||||
(void)pending; | (void)pending; | ||||
ifp = (struct ifnet *)context; | ifp = (if_t)context; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
SMC_LOCK(sc); | SMC_LOCK(sc); | ||||
if (sc->smc_pending == NULL) { | if (sc->smc_pending == NULL) { | ||||
SMC_UNLOCK(sc); | SMC_UNLOCK(sc); | ||||
goto next_packet; | goto next_packet; | ||||
} | } | ||||
m = m0 = sc->smc_pending; | m = m0 = sc->smc_pending; | ||||
sc->smc_pending = NULL; | sc->smc_pending = NULL; | ||||
smc_select_bank(sc, 2); | smc_select_bank(sc, 2); | ||||
/* | /* | ||||
* Check the allocation result. | * Check the allocation result. | ||||
*/ | */ | ||||
packet = smc_read_1(sc, ARR); | packet = smc_read_1(sc, ARR); | ||||
/* | /* | ||||
* If the allocation failed, requeue the packet and retry. | * If the allocation failed, requeue the packet and retry. | ||||
*/ | */ | ||||
if (packet & ARR_FAILED) { | if (packet & ARR_FAILED) { | ||||
IFQ_DRV_PREPEND(&ifp->if_snd, m); | if_sendq_prepend(ifp, m); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); | ||||
smc_start_locked(ifp); | smc_start_locked(ifp); | ||||
SMC_UNLOCK(sc); | SMC_UNLOCK(sc); | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* Tell the device to write to our packet number. | * Tell the device to write to our packet number. | ||||
*/ | */ | ||||
Show All 26 Lines | if ((len & 1) != 0 && data != NULL) | ||||
smc_write_2(sc, DATA0, (CTRL_ODD << 8) | data[last_len - 1]); | smc_write_2(sc, DATA0, (CTRL_ODD << 8) | data[last_len - 1]); | ||||
else | else | ||||
smc_write_2(sc, DATA0, 0); | smc_write_2(sc, DATA0, 0); | ||||
/* | /* | ||||
* Unmask the TX empty interrupt. | * Unmask the TX empty interrupt. | ||||
*/ | */ | ||||
sc->smc_mask |= TX_EMPTY_INT; | sc->smc_mask |= TX_EMPTY_INT; | ||||
if ((ifp->if_capenable & IFCAP_POLLING) == 0) | if ((if_getcapenable(ifp) & IFCAP_POLLING) == 0) | ||||
smc_write_1(sc, MSK, sc->smc_mask); | smc_write_1(sc, MSK, sc->smc_mask); | ||||
/* | /* | ||||
* Enqueue the packet. | * Enqueue the packet. | ||||
*/ | */ | ||||
smc_mmu_wait(sc); | smc_mmu_wait(sc); | ||||
smc_write_2(sc, MMUCR, MMUCR_CMD_ENQUEUE); | smc_write_2(sc, MMUCR, MMUCR_CMD_ENQUEUE); | ||||
callout_reset(&sc->smc_watchdog, hz * 2, smc_watchdog, sc); | callout_reset(&sc->smc_watchdog, hz * 2, smc_watchdog, sc); | ||||
/* | /* | ||||
* Finish up. | * Finish up. | ||||
*/ | */ | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); | ||||
SMC_UNLOCK(sc); | SMC_UNLOCK(sc); | ||||
BPF_MTAP(ifp, m0); | BPF_MTAP(ifp, m0); | ||||
m_freem(m0); | m_freem(m0); | ||||
next_packet: | next_packet: | ||||
/* | /* | ||||
* See if there's anything else to do. | * See if there's anything else to do. | ||||
*/ | */ | ||||
smc_start(ifp); | smc_start(ifp); | ||||
} | } | ||||
static void | static void | ||||
smc_task_rx(void *context, int pending) | smc_task_rx(void *context, int pending) | ||||
{ | { | ||||
u_int packet, status, len; | u_int packet, status, len; | ||||
uint8_t *data; | uint8_t *data; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
struct smc_softc *sc; | struct smc_softc *sc; | ||||
struct mbuf *m, *mhead, *mtail; | struct mbuf *m, *mhead, *mtail; | ||||
(void)pending; | (void)pending; | ||||
ifp = (struct ifnet *)context; | ifp = (if_t)context; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
mhead = mtail = NULL; | mhead = mtail = NULL; | ||||
SMC_LOCK(sc); | SMC_LOCK(sc); | ||||
packet = smc_read_1(sc, FIFO_RX); | packet = smc_read_1(sc, FIFO_RX); | ||||
while ((packet & FIFO_EMPTY) == 0) { | while ((packet & FIFO_EMPTY) == 0) { | ||||
/* | /* | ||||
* Grab an mbuf and attach a cluster. | * Grab an mbuf and attach a cluster. | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | while ((packet & FIFO_EMPTY) == 0) { | ||||
} else { | } else { | ||||
mtail->m_next = m; | mtail->m_next = m; | ||||
mtail = m; | mtail = m; | ||||
} | } | ||||
packet = smc_read_1(sc, FIFO_RX); | packet = smc_read_1(sc, FIFO_RX); | ||||
} | } | ||||
sc->smc_mask |= RCV_INT; | sc->smc_mask |= RCV_INT; | ||||
if ((ifp->if_capenable & IFCAP_POLLING) == 0) | if ((if_getcapenable(ifp) & IFCAP_POLLING) == 0) | ||||
smc_write_1(sc, MSK, sc->smc_mask); | smc_write_1(sc, MSK, sc->smc_mask); | ||||
SMC_UNLOCK(sc); | SMC_UNLOCK(sc); | ||||
while (mhead != NULL) { | while (mhead != NULL) { | ||||
m = mhead; | m = mhead; | ||||
mhead = mhead->m_next; | mhead = mhead->m_next; | ||||
m->m_next = NULL; | m->m_next = NULL; | ||||
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); | if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); | ||||
(*ifp->if_input)(ifp, m); | if_input(ifp, m); | ||||
} | } | ||||
} | } | ||||
#ifdef DEVICE_POLLING | #ifdef DEVICE_POLLING | ||||
static int | static int | ||||
smc_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) | smc_poll(if_t ifp, enum poll_cmd cmd, int count) | ||||
{ | { | ||||
struct smc_softc *sc; | struct smc_softc *sc; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
SMC_LOCK(sc); | SMC_LOCK(sc); | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) { | ||||
SMC_UNLOCK(sc); | SMC_UNLOCK(sc); | ||||
return (0); | return (0); | ||||
} | } | ||||
SMC_UNLOCK(sc); | SMC_UNLOCK(sc); | ||||
if (cmd == POLL_AND_CHECK_STATUS) | if (cmd == POLL_AND_CHECK_STATUS) | ||||
taskqueue_enqueue(sc->smc_tq, &sc->smc_intr); | taskqueue_enqueue(sc->smc_tq, &sc->smc_intr); | ||||
return (0); | return (0); | ||||
Show All 25 Lines | smc_intr(void *context) | ||||
taskqueue_enqueue(sc->smc_tq, &sc->smc_intr); | taskqueue_enqueue(sc->smc_tq, &sc->smc_intr); | ||||
return (FILTER_HANDLED); | return (FILTER_HANDLED); | ||||
} | } | ||||
static void | static void | ||||
smc_task_intr(void *context, int pending) | smc_task_intr(void *context, int pending) | ||||
{ | { | ||||
struct smc_softc *sc; | struct smc_softc *sc; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
u_int status, packet, counter, tcr; | u_int status, packet, counter, tcr; | ||||
(void)pending; | (void)pending; | ||||
ifp = (struct ifnet *)context; | ifp = (if_t)context; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
SMC_LOCK(sc); | SMC_LOCK(sc); | ||||
smc_select_bank(sc, 2); | smc_select_bank(sc, 2); | ||||
/* | /* | ||||
* Find out what interrupts are flagged. | * Find out what interrupts are flagged. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | if (status & TX_EMPTY_INT) { | ||||
*/ | */ | ||||
taskqueue_enqueue(sc->smc_tq, &sc->smc_tx); | taskqueue_enqueue(sc->smc_tq, &sc->smc_tx); | ||||
} | } | ||||
/* | /* | ||||
* Update the interrupt mask. | * Update the interrupt mask. | ||||
*/ | */ | ||||
smc_select_bank(sc, 2); | smc_select_bank(sc, 2); | ||||
if ((ifp->if_capenable & IFCAP_POLLING) == 0) | if ((if_getcapenable(ifp) & IFCAP_POLLING) == 0) | ||||
smc_write_1(sc, MSK, sc->smc_mask); | smc_write_1(sc, MSK, sc->smc_mask); | ||||
SMC_UNLOCK(sc); | SMC_UNLOCK(sc); | ||||
} | } | ||||
static uint32_t | static uint32_t | ||||
smc_mii_bitbang_read(device_t dev) | smc_mii_bitbang_read(device_t dev) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | else | ||||
tcr &= ~TCR_SWFDUP; | tcr &= ~TCR_SWFDUP; | ||||
smc_write_2(sc, TCR, tcr); | smc_write_2(sc, TCR, tcr); | ||||
SMC_UNLOCK(sc); | SMC_UNLOCK(sc); | ||||
} | } | ||||
static int | static int | ||||
smc_mii_ifmedia_upd(struct ifnet *ifp) | smc_mii_ifmedia_upd(if_t ifp) | ||||
{ | { | ||||
struct smc_softc *sc; | struct smc_softc *sc; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
if (sc->smc_miibus == NULL) | if (sc->smc_miibus == NULL) | ||||
return (ENXIO); | return (ENXIO); | ||||
mii = device_get_softc(sc->smc_miibus); | mii = device_get_softc(sc->smc_miibus); | ||||
return (mii_mediachg(mii)); | return (mii_mediachg(mii)); | ||||
} | } | ||||
static void | static void | ||||
smc_mii_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) | smc_mii_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) | ||||
{ | { | ||||
struct smc_softc *sc; | struct smc_softc *sc; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
if (sc->smc_miibus == NULL) | if (sc->smc_miibus == NULL) | ||||
return; | return; | ||||
mii = device_get_softc(sc->smc_miibus); | mii = device_get_softc(sc->smc_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; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | smc_reset(struct smc_softc *sc) | ||||
smc_select_bank(sc, 2); | smc_select_bank(sc, 2); | ||||
smc_mmu_wait(sc); | smc_mmu_wait(sc); | ||||
smc_write_2(sc, MMUCR, MMUCR_CMD_MMU_RESET); | smc_write_2(sc, MMUCR, MMUCR_CMD_MMU_RESET); | ||||
} | } | ||||
static void | static void | ||||
smc_enable(struct smc_softc *sc) | smc_enable(struct smc_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp; | if_t ifp; | ||||
SMC_ASSERT_LOCKED(sc); | SMC_ASSERT_LOCKED(sc); | ||||
ifp = sc->smc_ifp; | ifp = sc->smc_ifp; | ||||
/* | /* | ||||
* Set up the receive/PHY control register. | * Set up the receive/PHY control register. | ||||
*/ | */ | ||||
smc_select_bank(sc, 0); | smc_select_bank(sc, 0); | ||||
smc_write_2(sc, RPCR, RPCR_ANEG | (RPCR_LED_LINK_ANY << RPCR_LSA_SHIFT) | smc_write_2(sc, RPCR, RPCR_ANEG | (RPCR_LED_LINK_ANY << RPCR_LSA_SHIFT) | ||||
| (RPCR_LED_ACT_ANY << RPCR_LSB_SHIFT)); | | (RPCR_LED_ACT_ANY << RPCR_LSB_SHIFT)); | ||||
/* | /* | ||||
* Set up the transmit and receive control registers. | * Set up the transmit and receive control registers. | ||||
*/ | */ | ||||
smc_write_2(sc, TCR, TCR_TXENA | TCR_PAD_EN); | smc_write_2(sc, TCR, TCR_TXENA | TCR_PAD_EN); | ||||
smc_write_2(sc, RCR, RCR_RXEN | RCR_STRIP_CRC); | smc_write_2(sc, RCR, RCR_RXEN | RCR_STRIP_CRC); | ||||
/* | /* | ||||
* Set up the interrupt mask. | * Set up the interrupt mask. | ||||
*/ | */ | ||||
smc_select_bank(sc, 2); | smc_select_bank(sc, 2); | ||||
sc->smc_mask = EPH_INT | RX_OVRN_INT | RCV_INT | TX_INT; | sc->smc_mask = EPH_INT | RX_OVRN_INT | RCV_INT | TX_INT; | ||||
if ((ifp->if_capenable & IFCAP_POLLING) != 0) | if ((if_getcapenable(ifp) & IFCAP_POLLING) != 0) | ||||
smc_write_1(sc, MSK, sc->smc_mask); | smc_write_1(sc, MSK, sc->smc_mask); | ||||
} | } | ||||
static void | static void | ||||
smc_stop(struct smc_softc *sc) | smc_stop(struct smc_softc *sc) | ||||
{ | { | ||||
SMC_ASSERT_LOCKED(sc); | SMC_ASSERT_LOCKED(sc); | ||||
/* | /* | ||||
* Turn off callouts. | * Turn off callouts. | ||||
*/ | */ | ||||
callout_stop(&sc->smc_watchdog); | callout_stop(&sc->smc_watchdog); | ||||
callout_stop(&sc->smc_mii_tick_ch); | callout_stop(&sc->smc_mii_tick_ch); | ||||
/* | /* | ||||
* Mask all interrupts. | * Mask all interrupts. | ||||
*/ | */ | ||||
smc_select_bank(sc, 2); | smc_select_bank(sc, 2); | ||||
sc->smc_mask = 0; | sc->smc_mask = 0; | ||||
smc_write_1(sc, MSK, 0); | smc_write_1(sc, MSK, 0); | ||||
#ifdef DEVICE_POLLING | #ifdef DEVICE_POLLING | ||||
ether_poll_deregister(sc->smc_ifp); | ether_poll_deregister(sc->smc_ifp); | ||||
sc->smc_ifp->if_capenable &= ~IFCAP_POLLING; | if_setcapenablebit(ifp, 0, IFCAP_POLLING); | ||||
#endif | #endif | ||||
/* | /* | ||||
* Disable transmit and receive. | * Disable transmit and receive. | ||||
*/ | */ | ||||
smc_select_bank(sc, 0); | smc_select_bank(sc, 0); | ||||
smc_write_2(sc, TCR, 0); | smc_write_2(sc, TCR, 0); | ||||
smc_write_2(sc, RCR, 0); | smc_write_2(sc, RCR, 0); | ||||
sc->smc_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | if_setdrvflagbits(sc->smc_ifp, 0, IFF_DRV_RUNNING); | ||||
} | } | ||||
static void | static void | ||||
smc_watchdog(void *arg) | smc_watchdog(void *arg) | ||||
{ | { | ||||
struct smc_softc *sc; | struct smc_softc *sc; | ||||
sc = (struct smc_softc *)arg; | sc = (struct smc_softc *)arg; | ||||
Show All 10 Lines | smc_init(void *context) | ||||
SMC_LOCK(sc); | SMC_LOCK(sc); | ||||
smc_init_locked(sc); | smc_init_locked(sc); | ||||
SMC_UNLOCK(sc); | SMC_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
smc_init_locked(struct smc_softc *sc) | smc_init_locked(struct smc_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp; | if_t ifp; | ||||
SMC_ASSERT_LOCKED(sc); | SMC_ASSERT_LOCKED(sc); | ||||
ifp = sc->smc_ifp; | ifp = sc->smc_ifp; | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) | if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) | ||||
return; | return; | ||||
smc_reset(sc); | smc_reset(sc); | ||||
smc_enable(sc); | smc_enable(sc); | ||||
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); | ||||
smc_start_locked(ifp); | smc_start_locked(ifp); | ||||
if (sc->smc_mii_tick != NULL) | if (sc->smc_mii_tick != NULL) | ||||
callout_reset(&sc->smc_mii_tick_ch, hz, sc->smc_mii_tick, sc); | callout_reset(&sc->smc_mii_tick_ch, hz, sc->smc_mii_tick, sc); | ||||
#ifdef DEVICE_POLLING | #ifdef DEVICE_POLLING | ||||
SMC_UNLOCK(sc); | SMC_UNLOCK(sc); | ||||
ether_poll_register(smc_poll, ifp); | ether_poll_register(smc_poll, ifp); | ||||
SMC_LOCK(sc); | SMC_LOCK(sc); | ||||
ifp->if_capenable |= IFCAP_POLLING; | if_setcapenablebit(ifp, IFCAP_POLLING, 0); | ||||
#endif | #endif | ||||
} | } | ||||
static int | static int | ||||
smc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | smc_ioctl(if_t ifp, u_long cmd, caddr_t data) | ||||
{ | { | ||||
struct smc_softc *sc; | struct smc_softc *sc; | ||||
int error; | int error; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
error = 0; | error = 0; | ||||
switch (cmd) { | switch (cmd) { | ||||
case SIOCSIFFLAGS: | case SIOCSIFFLAGS: | ||||
if ((ifp->if_flags & IFF_UP) == 0 && | if ((if_getflags(ifp) & IFF_UP) == 0 && | ||||
(ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { | (if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { | ||||
SMC_LOCK(sc); | SMC_LOCK(sc); | ||||
smc_stop(sc); | smc_stop(sc); | ||||
SMC_UNLOCK(sc); | SMC_UNLOCK(sc); | ||||
} else { | } else { | ||||
smc_init(sc); | smc_init(sc); | ||||
if (sc->smc_mii_mediachg != NULL) | if (sc->smc_mii_mediachg != NULL) | ||||
sc->smc_mii_mediachg(sc); | sc->smc_mii_mediachg(sc); | ||||
} | } | ||||
Show All 28 Lines |