summaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2012-12-14 13:08:10 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2012-12-18 11:22:19 +0100
commit2cd48da071950ad73baa3802200449c17b6a0893 (patch)
treea4f5a19a6aef4413800c97dec317b729b3988ecc /c
parentbsps/arm: Prepare for interface down support (diff)
downloadrtems-2cd48da071950ad73baa3802200449c17b6a0893.tar.bz2
bsps/arm: Add interface down support
Diffstat (limited to 'c')
-rw-r--r--c/src/lib/libbsp/arm/lpc24xx/include/lpc-ethernet-config.h5
-rw-r--r--c/src/lib/libbsp/arm/lpc32xx/include/lpc-ethernet-config.h5
-rw-r--r--c/src/lib/libbsp/arm/shared/lpc/network/lpc-ethernet.c138
3 files changed, 105 insertions, 43 deletions
diff --git a/c/src/lib/libbsp/arm/lpc24xx/include/lpc-ethernet-config.h b/c/src/lib/libbsp/arm/lpc24xx/include/lpc-ethernet-config.h
index 8c787b75da..26482bfcda 100644
--- a/c/src/lib/libbsp/arm/lpc24xx/include/lpc-ethernet-config.h
+++ b/c/src/lib/libbsp/arm/lpc24xx/include/lpc-ethernet-config.h
@@ -92,6 +92,11 @@ extern "C" {
}
#endif
+static void lpc_eth_config_module_disable(void)
+{
+ lpc24xx_module_disable(LPC24XX_MODULE_ETHERNET);
+}
+
static char *lpc_eth_config_alloc_table_area(size_t size)
{
if (size < LPC24XX_ETH_RAM_SIZE) {
diff --git a/c/src/lib/libbsp/arm/lpc32xx/include/lpc-ethernet-config.h b/c/src/lib/libbsp/arm/lpc32xx/include/lpc-ethernet-config.h
index 12dbd792f6..3dc1dc0f3c 100644
--- a/c/src/lib/libbsp/arm/lpc32xx/include/lpc-ethernet-config.h
+++ b/c/src/lib/libbsp/arm/lpc32xx/include/lpc-ethernet-config.h
@@ -71,6 +71,11 @@ extern "C" {
}
#endif
+static void lpc_eth_config_module_disable(void)
+{
+ LPC32XX_MAC_CLK_CTRL = 0;
+}
+
#define LPC_ETH_CONFIG_USE_TRANSMIT_DMA
static char *lpc_eth_config_alloc_table_area(size_t size)
diff --git a/c/src/lib/libbsp/arm/shared/lpc/network/lpc-ethernet.c b/c/src/lib/libbsp/arm/shared/lpc/network/lpc-ethernet.c
index df71776d90..fd7effd869 100644
--- a/c/src/lib/libbsp/arm/shared/lpc/network/lpc-ethernet.c
+++ b/c/src/lib/libbsp/arm/shared/lpc/network/lpc-ethernet.c
@@ -253,10 +253,12 @@ static volatile lpc_eth_controller *const lpc_eth =
#define LPC_ETH_EVENT_INITIALIZE RTEMS_EVENT_1
-#define LPC_ETH_EVENT_START RTEMS_EVENT_2
+#define LPC_ETH_EVENT_TXSTART RTEMS_EVENT_2
#define LPC_ETH_EVENT_INTERRUPT RTEMS_EVENT_3
+#define LPC_ETH_EVENT_STOP RTEMS_EVENT_4
+
/* Status */
#define LPC_ETH_INTERRUPT_RECEIVE \
@@ -560,7 +562,9 @@ static void lpc_eth_receive_task(void *arg)
while (true) {
/* Wait for events */
sc = rtems_bsdnet_event_receive(
- LPC_ETH_EVENT_INITIALIZE | LPC_ETH_EVENT_INTERRUPT,
+ LPC_ETH_EVENT_INITIALIZE
+ | LPC_ETH_EVENT_STOP
+ | LPC_ETH_EVENT_INTERRUPT,
RTEMS_EVENT_ANY | RTEMS_WAIT,
RTEMS_NO_TIMEOUT,
&events
@@ -569,6 +573,14 @@ static void lpc_eth_receive_task(void *arg)
LPC_ETH_PRINTF("rx: wake up: 0x%08" PRIx32 "\n", events);
+ /* Stop receiver? */
+ if ((events & LPC_ETH_EVENT_STOP) != 0) {
+ lpc_eth_control_request_complete(e);
+
+ /* Wait for events */
+ continue;
+ }
+
/* Initialize receiver? */
if ((events & LPC_ETH_EVENT_INITIALIZE) != 0) {
/* Disable receive interrupts */
@@ -799,7 +811,8 @@ static void lpc_eth_transmit_task(void *arg)
/* Wait for events */
sc = rtems_bsdnet_event_receive(
LPC_ETH_EVENT_INITIALIZE
- | LPC_ETH_EVENT_START
+ | LPC_ETH_EVENT_STOP
+ | LPC_ETH_EVENT_TXSTART
| LPC_ETH_EVENT_INTERRUPT,
RTEMS_EVENT_ANY | RTEMS_WAIT,
RTEMS_NO_TIMEOUT,
@@ -809,6 +822,14 @@ static void lpc_eth_transmit_task(void *arg)
LPC_ETH_PRINTF("tx: wake up: 0x%08" PRIx32 "\n", events);
+ /* Stop transmitter? */
+ if ((events & LPC_ETH_EVENT_STOP) != 0) {
+ lpc_eth_control_request_complete(e);
+
+ /* Wait for events */
+ continue;
+ }
+
/* Initialize transmitter? */
if ((events & LPC_ETH_EVENT_INITIALIZE) != 0) {
/* Disable transmit interrupts */
@@ -1131,6 +1152,13 @@ static int lpc_eth_mdio_write(
return eno;
}
+static void lpc_eth_soft_reset(void)
+{
+ lpc_eth->command = 0x38;
+ lpc_eth->mac1 = 0xcf00;
+ lpc_eth->mac1 = 0x0;
+}
+
static void lpc_eth_up_or_down(lpc_eth_driver_entry *e, bool up)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
@@ -1139,12 +1167,7 @@ static void lpc_eth_up_or_down(lpc_eth_driver_entry *e, bool up)
if (up && e->state == LPC_ETH_STATE_DOWN) {
lpc_eth_config_module_enable();
- /* Soft reset */
-
- /* Do soft reset */
- lpc_eth->command = 0x38;
- lpc_eth->mac1 = 0xcf00;
- lpc_eth->mac1 = 0x0;
+ lpc_eth_soft_reset();
/* Initialize PHY */
lpc_eth->mcfg = ETH_MCFG_CLOCK_SELECT(0x7);
@@ -1200,7 +1223,26 @@ static void lpc_eth_up_or_down(lpc_eth_driver_entry *e, bool up)
/* Change state */
e->state = LPC_ETH_STATE_UP;
} else if (!up && e->state == LPC_ETH_STATE_UP) {
- /* TODO */
+ /* Remove interrupt handler */
+ sc = rtems_interrupt_handler_remove(
+ e->interrupt_number,
+ lpc_eth_interrupt_handler,
+ e
+ );
+ assert(sc == RTEMS_SUCCESSFUL);
+
+ /* Stop tasks */
+ lpc_eth_control_request(e, e->receive_task, LPC_ETH_EVENT_STOP);
+ lpc_eth_control_request(e, e->transmit_task, LPC_ETH_EVENT_STOP);
+
+ lpc_eth_soft_reset();
+ lpc_eth_config_module_disable();
+
+ /* Stop watchdog timer */
+ ifp->if_timer = 0;
+
+ /* Change state */
+ e->state = LPC_ETH_STATE_DOWN;
}
}
@@ -1211,8 +1253,13 @@ static void lpc_eth_interface_init(void *arg)
static void lpc_eth_interface_stats(lpc_eth_driver_entry *e)
{
- int media = IFM_MAKEWORD(0, 0, 0, 0);
- int eno = rtems_mii_ioctl(&e->mdio, e, SIOCGIFMEDIA, &media);
+ int eno = EIO;
+ int media = 0;
+
+ if (e->state == LPC_ETH_STATE_UP) {
+ media = IFM_MAKEWORD(0, 0, 0, 0);
+ eno = rtems_mii_ioctl(&e->mdio, e, SIOCGIFMEDIA, &media);
+ }
rtems_bsdnet_semaphore_release();
@@ -1340,46 +1387,51 @@ static void lpc_eth_interface_start(struct ifnet *ifp)
ifp->if_flags |= IFF_OACTIVE;
- sc = rtems_bsdnet_event_send(e->transmit_task, LPC_ETH_EVENT_START);
- assert(sc == RTEMS_SUCCESSFUL);
+ if (e->state == LPC_ETH_STATE_UP) {
+ sc = rtems_bsdnet_event_send(e->transmit_task, LPC_ETH_EVENT_TXSTART);
+ assert(sc == RTEMS_SUCCESSFUL);
+ }
}
static void lpc_eth_interface_watchdog(struct ifnet *ifp)
{
lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) ifp->if_softc;
- uint32_t anlpar = lpc_eth_mdio_read_anlpar();
-
- if (e->anlpar != anlpar) {
- bool full_duplex = false;
- bool speed = false;
-
- e->anlpar = anlpar;
-
- if ((anlpar & ANLPAR_TX_FD) != 0) {
- full_duplex = true;
- speed = true;
- } else if ((anlpar & ANLPAR_T4) != 0) {
- speed = true;
- } else if ((anlpar & ANLPAR_TX) != 0) {
- speed = true;
- } else if ((anlpar & ANLPAR_10_FD) != 0) {
- full_duplex = true;
- }
- if (full_duplex) {
- lpc_eth->mac2 |= ETH_MAC2_FULL_DUPLEX;
- } else {
- lpc_eth->mac2 &= ~ETH_MAC2_FULL_DUPLEX;
- }
+ if (e->state == LPC_ETH_STATE_UP) {
+ uint32_t anlpar = lpc_eth_mdio_read_anlpar();
- if (speed) {
- lpc_eth->supp |= ETH_SUPP_SPEED;
- } else {
- lpc_eth->supp &= ~ETH_SUPP_SPEED;
+ if (e->anlpar != anlpar) {
+ bool full_duplex = false;
+ bool speed = false;
+
+ e->anlpar = anlpar;
+
+ if ((anlpar & ANLPAR_TX_FD) != 0) {
+ full_duplex = true;
+ speed = true;
+ } else if ((anlpar & ANLPAR_T4) != 0) {
+ speed = true;
+ } else if ((anlpar & ANLPAR_TX) != 0) {
+ speed = true;
+ } else if ((anlpar & ANLPAR_10_FD) != 0) {
+ full_duplex = true;
+ }
+
+ if (full_duplex) {
+ lpc_eth->mac2 |= ETH_MAC2_FULL_DUPLEX;
+ } else {
+ lpc_eth->mac2 &= ~ETH_MAC2_FULL_DUPLEX;
+ }
+
+ if (speed) {
+ lpc_eth->supp |= ETH_SUPP_SPEED;
+ } else {
+ lpc_eth->supp &= ~ETH_SUPP_SPEED;
+ }
}
- }
- ifp->if_timer = WATCHDOG_TIMEOUT;
+ ifp->if_timer = WATCHDOG_TIMEOUT;
+ }
}
static unsigned lpc_eth_fixup_unit_count(int count, int default_value, int max)