|
@@ -119,6 +119,7 @@
|
|
#include <linux/kmod.h>
|
|
#include <linux/kmod.h>
|
|
#include <linux/mdio.h>
|
|
#include <linux/mdio.h>
|
|
#include <linux/phy.h>
|
|
#include <linux/phy.h>
|
|
|
|
+#include <linux/ethtool.h>
|
|
|
|
|
|
#include "xgbe.h"
|
|
#include "xgbe.h"
|
|
#include "xgbe-common.h"
|
|
#include "xgbe-common.h"
|
|
@@ -270,6 +271,15 @@ struct xgbe_sfp_eeprom {
|
|
u8 vendor[32];
|
|
u8 vendor[32];
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+#define XGBE_SFP_DIAGS_SUPPORTED(_x) \
|
|
|
|
+ ((_x)->extd[XGBE_SFP_EXTD_SFF_8472] && \
|
|
|
|
+ !((_x)->extd[XGBE_SFP_EXTD_DIAG] & XGBE_SFP_EXTD_DIAG_ADDR_CHANGE))
|
|
|
|
+
|
|
|
|
+#define XGBE_SFP_EEPROM_BASE_LEN 256
|
|
|
|
+#define XGBE_SFP_EEPROM_DIAG_LEN 256
|
|
|
|
+#define XGBE_SFP_EEPROM_MAX (XGBE_SFP_EEPROM_BASE_LEN + \
|
|
|
|
+ XGBE_SFP_EEPROM_DIAG_LEN)
|
|
|
|
+
|
|
#define XGBE_BEL_FUSE_VENDOR "BEL-FUSE "
|
|
#define XGBE_BEL_FUSE_VENDOR "BEL-FUSE "
|
|
#define XGBE_BEL_FUSE_PARTNO "1GBT-SFP06 "
|
|
#define XGBE_BEL_FUSE_PARTNO "1GBT-SFP06 "
|
|
|
|
|
|
@@ -327,8 +337,6 @@ struct xgbe_phy_data {
|
|
|
|
|
|
unsigned int mdio_addr;
|
|
unsigned int mdio_addr;
|
|
|
|
|
|
- unsigned int comm_owned;
|
|
|
|
-
|
|
|
|
/* SFP Support */
|
|
/* SFP Support */
|
|
enum xgbe_sfp_comm sfp_comm;
|
|
enum xgbe_sfp_comm sfp_comm;
|
|
unsigned int sfp_mux_address;
|
|
unsigned int sfp_mux_address;
|
|
@@ -345,7 +353,6 @@ struct xgbe_phy_data {
|
|
unsigned int sfp_rx_los;
|
|
unsigned int sfp_rx_los;
|
|
unsigned int sfp_tx_fault;
|
|
unsigned int sfp_tx_fault;
|
|
unsigned int sfp_mod_absent;
|
|
unsigned int sfp_mod_absent;
|
|
- unsigned int sfp_diags;
|
|
|
|
unsigned int sfp_changed;
|
|
unsigned int sfp_changed;
|
|
unsigned int sfp_phy_avail;
|
|
unsigned int sfp_phy_avail;
|
|
unsigned int sfp_cable_len;
|
|
unsigned int sfp_cable_len;
|
|
@@ -382,12 +389,6 @@ static enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata);
|
|
static int xgbe_phy_i2c_xfer(struct xgbe_prv_data *pdata,
|
|
static int xgbe_phy_i2c_xfer(struct xgbe_prv_data *pdata,
|
|
struct xgbe_i2c_op *i2c_op)
|
|
struct xgbe_i2c_op *i2c_op)
|
|
{
|
|
{
|
|
- struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
|
|
-
|
|
|
|
- /* Be sure we own the bus */
|
|
|
|
- if (WARN_ON(!phy_data->comm_owned))
|
|
|
|
- return -EIO;
|
|
|
|
-
|
|
|
|
return pdata->i2c_if.i2c_xfer(pdata, i2c_op);
|
|
return pdata->i2c_if.i2c_xfer(pdata, i2c_op);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -549,10 +550,6 @@ static int xgbe_phy_sfp_get_mux(struct xgbe_prv_data *pdata)
|
|
|
|
|
|
static void xgbe_phy_put_comm_ownership(struct xgbe_prv_data *pdata)
|
|
static void xgbe_phy_put_comm_ownership(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
- struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
|
|
-
|
|
|
|
- phy_data->comm_owned = 0;
|
|
|
|
-
|
|
|
|
mutex_unlock(&xgbe_phy_comm_lock);
|
|
mutex_unlock(&xgbe_phy_comm_lock);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -562,9 +559,6 @@ static int xgbe_phy_get_comm_ownership(struct xgbe_prv_data *pdata)
|
|
unsigned long timeout;
|
|
unsigned long timeout;
|
|
unsigned int mutex_id;
|
|
unsigned int mutex_id;
|
|
|
|
|
|
- if (phy_data->comm_owned)
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
/* The I2C and MDIO/GPIO bus is multiplexed between multiple devices,
|
|
/* The I2C and MDIO/GPIO bus is multiplexed between multiple devices,
|
|
* the driver needs to take the software mutex and then the hardware
|
|
* the driver needs to take the software mutex and then the hardware
|
|
* mutexes before being able to use the busses.
|
|
* mutexes before being able to use the busses.
|
|
@@ -593,7 +587,6 @@ static int xgbe_phy_get_comm_ownership(struct xgbe_prv_data *pdata)
|
|
XP_IOWRITE(pdata, XP_I2C_MUTEX, mutex_id);
|
|
XP_IOWRITE(pdata, XP_I2C_MUTEX, mutex_id);
|
|
XP_IOWRITE(pdata, XP_MDIO_MUTEX, mutex_id);
|
|
XP_IOWRITE(pdata, XP_MDIO_MUTEX, mutex_id);
|
|
|
|
|
|
- phy_data->comm_owned = 1;
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -867,6 +860,9 @@ static bool xgbe_phy_finisar_phy_quirks(struct xgbe_prv_data *pdata)
|
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
unsigned int phy_id = phy_data->phydev->phy_id;
|
|
unsigned int phy_id = phy_data->phydev->phy_id;
|
|
|
|
|
|
|
|
+ if (phy_data->port_mode != XGBE_PORT_MODE_SFP)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
if ((phy_id & 0xfffffff0) != 0x01ff0cc0)
|
|
if ((phy_id & 0xfffffff0) != 0x01ff0cc0)
|
|
return false;
|
|
return false;
|
|
|
|
|
|
@@ -892,8 +888,83 @@ static bool xgbe_phy_finisar_phy_quirks(struct xgbe_prv_data *pdata)
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool xgbe_phy_belfuse_phy_quirks(struct xgbe_prv_data *pdata)
|
|
|
|
+{
|
|
|
|
+ struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
|
|
+ struct xgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom;
|
|
|
|
+ unsigned int phy_id = phy_data->phydev->phy_id;
|
|
|
|
+ int reg;
|
|
|
|
+
|
|
|
|
+ if (phy_data->port_mode != XGBE_PORT_MODE_SFP)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME],
|
|
|
|
+ XGBE_BEL_FUSE_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN))
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ /* For Bel-Fuse, use the extra AN flag */
|
|
|
|
+ pdata->an_again = 1;
|
|
|
|
+
|
|
|
|
+ if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN],
|
|
|
|
+ XGBE_BEL_FUSE_PARTNO, XGBE_SFP_BASE_VENDOR_PN_LEN))
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ if ((phy_id & 0xfffffff0) != 0x03625d10)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ /* Disable RGMII mode */
|
|
|
|
+ phy_write(phy_data->phydev, 0x18, 0x7007);
|
|
|
|
+ reg = phy_read(phy_data->phydev, 0x18);
|
|
|
|
+ phy_write(phy_data->phydev, 0x18, reg & ~0x0080);
|
|
|
|
+
|
|
|
|
+ /* Enable fiber register bank */
|
|
|
|
+ phy_write(phy_data->phydev, 0x1c, 0x7c00);
|
|
|
|
+ reg = phy_read(phy_data->phydev, 0x1c);
|
|
|
|
+ reg &= 0x03ff;
|
|
|
|
+ reg &= ~0x0001;
|
|
|
|
+ phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg | 0x0001);
|
|
|
|
+
|
|
|
|
+ /* Power down SerDes */
|
|
|
|
+ reg = phy_read(phy_data->phydev, 0x00);
|
|
|
|
+ phy_write(phy_data->phydev, 0x00, reg | 0x00800);
|
|
|
|
+
|
|
|
|
+ /* Configure SGMII-to-Copper mode */
|
|
|
|
+ phy_write(phy_data->phydev, 0x1c, 0x7c00);
|
|
|
|
+ reg = phy_read(phy_data->phydev, 0x1c);
|
|
|
|
+ reg &= 0x03ff;
|
|
|
|
+ reg &= ~0x0006;
|
|
|
|
+ phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg | 0x0004);
|
|
|
|
+
|
|
|
|
+ /* Power up SerDes */
|
|
|
|
+ reg = phy_read(phy_data->phydev, 0x00);
|
|
|
|
+ phy_write(phy_data->phydev, 0x00, reg & ~0x00800);
|
|
|
|
+
|
|
|
|
+ /* Enable copper register bank */
|
|
|
|
+ phy_write(phy_data->phydev, 0x1c, 0x7c00);
|
|
|
|
+ reg = phy_read(phy_data->phydev, 0x1c);
|
|
|
|
+ reg &= 0x03ff;
|
|
|
|
+ reg &= ~0x0001;
|
|
|
|
+ phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg);
|
|
|
|
+
|
|
|
|
+ /* Power up SerDes */
|
|
|
|
+ reg = phy_read(phy_data->phydev, 0x00);
|
|
|
|
+ phy_write(phy_data->phydev, 0x00, reg & ~0x00800);
|
|
|
|
+
|
|
|
|
+ phy_data->phydev->supported = PHY_GBIT_FEATURES;
|
|
|
|
+ phy_data->phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
|
|
|
+ phy_data->phydev->advertising = phy_data->phydev->supported;
|
|
|
|
+
|
|
|
|
+ netif_dbg(pdata, drv, pdata->netdev,
|
|
|
|
+ "BelFuse PHY quirk in place\n");
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
static void xgbe_phy_external_phy_quirks(struct xgbe_prv_data *pdata)
|
|
static void xgbe_phy_external_phy_quirks(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
|
|
+ if (xgbe_phy_belfuse_phy_quirks(pdata))
|
|
|
|
+ return;
|
|
|
|
+
|
|
if (xgbe_phy_finisar_phy_quirks(pdata))
|
|
if (xgbe_phy_finisar_phy_quirks(pdata))
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
@@ -910,6 +981,9 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata)
|
|
if (phy_data->phydev)
|
|
if (phy_data->phydev)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+ /* Clear the extra AN flag */
|
|
|
|
+ pdata->an_again = 0;
|
|
|
|
+
|
|
/* Check for the use of an external PHY */
|
|
/* Check for the use of an external PHY */
|
|
if (phy_data->phydev_mode == XGBE_MDIO_MODE_NONE)
|
|
if (phy_data->phydev_mode == XGBE_MDIO_MODE_NONE)
|
|
return 0;
|
|
return 0;
|
|
@@ -1034,37 +1108,6 @@ static bool xgbe_phy_check_sfp_mod_absent(struct xgbe_phy_data *phy_data)
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
-static bool xgbe_phy_belfuse_parse_quirks(struct xgbe_prv_data *pdata)
|
|
|
|
-{
|
|
|
|
- struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
|
|
- struct xgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom;
|
|
|
|
-
|
|
|
|
- if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME],
|
|
|
|
- XGBE_BEL_FUSE_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN))
|
|
|
|
- return false;
|
|
|
|
-
|
|
|
|
- if (!memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN],
|
|
|
|
- XGBE_BEL_FUSE_PARTNO, XGBE_SFP_BASE_VENDOR_PN_LEN)) {
|
|
|
|
- phy_data->sfp_base = XGBE_SFP_BASE_1000_SX;
|
|
|
|
- phy_data->sfp_cable = XGBE_SFP_CABLE_ACTIVE;
|
|
|
|
- phy_data->sfp_speed = XGBE_SFP_SPEED_1000;
|
|
|
|
- if (phy_data->sfp_changed)
|
|
|
|
- netif_dbg(pdata, drv, pdata->netdev,
|
|
|
|
- "Bel-Fuse SFP quirk in place\n");
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return false;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static bool xgbe_phy_sfp_parse_quirks(struct xgbe_prv_data *pdata)
|
|
|
|
-{
|
|
|
|
- if (xgbe_phy_belfuse_parse_quirks(pdata))
|
|
|
|
- return true;
|
|
|
|
-
|
|
|
|
- return false;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
|
|
static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
@@ -1083,9 +1126,6 @@ static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
|
|
phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data);
|
|
phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data);
|
|
phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data);
|
|
phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data);
|
|
|
|
|
|
- if (xgbe_phy_sfp_parse_quirks(pdata))
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
/* Assume ACTIVE cable unless told it is PASSIVE */
|
|
/* Assume ACTIVE cable unless told it is PASSIVE */
|
|
if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_PASSIVE) {
|
|
if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_PASSIVE) {
|
|
phy_data->sfp_cable = XGBE_SFP_CABLE_PASSIVE;
|
|
phy_data->sfp_cable = XGBE_SFP_CABLE_PASSIVE;
|
|
@@ -1227,13 +1267,6 @@ static int xgbe_phy_sfp_read_eeprom(struct xgbe_prv_data *pdata)
|
|
|
|
|
|
memcpy(&phy_data->sfp_eeprom, &sfp_eeprom, sizeof(sfp_eeprom));
|
|
memcpy(&phy_data->sfp_eeprom, &sfp_eeprom, sizeof(sfp_eeprom));
|
|
|
|
|
|
- if (sfp_eeprom.extd[XGBE_SFP_EXTD_SFF_8472]) {
|
|
|
|
- u8 diag_type = sfp_eeprom.extd[XGBE_SFP_EXTD_DIAG];
|
|
|
|
-
|
|
|
|
- if (!(diag_type & XGBE_SFP_EXTD_DIAG_ADDR_CHANGE))
|
|
|
|
- phy_data->sfp_diags = 1;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
xgbe_phy_free_phy_device(pdata);
|
|
xgbe_phy_free_phy_device(pdata);
|
|
} else {
|
|
} else {
|
|
phy_data->sfp_changed = 0;
|
|
phy_data->sfp_changed = 0;
|
|
@@ -1283,7 +1316,6 @@ static void xgbe_phy_sfp_reset(struct xgbe_phy_data *phy_data)
|
|
phy_data->sfp_rx_los = 0;
|
|
phy_data->sfp_rx_los = 0;
|
|
phy_data->sfp_tx_fault = 0;
|
|
phy_data->sfp_tx_fault = 0;
|
|
phy_data->sfp_mod_absent = 1;
|
|
phy_data->sfp_mod_absent = 1;
|
|
- phy_data->sfp_diags = 0;
|
|
|
|
phy_data->sfp_base = XGBE_SFP_BASE_UNKNOWN;
|
|
phy_data->sfp_base = XGBE_SFP_BASE_UNKNOWN;
|
|
phy_data->sfp_cable = XGBE_SFP_CABLE_UNKNOWN;
|
|
phy_data->sfp_cable = XGBE_SFP_CABLE_UNKNOWN;
|
|
phy_data->sfp_speed = XGBE_SFP_SPEED_UNKNOWN;
|
|
phy_data->sfp_speed = XGBE_SFP_SPEED_UNKNOWN;
|
|
@@ -1326,6 +1358,130 @@ put:
|
|
xgbe_phy_put_comm_ownership(pdata);
|
|
xgbe_phy_put_comm_ownership(pdata);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int xgbe_phy_module_eeprom(struct xgbe_prv_data *pdata,
|
|
|
|
+ struct ethtool_eeprom *eeprom, u8 *data)
|
|
|
|
+{
|
|
|
|
+ struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
|
|
+ u8 eeprom_addr, eeprom_data[XGBE_SFP_EEPROM_MAX];
|
|
|
|
+ struct xgbe_sfp_eeprom *sfp_eeprom;
|
|
|
|
+ unsigned int i, j, rem;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ rem = eeprom->len;
|
|
|
|
+
|
|
|
|
+ if (!eeprom->len) {
|
|
|
|
+ ret = -EINVAL;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ((eeprom->offset + eeprom->len) > XGBE_SFP_EEPROM_MAX) {
|
|
|
|
+ ret = -EINVAL;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (phy_data->port_mode != XGBE_PORT_MODE_SFP) {
|
|
|
|
+ ret = -ENXIO;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!netif_running(pdata->netdev)) {
|
|
|
|
+ ret = -EIO;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (phy_data->sfp_mod_absent) {
|
|
|
|
+ ret = -EIO;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = xgbe_phy_get_comm_ownership(pdata);
|
|
|
|
+ if (ret) {
|
|
|
|
+ ret = -EIO;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = xgbe_phy_sfp_get_mux(pdata);
|
|
|
|
+ if (ret) {
|
|
|
|
+ netdev_err(pdata->netdev, "I2C error setting SFP MUX\n");
|
|
|
|
+ ret = -EIO;
|
|
|
|
+ goto put_own;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Read the SFP serial ID eeprom */
|
|
|
|
+ eeprom_addr = 0;
|
|
|
|
+ ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_SERIAL_ID_ADDRESS,
|
|
|
|
+ &eeprom_addr, sizeof(eeprom_addr),
|
|
|
|
+ eeprom_data, XGBE_SFP_EEPROM_BASE_LEN);
|
|
|
|
+ if (ret) {
|
|
|
|
+ netdev_err(pdata->netdev,
|
|
|
|
+ "I2C error reading SFP EEPROM\n");
|
|
|
|
+ ret = -EIO;
|
|
|
|
+ goto put_mux;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ sfp_eeprom = (struct xgbe_sfp_eeprom *)eeprom_data;
|
|
|
|
+
|
|
|
|
+ if (XGBE_SFP_DIAGS_SUPPORTED(sfp_eeprom)) {
|
|
|
|
+ /* Read the SFP diagnostic eeprom */
|
|
|
|
+ eeprom_addr = 0;
|
|
|
|
+ ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_DIAG_INFO_ADDRESS,
|
|
|
|
+ &eeprom_addr, sizeof(eeprom_addr),
|
|
|
|
+ eeprom_data + XGBE_SFP_EEPROM_BASE_LEN,
|
|
|
|
+ XGBE_SFP_EEPROM_DIAG_LEN);
|
|
|
|
+ if (ret) {
|
|
|
|
+ netdev_err(pdata->netdev,
|
|
|
|
+ "I2C error reading SFP DIAGS\n");
|
|
|
|
+ ret = -EIO;
|
|
|
|
+ goto put_mux;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (i = 0, j = eeprom->offset; i < eeprom->len; i++, j++) {
|
|
|
|
+ if ((j >= XGBE_SFP_EEPROM_BASE_LEN) &&
|
|
|
|
+ !XGBE_SFP_DIAGS_SUPPORTED(sfp_eeprom))
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ data[i] = eeprom_data[j];
|
|
|
|
+ rem--;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+put_mux:
|
|
|
|
+ xgbe_phy_sfp_put_mux(pdata);
|
|
|
|
+
|
|
|
|
+put_own:
|
|
|
|
+ xgbe_phy_put_comm_ownership(pdata);
|
|
|
|
+
|
|
|
|
+done:
|
|
|
|
+ eeprom->len -= rem;
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int xgbe_phy_module_info(struct xgbe_prv_data *pdata,
|
|
|
|
+ struct ethtool_modinfo *modinfo)
|
|
|
|
+{
|
|
|
|
+ struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
|
|
+
|
|
|
|
+ if (phy_data->port_mode != XGBE_PORT_MODE_SFP)
|
|
|
|
+ return -ENXIO;
|
|
|
|
+
|
|
|
|
+ if (!netif_running(pdata->netdev))
|
|
|
|
+ return -EIO;
|
|
|
|
+
|
|
|
|
+ if (phy_data->sfp_mod_absent)
|
|
|
|
+ return -EIO;
|
|
|
|
+
|
|
|
|
+ if (XGBE_SFP_DIAGS_SUPPORTED(&phy_data->sfp_eeprom)) {
|
|
|
|
+ modinfo->type = ETH_MODULE_SFF_8472;
|
|
|
|
+ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
|
|
|
|
+ } else {
|
|
|
|
+ modinfo->type = ETH_MODULE_SFF_8079;
|
|
|
|
+ modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata)
|
|
static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
|
|
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
|
|
@@ -1611,6 +1767,10 @@ static void xgbe_phy_an_advertising(struct xgbe_prv_data *pdata,
|
|
XGBE_CLR_ADV(dlks, 1000baseKX_Full);
|
|
XGBE_CLR_ADV(dlks, 1000baseKX_Full);
|
|
XGBE_CLR_ADV(dlks, 10000baseKR_Full);
|
|
XGBE_CLR_ADV(dlks, 10000baseKR_Full);
|
|
|
|
|
|
|
|
+ /* Advertise FEC support is present */
|
|
|
|
+ if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
|
|
|
|
+ XGBE_SET_ADV(dlks, 10000baseR_FEC);
|
|
|
|
+
|
|
switch (phy_data->port_mode) {
|
|
switch (phy_data->port_mode) {
|
|
case XGBE_PORT_MODE_BACKPLANE:
|
|
case XGBE_PORT_MODE_BACKPLANE:
|
|
XGBE_SET_ADV(dlks, 10000baseKR_Full);
|
|
XGBE_SET_ADV(dlks, 10000baseKR_Full);
|
|
@@ -2421,22 +2581,21 @@ static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart)
|
|
static void xgbe_phy_sfp_gpio_setup(struct xgbe_prv_data *pdata)
|
|
static void xgbe_phy_sfp_gpio_setup(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
- unsigned int reg;
|
|
|
|
-
|
|
|
|
- reg = XP_IOREAD(pdata, XP_PROP_3);
|
|
|
|
|
|
|
|
phy_data->sfp_gpio_address = XGBE_GPIO_ADDRESS_PCA9555 +
|
|
phy_data->sfp_gpio_address = XGBE_GPIO_ADDRESS_PCA9555 +
|
|
- XP_GET_BITS(reg, XP_PROP_3, GPIO_ADDR);
|
|
|
|
|
|
+ XP_GET_BITS(pdata->pp3, XP_PROP_3,
|
|
|
|
+ GPIO_ADDR);
|
|
|
|
|
|
- phy_data->sfp_gpio_mask = XP_GET_BITS(reg, XP_PROP_3, GPIO_MASK);
|
|
|
|
|
|
+ phy_data->sfp_gpio_mask = XP_GET_BITS(pdata->pp3, XP_PROP_3,
|
|
|
|
+ GPIO_MASK);
|
|
|
|
|
|
- phy_data->sfp_gpio_rx_los = XP_GET_BITS(reg, XP_PROP_3,
|
|
|
|
|
|
+ phy_data->sfp_gpio_rx_los = XP_GET_BITS(pdata->pp3, XP_PROP_3,
|
|
GPIO_RX_LOS);
|
|
GPIO_RX_LOS);
|
|
- phy_data->sfp_gpio_tx_fault = XP_GET_BITS(reg, XP_PROP_3,
|
|
|
|
|
|
+ phy_data->sfp_gpio_tx_fault = XP_GET_BITS(pdata->pp3, XP_PROP_3,
|
|
GPIO_TX_FAULT);
|
|
GPIO_TX_FAULT);
|
|
- phy_data->sfp_gpio_mod_absent = XP_GET_BITS(reg, XP_PROP_3,
|
|
|
|
|
|
+ phy_data->sfp_gpio_mod_absent = XP_GET_BITS(pdata->pp3, XP_PROP_3,
|
|
GPIO_MOD_ABS);
|
|
GPIO_MOD_ABS);
|
|
- phy_data->sfp_gpio_rate_select = XP_GET_BITS(reg, XP_PROP_3,
|
|
|
|
|
|
+ phy_data->sfp_gpio_rate_select = XP_GET_BITS(pdata->pp3, XP_PROP_3,
|
|
GPIO_RATE_SELECT);
|
|
GPIO_RATE_SELECT);
|
|
|
|
|
|
if (netif_msg_probe(pdata)) {
|
|
if (netif_msg_probe(pdata)) {
|
|
@@ -2458,18 +2617,17 @@ static void xgbe_phy_sfp_gpio_setup(struct xgbe_prv_data *pdata)
|
|
static void xgbe_phy_sfp_comm_setup(struct xgbe_prv_data *pdata)
|
|
static void xgbe_phy_sfp_comm_setup(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
- unsigned int reg, mux_addr_hi, mux_addr_lo;
|
|
|
|
|
|
+ unsigned int mux_addr_hi, mux_addr_lo;
|
|
|
|
|
|
- reg = XP_IOREAD(pdata, XP_PROP_4);
|
|
|
|
-
|
|
|
|
- mux_addr_hi = XP_GET_BITS(reg, XP_PROP_4, MUX_ADDR_HI);
|
|
|
|
- mux_addr_lo = XP_GET_BITS(reg, XP_PROP_4, MUX_ADDR_LO);
|
|
|
|
|
|
+ mux_addr_hi = XP_GET_BITS(pdata->pp4, XP_PROP_4, MUX_ADDR_HI);
|
|
|
|
+ mux_addr_lo = XP_GET_BITS(pdata->pp4, XP_PROP_4, MUX_ADDR_LO);
|
|
if (mux_addr_lo == XGBE_SFP_DIRECT)
|
|
if (mux_addr_lo == XGBE_SFP_DIRECT)
|
|
return;
|
|
return;
|
|
|
|
|
|
phy_data->sfp_comm = XGBE_SFP_COMM_PCA9545;
|
|
phy_data->sfp_comm = XGBE_SFP_COMM_PCA9545;
|
|
phy_data->sfp_mux_address = (mux_addr_hi << 2) + mux_addr_lo;
|
|
phy_data->sfp_mux_address = (mux_addr_hi << 2) + mux_addr_lo;
|
|
- phy_data->sfp_mux_channel = XP_GET_BITS(reg, XP_PROP_4, MUX_CHAN);
|
|
|
|
|
|
+ phy_data->sfp_mux_channel = XP_GET_BITS(pdata->pp4, XP_PROP_4,
|
|
|
|
+ MUX_CHAN);
|
|
|
|
|
|
if (netif_msg_probe(pdata)) {
|
|
if (netif_msg_probe(pdata)) {
|
|
dev_dbg(pdata->dev, "SFP: mux_address=%#x\n",
|
|
dev_dbg(pdata->dev, "SFP: mux_address=%#x\n",
|
|
@@ -2592,13 +2750,11 @@ static bool xgbe_phy_redrv_error(struct xgbe_phy_data *phy_data)
|
|
static int xgbe_phy_mdio_reset_setup(struct xgbe_prv_data *pdata)
|
|
static int xgbe_phy_mdio_reset_setup(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
|
- unsigned int reg;
|
|
|
|
|
|
|
|
if (phy_data->conn_type != XGBE_CONN_TYPE_MDIO)
|
|
if (phy_data->conn_type != XGBE_CONN_TYPE_MDIO)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- reg = XP_IOREAD(pdata, XP_PROP_3);
|
|
|
|
- phy_data->mdio_reset = XP_GET_BITS(reg, XP_PROP_3, MDIO_RESET);
|
|
|
|
|
|
+ phy_data->mdio_reset = XP_GET_BITS(pdata->pp3, XP_PROP_3, MDIO_RESET);
|
|
switch (phy_data->mdio_reset) {
|
|
switch (phy_data->mdio_reset) {
|
|
case XGBE_MDIO_RESET_NONE:
|
|
case XGBE_MDIO_RESET_NONE:
|
|
case XGBE_MDIO_RESET_I2C_GPIO:
|
|
case XGBE_MDIO_RESET_I2C_GPIO:
|
|
@@ -2612,12 +2768,12 @@ static int xgbe_phy_mdio_reset_setup(struct xgbe_prv_data *pdata)
|
|
|
|
|
|
if (phy_data->mdio_reset == XGBE_MDIO_RESET_I2C_GPIO) {
|
|
if (phy_data->mdio_reset == XGBE_MDIO_RESET_I2C_GPIO) {
|
|
phy_data->mdio_reset_addr = XGBE_GPIO_ADDRESS_PCA9555 +
|
|
phy_data->mdio_reset_addr = XGBE_GPIO_ADDRESS_PCA9555 +
|
|
- XP_GET_BITS(reg, XP_PROP_3,
|
|
|
|
|
|
+ XP_GET_BITS(pdata->pp3, XP_PROP_3,
|
|
MDIO_RESET_I2C_ADDR);
|
|
MDIO_RESET_I2C_ADDR);
|
|
- phy_data->mdio_reset_gpio = XP_GET_BITS(reg, XP_PROP_3,
|
|
|
|
|
|
+ phy_data->mdio_reset_gpio = XP_GET_BITS(pdata->pp3, XP_PROP_3,
|
|
MDIO_RESET_I2C_GPIO);
|
|
MDIO_RESET_I2C_GPIO);
|
|
} else if (phy_data->mdio_reset == XGBE_MDIO_RESET_INT_GPIO) {
|
|
} else if (phy_data->mdio_reset == XGBE_MDIO_RESET_INT_GPIO) {
|
|
- phy_data->mdio_reset_gpio = XP_GET_BITS(reg, XP_PROP_3,
|
|
|
|
|
|
+ phy_data->mdio_reset_gpio = XP_GET_BITS(pdata->pp3, XP_PROP_3,
|
|
MDIO_RESET_INT_GPIO);
|
|
MDIO_RESET_INT_GPIO);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2707,12 +2863,9 @@ static bool xgbe_phy_conn_type_mismatch(struct xgbe_prv_data *pdata)
|
|
|
|
|
|
static bool xgbe_phy_port_enabled(struct xgbe_prv_data *pdata)
|
|
static bool xgbe_phy_port_enabled(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
- unsigned int reg;
|
|
|
|
-
|
|
|
|
- reg = XP_IOREAD(pdata, XP_PROP_0);
|
|
|
|
- if (!XP_GET_BITS(reg, XP_PROP_0, PORT_SPEEDS))
|
|
|
|
|
|
+ if (!XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_SPEEDS))
|
|
return false;
|
|
return false;
|
|
- if (!XP_GET_BITS(reg, XP_PROP_0, CONN_TYPE))
|
|
|
|
|
|
+ if (!XP_GET_BITS(pdata->pp0, XP_PROP_0, CONN_TYPE))
|
|
return false;
|
|
return false;
|
|
|
|
|
|
return true;
|
|
return true;
|
|
@@ -2921,7 +3074,6 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
|
|
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
|
|
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
|
|
struct xgbe_phy_data *phy_data;
|
|
struct xgbe_phy_data *phy_data;
|
|
struct mii_bus *mii;
|
|
struct mii_bus *mii;
|
|
- unsigned int reg;
|
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
/* Check if enabled */
|
|
/* Check if enabled */
|
|
@@ -2940,12 +3092,11 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
pdata->phy_data = phy_data;
|
|
pdata->phy_data = phy_data;
|
|
|
|
|
|
- reg = XP_IOREAD(pdata, XP_PROP_0);
|
|
|
|
- phy_data->port_mode = XP_GET_BITS(reg, XP_PROP_0, PORT_MODE);
|
|
|
|
- phy_data->port_id = XP_GET_BITS(reg, XP_PROP_0, PORT_ID);
|
|
|
|
- phy_data->port_speeds = XP_GET_BITS(reg, XP_PROP_0, PORT_SPEEDS);
|
|
|
|
- phy_data->conn_type = XP_GET_BITS(reg, XP_PROP_0, CONN_TYPE);
|
|
|
|
- phy_data->mdio_addr = XP_GET_BITS(reg, XP_PROP_0, MDIO_ADDR);
|
|
|
|
|
|
+ phy_data->port_mode = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_MODE);
|
|
|
|
+ phy_data->port_id = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_ID);
|
|
|
|
+ phy_data->port_speeds = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_SPEEDS);
|
|
|
|
+ phy_data->conn_type = XP_GET_BITS(pdata->pp0, XP_PROP_0, CONN_TYPE);
|
|
|
|
+ phy_data->mdio_addr = XP_GET_BITS(pdata->pp0, XP_PROP_0, MDIO_ADDR);
|
|
if (netif_msg_probe(pdata)) {
|
|
if (netif_msg_probe(pdata)) {
|
|
dev_dbg(pdata->dev, "port mode=%u\n", phy_data->port_mode);
|
|
dev_dbg(pdata->dev, "port mode=%u\n", phy_data->port_mode);
|
|
dev_dbg(pdata->dev, "port id=%u\n", phy_data->port_id);
|
|
dev_dbg(pdata->dev, "port id=%u\n", phy_data->port_id);
|
|
@@ -2954,12 +3105,11 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
|
|
dev_dbg(pdata->dev, "mdio addr=%u\n", phy_data->mdio_addr);
|
|
dev_dbg(pdata->dev, "mdio addr=%u\n", phy_data->mdio_addr);
|
|
}
|
|
}
|
|
|
|
|
|
- reg = XP_IOREAD(pdata, XP_PROP_4);
|
|
|
|
- phy_data->redrv = XP_GET_BITS(reg, XP_PROP_4, REDRV_PRESENT);
|
|
|
|
- phy_data->redrv_if = XP_GET_BITS(reg, XP_PROP_4, REDRV_IF);
|
|
|
|
- phy_data->redrv_addr = XP_GET_BITS(reg, XP_PROP_4, REDRV_ADDR);
|
|
|
|
- phy_data->redrv_lane = XP_GET_BITS(reg, XP_PROP_4, REDRV_LANE);
|
|
|
|
- phy_data->redrv_model = XP_GET_BITS(reg, XP_PROP_4, REDRV_MODEL);
|
|
|
|
|
|
+ phy_data->redrv = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_PRESENT);
|
|
|
|
+ phy_data->redrv_if = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_IF);
|
|
|
|
+ phy_data->redrv_addr = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_ADDR);
|
|
|
|
+ phy_data->redrv_lane = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_LANE);
|
|
|
|
+ phy_data->redrv_model = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_MODEL);
|
|
if (phy_data->redrv && netif_msg_probe(pdata)) {
|
|
if (phy_data->redrv && netif_msg_probe(pdata)) {
|
|
dev_dbg(pdata->dev, "redrv present\n");
|
|
dev_dbg(pdata->dev, "redrv present\n");
|
|
dev_dbg(pdata->dev, "redrv i/f=%u\n", phy_data->redrv_if);
|
|
dev_dbg(pdata->dev, "redrv i/f=%u\n", phy_data->redrv_if);
|
|
@@ -3231,4 +3381,7 @@ void xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *phy_if)
|
|
|
|
|
|
phy_impl->kr_training_pre = xgbe_phy_kr_training_pre;
|
|
phy_impl->kr_training_pre = xgbe_phy_kr_training_pre;
|
|
phy_impl->kr_training_post = xgbe_phy_kr_training_post;
|
|
phy_impl->kr_training_post = xgbe_phy_kr_training_post;
|
|
|
|
+
|
|
|
|
+ phy_impl->module_info = xgbe_phy_module_info;
|
|
|
|
+ phy_impl->module_eeprom = xgbe_phy_module_eeprom;
|
|
}
|
|
}
|