Skip to content

Commit

Permalink
net: phy: leds: Add support for "link" trigger
Browse files Browse the repository at this point in the history
Currently, we create a LED trigger for any link speed known to a PHY.
These triggers only fire when their exact link speed had been negotiated
(they aren't cumulative, that is, they don't fire for "their or any higher"
link speed).

What we are missing, however, is a trigger which will fire on any link
speed known to the PHY. Such trigger can then be used for implementing a
poor man's substitute of the "link" LED on boards that lack it.
Let's add it.

Signed-off-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
maciejsszmigiero authored and davem330 committed Nov 8, 2017
1 parent ff198cd commit 3928ee6
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 5 deletions.
7 changes: 5 additions & 2 deletions drivers/net/phy/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,14 @@ config LED_TRIGGER_PHY
Adds support for a set of LED trigger events per-PHY. Link
state change will trigger the events, for consumption by an
LED class driver. There are triggers for each link speed currently
supported by the phy, and are of the form:
supported by the PHY and also a one common "link" trigger as a
logical-or of all the link speed ones.
All these triggers are named according to the following pattern:
<mii bus id>:<phy>:<speed>

Where speed is in the form:
<Speed in megabits>Mbps or <Speed in gigabits>Gbps
<Speed in megabits>Mbps OR <Speed in gigabits>Gbps OR link
for any speed known to the PHY.


comment "MII PHY device drivers"
Expand Down
43 changes: 40 additions & 3 deletions drivers/net/phy/phy_led_triggers.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ static void phy_led_trigger_no_link(struct phy_device *phy)
{
if (phy->last_triggered) {
led_trigger_event(&phy->last_triggered->trigger, LED_OFF);
led_trigger_event(&phy->led_link_trigger->trigger, LED_OFF);
phy->last_triggered = NULL;
}
}
Expand All @@ -54,13 +55,24 @@ void phy_led_trigger_change_speed(struct phy_device *phy)
}

if (plt != phy->last_triggered) {
if (!phy->last_triggered)
led_trigger_event(&phy->led_link_trigger->trigger,
LED_FULL);

led_trigger_event(&phy->last_triggered->trigger, LED_OFF);
led_trigger_event(&plt->trigger, LED_FULL);
phy->last_triggered = plt;
}
}
EXPORT_SYMBOL_GPL(phy_led_trigger_change_speed);

static void phy_led_trigger_format_name(struct phy_device *phy, char *buf,
size_t size, char *suffix)
{
snprintf(buf, size, PHY_ID_FMT ":%s",
phy->mdio.bus->id, phy->mdio.addr, suffix);
}

static int phy_led_trigger_register(struct phy_device *phy,
struct phy_led_trigger *plt,
unsigned int speed)
Expand All @@ -77,8 +89,8 @@ static int phy_led_trigger_register(struct phy_device *phy,
snprintf(name_suffix, sizeof(name_suffix), "%dGbps",
DIV_ROUND_CLOSEST(speed, 1000));

snprintf(plt->name, sizeof(plt->name), PHY_ID_FMT ":%s",
phy->mdio.bus->id, phy->mdio.addr, name_suffix);
phy_led_trigger_format_name(phy, plt->name, sizeof(plt->name),
name_suffix);
plt->trigger.name = plt->name;

return led_trigger_register(&plt->trigger);
Expand All @@ -99,13 +111,30 @@ int phy_led_triggers_register(struct phy_device *phy)
if (!phy->phy_num_led_triggers)
return 0;

phy->led_link_trigger = devm_kzalloc(&phy->mdio.dev,
sizeof(*phy->led_link_trigger),
GFP_KERNEL);
if (!phy->led_link_trigger) {
err = -ENOMEM;
goto out_clear;
}

phy_led_trigger_format_name(phy, phy->led_link_trigger->name,
sizeof(phy->led_link_trigger->name),
"link");
phy->led_link_trigger->trigger.name = phy->led_link_trigger->name;

err = led_trigger_register(&phy->led_link_trigger->trigger);
if (err)
goto out_free_link;

phy->phy_led_triggers = devm_kzalloc(&phy->mdio.dev,
sizeof(struct phy_led_trigger) *
phy->phy_num_led_triggers,
GFP_KERNEL);
if (!phy->phy_led_triggers) {
err = -ENOMEM;
goto out_clear;
goto out_unreg_link;
}

for (i = 0; i < phy->phy_num_led_triggers; i++) {
Expand All @@ -123,6 +152,11 @@ int phy_led_triggers_register(struct phy_device *phy)
while (i--)
phy_led_trigger_unregister(&phy->phy_led_triggers[i]);
devm_kfree(&phy->mdio.dev, phy->phy_led_triggers);
out_unreg_link:
phy_led_trigger_unregister(phy->led_link_trigger);
out_free_link:
devm_kfree(&phy->mdio.dev, phy->led_link_trigger);
phy->led_link_trigger = NULL;
out_clear:
phy->phy_num_led_triggers = 0;
return err;
Expand All @@ -135,5 +169,8 @@ void phy_led_triggers_unregister(struct phy_device *phy)

for (i = 0; i < phy->phy_num_led_triggers; i++)
phy_led_trigger_unregister(&phy->phy_led_triggers[i]);

if (phy->led_link_trigger)
phy_led_trigger_unregister(phy->led_link_trigger);
}
EXPORT_SYMBOL_GPL(phy_led_triggers_unregister);
2 changes: 2 additions & 0 deletions include/linux/phy.h
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,8 @@ struct phy_device {
struct phy_led_trigger *phy_led_triggers;
unsigned int phy_num_led_triggers;
struct phy_led_trigger *last_triggered;

struct phy_led_trigger *led_link_trigger;
#endif

/*
Expand Down

0 comments on commit 3928ee6

Please sign in to comment.