OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 1 | From 4a4aca08b11501cb1b2c509113bbb65eb66a1f45 Mon Sep 17 00:00:00 2001 |
2 | From: Russell King <rmk+kernel@armlinux.org.uk> |
||
3 | Date: Fri, 14 Apr 2017 14:21:25 +0100 |
||
4 | Subject: sfp: hack: allow marvell 10G phy support to use SFP |
||
5 | |||
6 | Allow the Marvell 10G PHY to register with the SFP bus, so that SFP+ |
||
7 | cages can work. This bypasses phylink, meaning that socket status |
||
8 | is not taken into account for the link state. Also, the tx-disable |
||
9 | signal must be commented out in DT for this to work... |
||
10 | |||
11 | Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> |
||
12 | --- |
||
13 | drivers/net/phy/marvell10g.c | 54 +++++++++++++++++++++++++++++++++++++++++++- |
||
14 | 1 file changed, 53 insertions(+), 1 deletion(-) |
||
15 | |||
16 | --- a/drivers/net/phy/marvell10g.c |
||
17 | +++ b/drivers/net/phy/marvell10g.c |
||
18 | @@ -15,8 +15,10 @@ |
||
19 | * If both the fiber and copper ports are connected, the first to gain |
||
20 | * link takes priority and the other port is completely locked out. |
||
21 | */ |
||
22 | +#include <linux/of.h> |
||
23 | #include <linux/phy.h> |
||
24 | #include <linux/marvell_phy.h> |
||
25 | +#include <linux/sfp.h> |
||
26 | |||
27 | enum { |
||
28 | MV_PCS_BASE_T = 0x0000, |
||
29 | @@ -38,6 +40,11 @@ enum { |
||
30 | MV_AN_RESULT_SPD_10000 = BIT(15), |
||
31 | }; |
||
32 | |||
33 | +struct mv3310_priv { |
||
34 | + struct device_node *sfp_node; |
||
35 | + struct sfp_bus *sfp_bus; |
||
36 | +}; |
||
37 | + |
||
38 | static int mv3310_modify(struct phy_device *phydev, int devad, u16 reg, |
||
39 | u16 mask, u16 bits) |
||
40 | { |
||
41 | @@ -56,17 +63,52 @@ static int mv3310_modify(struct phy_devi |
||
42 | return ret < 0 ? ret : 1; |
||
43 | } |
||
44 | |||
45 | +static int mv3310_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) |
||
46 | +{ |
||
47 | + struct phy_device *phydev = upstream; |
||
48 | + struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); |
||
49 | + |
||
50 | + if (sfp_parse_interface(priv->sfp_bus, id) != PHY_INTERFACE_MODE_10GKR) { |
||
51 | + dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); |
||
52 | + return -EINVAL; |
||
53 | + } |
||
54 | + return 0; |
||
55 | +} |
||
56 | + |
||
57 | +static const struct sfp_upstream_ops mv3310_sfp_ops = { |
||
58 | + .module_insert = mv3310_sfp_insert, |
||
59 | +}; |
||
60 | + |
||
61 | static int mv3310_probe(struct phy_device *phydev) |
||
62 | { |
||
63 | + struct mv3310_priv *priv; |
||
64 | u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN; |
||
65 | |||
66 | if (!phydev->is_c45 || |
||
67 | (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask) |
||
68 | return -ENODEV; |
||
69 | |||
70 | + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); |
||
71 | + if (!priv) |
||
72 | + return -ENOMEM; |
||
73 | + |
||
74 | + dev_set_drvdata(&phydev->mdio.dev, priv); |
||
75 | + |
||
76 | + if (phydev->mdio.dev.of_node) |
||
77 | + priv->sfp_node = of_parse_phandle(phydev->mdio.dev.of_node, |
||
78 | + "sfp", 0); |
||
79 | + |
||
80 | return 0; |
||
81 | } |
||
82 | |||
83 | +static void mv3310_remove(struct phy_device *phydev) |
||
84 | +{ |
||
85 | + struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); |
||
86 | + |
||
87 | + if (priv->sfp_bus) |
||
88 | + sfp_unregister_upstream(priv->sfp_bus); |
||
89 | +} |
||
90 | + |
||
91 | /* |
||
92 | * Resetting the MV88X3310 causes it to become non-responsive. Avoid |
||
93 | * setting the reset bit(s). |
||
94 | @@ -78,6 +120,7 @@ static int mv3310_soft_reset(struct phy_ |
||
95 | |||
96 | static int mv3310_config_init(struct phy_device *phydev) |
||
97 | { |
||
98 | + struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); |
||
99 | __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, }; |
||
100 | u32 mask; |
||
101 | int val; |
||
102 | @@ -166,6 +209,14 @@ static int mv3310_config_init(struct phy |
||
103 | phydev->supported &= mask; |
||
104 | phydev->advertising &= phydev->supported; |
||
105 | |||
106 | + /* Would be nice to do this in the probe function, but unfortunately, |
||
107 | + * phylib doesn't have phydev->attached_dev set there. |
||
108 | + */ |
||
109 | + if (priv->sfp_node && !priv->sfp_bus) |
||
110 | + priv->sfp_bus = sfp_register_upstream(priv->sfp_node, |
||
111 | + phydev->attached_dev, |
||
112 | + phydev, &mv3310_sfp_ops); |
||
113 | + |
||
114 | return 0; |
||
115 | } |
||
116 | |||
117 | @@ -349,12 +400,13 @@ static struct phy_driver mv3310_drivers[ |
||
118 | SUPPORTED_FIBRE | |
||
119 | SUPPORTED_10000baseT_Full | |
||
120 | SUPPORTED_Backplane, |
||
121 | - .probe = mv3310_probe, |
||
122 | .soft_reset = mv3310_soft_reset, |
||
123 | .config_init = mv3310_config_init, |
||
124 | + .probe = mv3310_probe, |
||
125 | .config_aneg = mv3310_config_aneg, |
||
126 | .aneg_done = mv3310_aneg_done, |
||
127 | .read_status = mv3310_read_status, |
||
128 | + .remove = mv3310_remove, |
||
129 | }, |
||
130 | }; |
||
131 |