Skip to content

Commit be51ed1

Browse files
hkallweitkuba-moo
authored andcommitted
r8169: add LED support for RTL8125/RTL8126
This adds LED support for RTL8125/RTL8126. Note: Due to missing datasheets changing the 5Gbps link mode isn't supported for RTL8126. Signed-off-by: Heiner Kallweit <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 4a78f01 commit be51ed1

File tree

3 files changed

+166
-4
lines changed

3 files changed

+166
-4
lines changed

drivers/net/ethernet/realtek/r8169.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,6 @@ void r8169_get_led_name(struct rtl8169_private *tp, int idx,
8585
int rtl8168_get_led_mode(struct rtl8169_private *tp);
8686
int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val);
8787
void rtl8168_init_leds(struct net_device *ndev);
88+
int rtl8125_get_led_mode(struct rtl8169_private *tp, int index);
89+
int rtl8125_set_led_mode(struct rtl8169_private *tp, int index, u16 mode);
90+
void rtl8125_init_leds(struct net_device *ndev);

drivers/net/ethernet/realtek/r8169_leds.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,14 @@
1818
#define RTL8168_LED_CTRL_LINK_100 BIT(1)
1919
#define RTL8168_LED_CTRL_LINK_10 BIT(0)
2020

21+
#define RTL8125_LED_CTRL_ACT BIT(9)
22+
#define RTL8125_LED_CTRL_LINK_2500 BIT(5)
23+
#define RTL8125_LED_CTRL_LINK_1000 BIT(3)
24+
#define RTL8125_LED_CTRL_LINK_100 BIT(1)
25+
#define RTL8125_LED_CTRL_LINK_10 BIT(0)
26+
2127
#define RTL8168_NUM_LEDS 3
28+
#define RTL8125_NUM_LEDS 4
2229

2330
struct r8169_led_classdev {
2431
struct led_classdev led;
@@ -156,3 +163,102 @@ void rtl8168_init_leds(struct net_device *ndev)
156163
for (i = 0; i < RTL8168_NUM_LEDS; i++)
157164
rtl8168_setup_ldev(leds + i, ndev, i);
158165
}
166+
167+
static int rtl8125_led_hw_control_is_supported(struct led_classdev *led_cdev,
168+
unsigned long flags)
169+
{
170+
struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
171+
struct rtl8169_private *tp = netdev_priv(ldev->ndev);
172+
173+
if (!r8169_trigger_mode_is_valid(flags)) {
174+
/* Switch LED off to indicate that mode isn't supported */
175+
rtl8125_set_led_mode(tp, ldev->index, 0);
176+
return -EOPNOTSUPP;
177+
}
178+
179+
return 0;
180+
}
181+
182+
static int rtl8125_led_hw_control_set(struct led_classdev *led_cdev,
183+
unsigned long flags)
184+
{
185+
struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
186+
struct rtl8169_private *tp = netdev_priv(ldev->ndev);
187+
u16 mode = 0;
188+
189+
if (flags & BIT(TRIGGER_NETDEV_LINK_10))
190+
mode |= RTL8125_LED_CTRL_LINK_10;
191+
if (flags & BIT(TRIGGER_NETDEV_LINK_100))
192+
mode |= RTL8125_LED_CTRL_LINK_100;
193+
if (flags & BIT(TRIGGER_NETDEV_LINK_1000))
194+
mode |= RTL8125_LED_CTRL_LINK_1000;
195+
if (flags & BIT(TRIGGER_NETDEV_LINK_2500))
196+
mode |= RTL8125_LED_CTRL_LINK_2500;
197+
if (flags & (BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX)))
198+
mode |= RTL8125_LED_CTRL_ACT;
199+
200+
return rtl8125_set_led_mode(tp, ldev->index, mode);
201+
}
202+
203+
static int rtl8125_led_hw_control_get(struct led_classdev *led_cdev,
204+
unsigned long *flags)
205+
{
206+
struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
207+
struct rtl8169_private *tp = netdev_priv(ldev->ndev);
208+
int mode;
209+
210+
mode = rtl8125_get_led_mode(tp, ldev->index);
211+
if (mode < 0)
212+
return mode;
213+
214+
if (mode & RTL8125_LED_CTRL_LINK_10)
215+
*flags |= BIT(TRIGGER_NETDEV_LINK_10);
216+
if (mode & RTL8125_LED_CTRL_LINK_100)
217+
*flags |= BIT(TRIGGER_NETDEV_LINK_100);
218+
if (mode & RTL8125_LED_CTRL_LINK_1000)
219+
*flags |= BIT(TRIGGER_NETDEV_LINK_1000);
220+
if (mode & RTL8125_LED_CTRL_LINK_2500)
221+
*flags |= BIT(TRIGGER_NETDEV_LINK_2500);
222+
if (mode & RTL8125_LED_CTRL_ACT)
223+
*flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX);
224+
225+
return 0;
226+
}
227+
228+
static void rtl8125_setup_led_ldev(struct r8169_led_classdev *ldev,
229+
struct net_device *ndev, int index)
230+
{
231+
struct rtl8169_private *tp = netdev_priv(ndev);
232+
struct led_classdev *led_cdev = &ldev->led;
233+
char led_name[LED_MAX_NAME_SIZE];
234+
235+
ldev->ndev = ndev;
236+
ldev->index = index;
237+
238+
r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE);
239+
led_cdev->name = led_name;
240+
led_cdev->hw_control_trigger = "netdev";
241+
led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN;
242+
led_cdev->hw_control_is_supported = rtl8125_led_hw_control_is_supported;
243+
led_cdev->hw_control_set = rtl8125_led_hw_control_set;
244+
led_cdev->hw_control_get = rtl8125_led_hw_control_get;
245+
led_cdev->hw_control_get_device = r8169_led_hw_control_get_device;
246+
247+
/* ignore errors */
248+
devm_led_classdev_register(&ndev->dev, led_cdev);
249+
}
250+
251+
void rtl8125_init_leds(struct net_device *ndev)
252+
{
253+
/* bind resource mgmt to netdev */
254+
struct device *dev = &ndev->dev;
255+
struct r8169_led_classdev *leds;
256+
int i;
257+
258+
leds = devm_kcalloc(dev, RTL8125_NUM_LEDS, sizeof(*leds), GFP_KERNEL);
259+
if (!leds)
260+
return;
261+
262+
for (i = 0; i < RTL8125_NUM_LEDS; i++)
263+
rtl8125_setup_led_ldev(leds + i, ndev, i);
264+
}

drivers/net/ethernet/realtek/r8169_main.c

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,17 +330,23 @@ enum rtl8168_registers {
330330
};
331331

332332
enum rtl8125_registers {
333+
LEDSEL0 = 0x18,
333334
INT_CFG0_8125 = 0x34,
334335
#define INT_CFG0_ENABLE_8125 BIT(0)
335336
#define INT_CFG0_CLKREQEN BIT(3)
336337
IntrMask_8125 = 0x38,
337338
IntrStatus_8125 = 0x3c,
338339
INT_CFG1_8125 = 0x7a,
340+
LEDSEL2 = 0x84,
341+
LEDSEL1 = 0x86,
339342
TxPoll_8125 = 0x90,
343+
LEDSEL3 = 0x96,
340344
MAC0_BKP = 0x19e0,
341345
EEE_TXIDLE_TIMER_8125 = 0x6048,
342346
};
343347

348+
#define LEDSEL_MASK_8125 0x23f
349+
344350
#define RX_VLAN_INNER_8125 BIT(22)
345351
#define RX_VLAN_OUTER_8125 BIT(23)
346352
#define RX_VLAN_8125 (RX_VLAN_INNER_8125 | RX_VLAN_OUTER_8125)
@@ -830,6 +836,51 @@ int rtl8168_get_led_mode(struct rtl8169_private *tp)
830836
return ret;
831837
}
832838

839+
static int rtl8125_get_led_reg(int index)
840+
{
841+
static const int led_regs[] = { LEDSEL0, LEDSEL1, LEDSEL2, LEDSEL3 };
842+
843+
return led_regs[index];
844+
}
845+
846+
int rtl8125_set_led_mode(struct rtl8169_private *tp, int index, u16 mode)
847+
{
848+
int reg = rtl8125_get_led_reg(index);
849+
struct device *dev = tp_to_dev(tp);
850+
int ret;
851+
u16 val;
852+
853+
ret = pm_runtime_resume_and_get(dev);
854+
if (ret < 0)
855+
return ret;
856+
857+
mutex_lock(&tp->led_lock);
858+
val = RTL_R16(tp, reg) & ~LEDSEL_MASK_8125;
859+
RTL_W16(tp, reg, val | mode);
860+
mutex_unlock(&tp->led_lock);
861+
862+
pm_runtime_put_sync(dev);
863+
864+
return 0;
865+
}
866+
867+
int rtl8125_get_led_mode(struct rtl8169_private *tp, int index)
868+
{
869+
int reg = rtl8125_get_led_reg(index);
870+
struct device *dev = tp_to_dev(tp);
871+
int ret;
872+
873+
ret = pm_runtime_resume_and_get(dev);
874+
if (ret < 0)
875+
return ret;
876+
877+
ret = RTL_R16(tp, reg);
878+
879+
pm_runtime_put_sync(dev);
880+
881+
return ret;
882+
}
883+
833884
void r8169_get_led_name(struct rtl8169_private *tp, int idx,
834885
char *buf, int buf_len)
835886
{
@@ -5385,10 +5436,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
53855436
if (rc)
53865437
return rc;
53875438

5388-
if (IS_ENABLED(CONFIG_R8169_LEDS) &&
5389-
tp->mac_version > RTL_GIGA_MAC_VER_06 &&
5390-
tp->mac_version < RTL_GIGA_MAC_VER_61)
5391-
rtl8168_init_leds(dev);
5439+
if (IS_ENABLED(CONFIG_R8169_LEDS)) {
5440+
if (rtl_is_8125(tp))
5441+
rtl8125_init_leds(dev);
5442+
else if (tp->mac_version > RTL_GIGA_MAC_VER_06)
5443+
rtl8168_init_leds(dev);
5444+
}
53925445

53935446
netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n",
53945447
rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq);

0 commit comments

Comments
 (0)