aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/drivers/net/axge.c58
-rw-r--r--src/drivers/net/axge.h3
2 files changed, 39 insertions, 22 deletions
diff --git a/src/drivers/net/axge.c b/src/drivers/net/axge.c
index ab59a8b..1106c1e 100644
--- a/src/drivers/net/axge.c
+++ b/src/drivers/net/axge.c
@@ -213,6 +213,7 @@ static inline int axge_write_dword ( struct axge_device *axge,
static int axge_check_link ( struct axge_device *axge ) {
struct net_device *netdev = axge->netdev;
uint8_t plsr;
+ uint16_t msr;
int rc;
/* Read physical link status register */
@@ -222,12 +223,28 @@ static int axge_check_link ( struct axge_device *axge ) {
return rc;
}
+ /* Write medium status register */
+ msr = cpu_to_le16 ( AXGE_MSR_FD | AXGE_MSR_RFC | AXGE_MSR_TFC |
+ AXGE_MSR_RE );
+ if ( plsr & AXGE_PLSR_EPHY_1000 ) {
+ msr |= cpu_to_le16 ( AXGE_MSR_GM );
+ } else if ( plsr & AXGE_PLSR_EPHY_100 ) {
+ msr |= cpu_to_le16 ( AXGE_MSR_PS );
+ }
+ if ( ( rc = axge_write_word ( axge, AXGE_MSR, msr ) ) != 0 ) {
+ DBGC ( axge, "AXGE %p could not write MSR: %s\n",
+ axge, strerror ( rc ) );
+ return rc;
+ }
+
/* Update link status */
if ( plsr & AXGE_PLSR_EPHY_ANY ) {
- DBGC ( axge, "AXGE %p link up (PLSR %02x)\n", axge, plsr );
+ DBGC ( axge, "AXGE %p link up (PLSR %02x MSR %04x)\n",
+ axge, plsr, msr );
netdev_link_up ( netdev );
} else {
- DBGC ( axge, "AXGE %p link down (PLSR %02x)\n", axge, plsr );
+ DBGC ( axge, "AXGE %p link down (PLSR %02x MSR %04x)\n",
+ axge, plsr, msr );
netdev_link_down ( netdev );
}
@@ -291,13 +308,8 @@ static void axge_intr_complete ( struct usb_endpoint *ep,
/* Extract link status */
link_ok = ( intr->link & cpu_to_le16 ( AXGE_INTR_LINK_PPLS ) );
- if ( link_ok && ! netdev_link_ok ( netdev ) ) {
- DBGC ( axge, "AXGE %p link up\n", axge );
- netdev_link_up ( netdev );
- } else if ( netdev_link_ok ( netdev ) && ! link_ok ) {
- DBGC ( axge, "AXGE %p link down\n", axge );
- netdev_link_down ( netdev );
- }
+ if ( ( !! link_ok ) ^ ( !! netdev_link_ok ( netdev ) ) )
+ axge->check_link = 1;
/* Free I/O buffer */
free_iob ( iobuf );
@@ -544,10 +556,12 @@ static int axge_open ( struct net_device *netdev ) {
}
/* Update link status */
- axge_check_link ( axge );
+ if ( ( rc = axge_check_link ( axge ) ) != 0 )
+ goto err_check_link;
return 0;
+ err_check_link:
axge_write_word ( axge, AXGE_RCR, 0 );
err_write_rcr:
err_write_mac:
@@ -605,6 +619,15 @@ static void axge_poll ( struct net_device *netdev ) {
/* Refill endpoints */
if ( ( rc = usbnet_refill ( &axge->usbnet ) ) != 0 )
netdev_rx_err ( netdev, NULL, rc );
+
+ /* Update link state, if applicable */
+ if ( axge->check_link ) {
+ if ( ( rc = axge_check_link ( axge ) ) == 0 ) {
+ axge->check_link = 0;
+ } else {
+ netdev_rx_err ( netdev, NULL, rc );
+ }
+ }
}
/** AXGE network device operations */
@@ -635,7 +658,6 @@ static int axge_probe ( struct usb_function *func,
struct net_device *netdev;
struct axge_device *axge;
uint16_t epprcr;
- uint16_t msr;
uint8_t csr;
int rc;
@@ -705,28 +727,20 @@ static int axge_probe ( struct usb_function *func,
goto err_write_bicr;
}
- /* Set medium status */
- msr = cpu_to_le16 ( AXGE_MSR_GM | AXGE_MSR_FD | AXGE_MSR_RFC |
- AXGE_MSR_TFC | AXGE_MSR_RE );
- if ( ( rc = axge_write_word ( axge, AXGE_MSR, msr ) ) != 0 ) {
- DBGC ( axge, "AXGE %p could not write MSR: %s\n",
- axge, strerror ( rc ) );
- goto err_write_msr;
- }
-
/* Register network device */
if ( ( rc = register_netdev ( netdev ) ) != 0 )
goto err_register;
/* Update link status */
- axge_check_link ( axge );
+ if ( ( rc = axge_check_link ( axge ) ) != 0 )
+ goto err_check_link;
usb_func_set_drvdata ( func, axge );
return 0;
+ err_check_link:
unregister_netdev ( netdev );
err_register:
- err_write_msr:
err_write_bicr:
err_write_csr:
err_write_epprcr_on:
diff --git a/src/drivers/net/axge.h b/src/drivers/net/axge.h
index 65bf911..6183b4e 100644
--- a/src/drivers/net/axge.h
+++ b/src/drivers/net/axge.h
@@ -49,6 +49,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define AXGE_MSR_RFC 0x0010 /**< RX flow control enable */
#define AXGE_MSR_TFC 0x0020 /**< TX flow control enable */
#define AXGE_MSR_RE 0x0100 /**< Receive enable */
+#define AXGE_MSR_PS 0x0200 /**< 100Mbps port speed */
/** Ethernet PHY Power and Reset Control Register */
#define AXGE_EPPRCR 0x26
@@ -144,6 +145,8 @@ struct axge_device {
struct net_device *netdev;
/** USB network device */
struct usbnet_device usbnet;
+ /** Link state has changed */
+ int check_link;
};
/** Interrupt maximum fill level