Skip to content

Commit 2347093

Browse files
committed
Merge branch 'phylink-and-sfp-support'
Russell King says: ==================== phylink and sfp support This patch series introduces generic support for SFP sockets found on various Marvell based platforms. The idea here is to provide common SFP socket support which can be re-used by network drivers as appropriate, rather than each network driver having to re-implement SFP socket support. SFP sockets typically use other system resources, eg, I2C buses to read identifying information, and GPIOs to monitor socket state and control the socket. Meanwhile, some network drivers drive multiple ethernet ports from one instantiation of the driver. It is not desirable to block the initialisation of a network driver (thus denying other ports from being operational) if the resources for the SFP socket are not yet available. This means that an element of independence between the SFP support code and the driver is required. More than that, SFP modules effectively bring hotplug PHYs to networking - SFP copper modules normally contain a standard PHY accessed over the I2C bus, and it is desirable to read their state so network drivers can be appropriately configured. To add to the complexity, SFP modules can be connected in at least two places: 1. Directly to the serdes output of a MAC with no intervening PHY. For example: mvneta ----> SFP socket 2. To a PHY, for example: mvpp2 ---> PHY ---> copper | `-----> SFP socket This code supports both setups, although it's not fully implemented with scenario (2). Moreover, the link presented by the SFP module can be one of the 10Gbase-R family (for SFP+ sockets), SGMII or 1000base-X (for SFP sockets) depending on the module, and network drivers need to reconfigure themselves accordingly for the link to come up. For example, if the MAC is configured for SGMII and a fibre module is plugged in, the link won't come up until the MAC is reconfigured for 1000base-X mode. The SFP code manages the SFP socket - detecting the module, reading the identifying information, and managing the control and status signals. Importantly, it disables the SFP module transmitter when the MAC is down, so that the laser is turned off (but that is not a guarantee.) phylink provides the mechanisms necessary to manage the link modes, based on the SFP module type, and supports hot-plugging of the PHY without needing the MAC driver to be brought up and down on transitions. phylink also supports the classical static PHY and fixed-link modes. I currently (but not included in this series) have code to convert mvneta to use phylink, and the out of tree mvpp2x driver. I have nothing for the mvpp2 driver at present as that driver is only recently becoming functional on 10G hardware, and is missing a lot of features that are necessary to make things work correctly. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 21e27f2 + 7397005 commit 2347093

File tree

14 files changed

+3867
-187
lines changed

14 files changed

+3867
-187
lines changed

drivers/net/phy/Kconfig

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,16 @@ config MDIO_HISI_FEMAC
106106
This module provides a driver for the MDIO busses found in the
107107
Hisilicon SoC that have an Fast Ethernet MAC.
108108

109+
config MDIO_I2C
110+
tristate
111+
depends on I2C
112+
help
113+
Support I2C based PHYs. This provides a MDIO bus bridged
114+
to I2C to allow PHYs connected in I2C mode to be accessed
115+
using the existing infrastructure.
116+
117+
This is library mode.
118+
109119
config MDIO_MOXART
110120
tristate "MOXA ART MDIO interface support"
111121
depends on ARCH_MOXART
@@ -159,6 +169,16 @@ menuconfig PHYLIB
159169
devices. This option provides infrastructure for
160170
managing PHY devices.
161171

172+
config PHYLINK
173+
tristate
174+
depends on NETDEVICES
175+
select PHYLIB
176+
select SWPHY
177+
help
178+
PHYlink models the link between the PHY and MAC, allowing fixed
179+
configuration links, PHYs, and Serdes links with MAC level
180+
autonegotiation modes.
181+
162182
if PHYLIB
163183

164184
config SWPHY
@@ -180,6 +200,11 @@ config LED_TRIGGER_PHY
180200

181201
comment "MII PHY device drivers"
182202

203+
config SFP
204+
tristate "SFP cage support"
205+
depends on I2C && PHYLINK
206+
select MDIO_I2C
207+
183208
config AMD_PHY
184209
tristate "AMD PHYs"
185210
---help---

drivers/net/phy/Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ endif
1818
libphy-$(CONFIG_SWPHY) += swphy.o
1919
libphy-$(CONFIG_LED_TRIGGER_PHY) += phy_led_triggers.o
2020

21+
obj-$(CONFIG_PHYLINK) += phylink.o
2122
obj-$(CONFIG_PHYLIB) += libphy.o
2223

2324
obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o
@@ -30,12 +31,17 @@ obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o
3031
obj-$(CONFIG_MDIO_CAVIUM) += mdio-cavium.o
3132
obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
3233
obj-$(CONFIG_MDIO_HISI_FEMAC) += mdio-hisi-femac.o
34+
obj-$(CONFIG_MDIO_I2C) += mdio-i2c.o
3335
obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o
3436
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
3537
obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o
3638
obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o
3739
obj-$(CONFIG_MDIO_XGENE) += mdio-xgene.o
3840

41+
obj-$(CONFIG_SFP) += sfp.o
42+
sfp-obj-$(CONFIG_SFP) += sfp-bus.o
43+
obj-y += $(sfp-obj-y) $(sfp-obj-m)
44+
3945
obj-$(CONFIG_AMD_PHY) += amd.o
4046
obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
4147
obj-$(CONFIG_AT803X_PHY) += at803x.o

drivers/net/phy/mdio-i2c.c

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* MDIO I2C bridge
3+
*
4+
* Copyright (C) 2015-2016 Russell King
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License version 2 as
8+
* published by the Free Software Foundation.
9+
*
10+
* Network PHYs can appear on I2C buses when they are part of SFP module.
11+
* This driver exposes these PHYs to the networking PHY code, allowing
12+
* our PHY drivers access to these PHYs, and so allowing configuration
13+
* of their settings.
14+
*/
15+
#include <linux/i2c.h>
16+
#include <linux/phy.h>
17+
18+
#include "mdio-i2c.h"
19+
20+
/*
21+
* I2C bus addresses 0x50 and 0x51 are normally an EEPROM, which is
22+
* specified to be present in SFP modules. These correspond with PHY
23+
* addresses 16 and 17. Disallow access to these "phy" addresses.
24+
*/
25+
static bool i2c_mii_valid_phy_id(int phy_id)
26+
{
27+
return phy_id != 0x10 && phy_id != 0x11;
28+
}
29+
30+
static unsigned int i2c_mii_phy_addr(int phy_id)
31+
{
32+
return phy_id + 0x40;
33+
}
34+
35+
static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg)
36+
{
37+
struct i2c_adapter *i2c = bus->priv;
38+
struct i2c_msg msgs[2];
39+
u8 data[2], dev_addr = reg;
40+
int bus_addr, ret;
41+
42+
if (!i2c_mii_valid_phy_id(phy_id))
43+
return 0xffff;
44+
45+
bus_addr = i2c_mii_phy_addr(phy_id);
46+
msgs[0].addr = bus_addr;
47+
msgs[0].flags = 0;
48+
msgs[0].len = 1;
49+
msgs[0].buf = &dev_addr;
50+
msgs[1].addr = bus_addr;
51+
msgs[1].flags = I2C_M_RD;
52+
msgs[1].len = sizeof(data);
53+
msgs[1].buf = data;
54+
55+
ret = i2c_transfer(i2c, msgs, ARRAY_SIZE(msgs));
56+
if (ret != ARRAY_SIZE(msgs))
57+
return 0xffff;
58+
59+
return data[0] << 8 | data[1];
60+
}
61+
62+
static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
63+
{
64+
struct i2c_adapter *i2c = bus->priv;
65+
struct i2c_msg msg;
66+
int ret;
67+
u8 data[3];
68+
69+
if (!i2c_mii_valid_phy_id(phy_id))
70+
return 0;
71+
72+
data[0] = reg;
73+
data[1] = val >> 8;
74+
data[2] = val;
75+
76+
msg.addr = i2c_mii_phy_addr(phy_id);
77+
msg.flags = 0;
78+
msg.len = 3;
79+
msg.buf = data;
80+
81+
ret = i2c_transfer(i2c, &msg, 1);
82+
83+
return ret < 0 ? ret : 0;
84+
}
85+
86+
struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c)
87+
{
88+
struct mii_bus *mii;
89+
90+
if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
91+
return ERR_PTR(-EINVAL);
92+
93+
mii = mdiobus_alloc();
94+
if (!mii)
95+
return ERR_PTR(-ENOMEM);
96+
97+
snprintf(mii->id, MII_BUS_ID_SIZE, "i2c:%s", dev_name(parent));
98+
mii->parent = parent;
99+
mii->read = i2c_mii_read;
100+
mii->write = i2c_mii_write;
101+
mii->priv = i2c;
102+
103+
return mii;
104+
}
105+
EXPORT_SYMBOL_GPL(mdio_i2c_alloc);
106+
107+
MODULE_AUTHOR("Russell King");
108+
MODULE_DESCRIPTION("MDIO I2C bridge library");
109+
MODULE_LICENSE("GPL v2");

drivers/net/phy/mdio-i2c.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* MDIO I2C bridge
3+
*
4+
* Copyright (C) 2015 Russell King
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License version 2 as
8+
* published by the Free Software Foundation.
9+
*/
10+
#ifndef MDIO_I2C_H
11+
#define MDIO_I2C_H
12+
13+
struct device;
14+
struct i2c_adapter;
15+
struct mii_bus;
16+
17+
struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c);
18+
19+
#endif

drivers/net/phy/phy-core.c

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,186 @@
99
#include <linux/export.h>
1010
#include <linux/phy.h>
1111

12+
const char *phy_speed_to_str(int speed)
13+
{
14+
switch (speed) {
15+
case SPEED_10:
16+
return "10Mbps";
17+
case SPEED_100:
18+
return "100Mbps";
19+
case SPEED_1000:
20+
return "1Gbps";
21+
case SPEED_2500:
22+
return "2.5Gbps";
23+
case SPEED_5000:
24+
return "5Gbps";
25+
case SPEED_10000:
26+
return "10Gbps";
27+
case SPEED_14000:
28+
return "14Gbps";
29+
case SPEED_20000:
30+
return "20Gbps";
31+
case SPEED_25000:
32+
return "25Gbps";
33+
case SPEED_40000:
34+
return "40Gbps";
35+
case SPEED_50000:
36+
return "50Gbps";
37+
case SPEED_56000:
38+
return "56Gbps";
39+
case SPEED_100000:
40+
return "100Gbps";
41+
case SPEED_UNKNOWN:
42+
return "Unknown";
43+
default:
44+
return "Unsupported (update phy-core.c)";
45+
}
46+
}
47+
EXPORT_SYMBOL_GPL(phy_speed_to_str);
48+
49+
const char *phy_duplex_to_str(unsigned int duplex)
50+
{
51+
if (duplex == DUPLEX_HALF)
52+
return "Half";
53+
if (duplex == DUPLEX_FULL)
54+
return "Full";
55+
if (duplex == DUPLEX_UNKNOWN)
56+
return "Unknown";
57+
return "Unsupported (update phy-core.c)";
58+
}
59+
EXPORT_SYMBOL_GPL(phy_duplex_to_str);
60+
61+
/* A mapping of all SUPPORTED settings to speed/duplex. This table
62+
* must be grouped by speed and sorted in descending match priority
63+
* - iow, descending speed. */
64+
static const struct phy_setting settings[] = {
65+
{
66+
.speed = SPEED_10000,
67+
.duplex = DUPLEX_FULL,
68+
.bit = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
69+
},
70+
{
71+
.speed = SPEED_10000,
72+
.duplex = DUPLEX_FULL,
73+
.bit = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
74+
},
75+
{
76+
.speed = SPEED_10000,
77+
.duplex = DUPLEX_FULL,
78+
.bit = ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
79+
},
80+
{
81+
.speed = SPEED_2500,
82+
.duplex = DUPLEX_FULL,
83+
.bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
84+
},
85+
{
86+
.speed = SPEED_1000,
87+
.duplex = DUPLEX_FULL,
88+
.bit = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
89+
},
90+
{
91+
.speed = SPEED_1000,
92+
.duplex = DUPLEX_FULL,
93+
.bit = ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
94+
},
95+
{
96+
.speed = SPEED_1000,
97+
.duplex = DUPLEX_FULL,
98+
.bit = ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
99+
},
100+
{
101+
.speed = SPEED_1000,
102+
.duplex = DUPLEX_HALF,
103+
.bit = ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
104+
},
105+
{
106+
.speed = SPEED_100,
107+
.duplex = DUPLEX_FULL,
108+
.bit = ETHTOOL_LINK_MODE_100baseT_Full_BIT,
109+
},
110+
{
111+
.speed = SPEED_100,
112+
.duplex = DUPLEX_HALF,
113+
.bit = ETHTOOL_LINK_MODE_100baseT_Half_BIT,
114+
},
115+
{
116+
.speed = SPEED_10,
117+
.duplex = DUPLEX_FULL,
118+
.bit = ETHTOOL_LINK_MODE_10baseT_Full_BIT,
119+
},
120+
{
121+
.speed = SPEED_10,
122+
.duplex = DUPLEX_HALF,
123+
.bit = ETHTOOL_LINK_MODE_10baseT_Half_BIT,
124+
},
125+
};
126+
127+
/**
128+
* phy_lookup_setting - lookup a PHY setting
129+
* @speed: speed to match
130+
* @duplex: duplex to match
131+
* @mask: allowed link modes
132+
* @maxbit: bit size of link modes
133+
* @exact: an exact match is required
134+
*
135+
* Search the settings array for a setting that matches the speed and
136+
* duplex, and which is supported.
137+
*
138+
* If @exact is unset, either an exact match or %NULL for no match will
139+
* be returned.
140+
*
141+
* If @exact is set, an exact match, the fastest supported setting at
142+
* or below the specified speed, the slowest supported setting, or if
143+
* they all fail, %NULL will be returned.
144+
*/
145+
const struct phy_setting *
146+
phy_lookup_setting(int speed, int duplex, const unsigned long *mask,
147+
size_t maxbit, bool exact)
148+
{
149+
const struct phy_setting *p, *match = NULL, *last = NULL;
150+
int i;
151+
152+
for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
153+
if (p->bit < maxbit && test_bit(p->bit, mask)) {
154+
last = p;
155+
if (p->speed == speed && p->duplex == duplex) {
156+
/* Exact match for speed and duplex */
157+
match = p;
158+
break;
159+
} else if (!exact) {
160+
if (!match && p->speed <= speed)
161+
/* Candidate */
162+
match = p;
163+
164+
if (p->speed < speed)
165+
break;
166+
}
167+
}
168+
}
169+
170+
if (!match && !exact)
171+
match = last;
172+
173+
return match;
174+
}
175+
EXPORT_SYMBOL_GPL(phy_lookup_setting);
176+
177+
size_t phy_speeds(unsigned int *speeds, size_t size,
178+
unsigned long *mask, size_t maxbit)
179+
{
180+
size_t count;
181+
int i;
182+
183+
for (i = 0, count = 0; i < ARRAY_SIZE(settings) && count < size; i++)
184+
if (settings[i].bit < maxbit &&
185+
test_bit(settings[i].bit, mask) &&
186+
(count == 0 || speeds[count - 1] != settings[i].speed))
187+
speeds[count++] = settings[i].speed;
188+
189+
return count;
190+
}
191+
12192
static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
13193
u16 regnum)
14194
{

0 commit comments

Comments
 (0)