diff --git a/6.12/package/kernel/mac80211/patches/build/999-assign_str-on-kernel-6.11.patch b/6.12/package/kernel/mac80211/patches/build/999-assign_str-on-kernel-6.11.patch deleted file mode 100644 index cf2b6556..00000000 --- a/6.12/package/kernel/mac80211/patches/build/999-assign_str-on-kernel-6.11.patch +++ /dev/null @@ -1,541 +0,0 @@ ---- a/net/wireless/trace.h 2024-09-13 13:11:10.145025393 +0200 -+++ b/net/wireless/trace.h 2024-09-13 13:14:21.774308452 +0200 -@@ -372,7 +372,7 @@ - ), - TP_fast_assign( - WIPHY_ASSIGN; -- __assign_str(vir_intf_name, name ? name : ""); -+ __assign_str(vir_intf_name); - __entry->type = type; - ), - TP_printk(WIPHY_PR_FMT ", virtual intf name: %s, type: %d", ---- a/net/mac80211/trace.h 2024-09-13 13:27:20.887264216 +0200 -+++ b/net/mac80211/trace.h 2024-09-13 13:29:33.057391014 +0200 -@@ -33,7 +33,7 @@ - __string(vif_name, sdata->name) - #define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \ - __entry->p2p = sdata->vif.p2p; \ -- __assign_str(vif_name, sdata->name) -+ __assign_str(vif_name) - #define VIF_PR_FMT " vif:%s(%d%s)" - #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" - ---- a/drivers/bus/mhi/host/trace.h 2024-09-13 13:31:32.207702337 +0200 -+++ b/drivers/bus/mhi/host/trace.h 2024-09-13 13:32:22.330991957 +0200 -@@ -103,7 +103,7 @@ - ), - - TP_fast_assign( -- __assign_str(name, mhi_cntrl->mhi_dev->name); -+ __assign_str(name); - __entry->ch_num = mhi_chan->chan; - __entry->wp = mhi_tre; - __entry->tre_ptr = mhi_tre->ptr; -@@ -131,7 +131,7 @@ - ), - - TP_fast_assign( -- __assign_str(name, mhi_cntrl->mhi_dev->name); -+ __assign_str(name); - __entry->local_ee = mhi_cntrl->ee; - __entry->state = mhi_cntrl->dev_state; - __entry->dev_ee = dev_ee; -@@ -158,7 +158,7 @@ - ), - - TP_fast_assign( -- __assign_str(name, mhi_cntrl->mhi_dev->name); -+ __assign_str(name); - if (pm_state) - pm_state = __fls(pm_state); - __entry->pm_state = pm_state; -@@ -184,7 +184,7 @@ - ), - - TP_fast_assign( -- __assign_str(name, mhi_cntrl->mhi_dev->name); -+ __assign_str(name); - __entry->rp = rp; - __entry->ptr = rp->ptr; - __entry->dword0 = rp->dword[0]; -@@ -226,7 +226,7 @@ - ), - - TP_fast_assign( -- __assign_str(name, mhi_cntrl->mhi_dev->name); -+ __assign_str(name); - __entry->ch_num = mhi_chan->chan; - __entry->state = state; - __entry->reason = reason; -@@ -265,7 +265,7 @@ - ), - - TP_fast_assign( -- __assign_str(name, mhi_cntrl->mhi_dev->name); -+ __assign_str(name); - __entry->state = state; - ), - ---- a/drivers/net/wireless/ath/ath10k/trace.h 2024-09-13 13:31:32.087704038 +0200 -+++ b/drivers/net/wireless/ath/ath10k/trace.h 2024-09-13 13:35:37.760222205 +0200 -@@ -55,8 +55,8 @@ - __vstring(msg, vaf->fmt, vaf->va) - ), - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __assign_vstr(msg, vaf->fmt, vaf->va); - ), - TP_printk( -@@ -92,8 +92,8 @@ - __vstring(msg, vaf->fmt, vaf->va) - ), - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->level = level; - __assign_vstr(msg, vaf->fmt, vaf->va); - ), -@@ -121,10 +121,10 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -- __assign_str(msg, msg); -- __assign_str(prefix, prefix); -+ __assign_str(device); -+ __assign_str(driver); -+ __assign_str(msg); -+ __assign_str(prefix); - __entry->buf_len = buf_len; - memcpy(__get_dynamic_array(buf), buf, buf_len); - ), -@@ -152,8 +152,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->id = id; - __entry->buf_len = buf_len; - memcpy(__get_dynamic_array(buf), buf, buf_len); -@@ -182,8 +182,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->id = id; - __entry->buf_len = buf_len; - memcpy(__get_dynamic_array(buf), buf, buf_len); -@@ -211,8 +211,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->buf_len = buf_len; - memcpy(__get_dynamic_array(buf), buf, buf_len); - ), -@@ -239,8 +239,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->hw_type = ar->hw_rev; - __entry->buf_len = buf_len; - memcpy(__get_dynamic_array(buf), buf, buf_len); -@@ -269,8 +269,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->hw_type = ar->hw_rev; - __entry->buf_len = buf_len; - memcpy(__get_dynamic_array(pktlog), buf, buf_len); -@@ -301,8 +301,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->msdu_id = msdu_id; - __entry->msdu_len = msdu_len; - __entry->vdev_id = vdev_id; -@@ -332,8 +332,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->msdu_id = msdu_id; - ), - -@@ -358,8 +358,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->len = ath10k_frm_hdr_len(data, len); - memcpy(__get_dynamic_array(data), data, __entry->len); - ), -@@ -386,8 +386,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->len = len - ath10k_frm_hdr_len(data, len); - memcpy(__get_dynamic_array(payload), - data + ath10k_frm_hdr_len(data, len), __entry->len); -@@ -435,8 +435,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->hw_type = ar->hw_rev; - __entry->len = len; - memcpy(__get_dynamic_array(rxdesc), data, len); -@@ -472,8 +472,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->type = type; - __entry->timestamp = timestamp; - __entry->code = code; -@@ -505,8 +505,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->dev)); -- __assign_str(driver, dev_driver_string(ar->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->len = len; - memcpy(__get_dynamic_array(data), data, len); - ), ---- a/drivers/net/wireless/ath/ath11k/trace.h 2024-09-13 13:31:32.047704605 +0200 -+++ b/drivers/net/wireless/ath/ath11k/trace.h 2024-09-13 13:37:29.026645264 +0200 -@@ -48,8 +48,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->ab->dev)); -- __assign_str(driver, dev_driver_string(ar->ab->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->buf_len = buf_len; - __entry->pktlog_checksum = pktlog_checksum; - memcpy(__get_dynamic_array(pktlog), buf, buf_len); -@@ -77,8 +77,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->ab->dev)); -- __assign_str(driver, dev_driver_string(ar->ab->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->len = len; - memcpy(__get_dynamic_array(ppdu), data, len); - ), -@@ -105,8 +105,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->ab->dev)); -- __assign_str(driver, dev_driver_string(ar->ab->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->len = len; - __entry->log_type = log_type; - memcpy(__get_dynamic_array(rxdesc), data, len); -@@ -130,8 +130,8 @@ - __vstring(msg, vaf->fmt, vaf->va) - ), - TP_fast_assign( -- __assign_str(device, dev_name(ab->dev)); -- __assign_str(driver, dev_driver_string(ab->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __assign_vstr(msg, vaf->fmt, vaf->va); - ), - TP_printk( -@@ -171,8 +171,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ab->dev)); -- __assign_str(driver, dev_driver_string(ab->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->id = id; - __entry->buf_len = buf_len; - memcpy(__get_dynamic_array(buf), buf, buf_len); -@@ -201,8 +201,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ab->dev)); -- __assign_str(driver, dev_driver_string(ab->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->id = id; - __entry->buf_len = buf_len; - memcpy(__get_dynamic_array(buf), buf, buf_len); -@@ -230,8 +230,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ab->dev)); -- __assign_str(driver, dev_driver_string(ab->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->level = level; - WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), - ATH11K_MSG_MAX, vaf->fmt, -@@ -262,10 +262,10 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ab->dev)); -- __assign_str(driver, dev_driver_string(ab->dev)); -- __assign_str(msg, msg); -- __assign_str(prefix, prefix); -+ __assign_str(device); -+ __assign_str(driver); -+ __assign_str(msg); -+ __assign_str(prefix); - __entry->buf_len = buf_len; - memcpy(__get_dynamic_array(buf), buf, buf_len); - ), -@@ -292,8 +292,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ab->dev)); -- __assign_str(driver, dev_driver_string(ab->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->len = len; - memcpy(__get_dynamic_array(data), data, len); - ), -@@ -318,8 +318,8 @@ - __field(u32, peer_ps_timestamp) - ), - -- TP_fast_assign(__assign_str(device, dev_name(ar->ab->dev)); -- __assign_str(driver, dev_driver_string(ar->ab->dev)); -+ TP_fast_assign(__assign_str(device); -+ __assign_str(driver); - memcpy(__get_dynamic_array(peer_addr), peer_addr, - ETH_ALEN); - __entry->peer_ps_state = peer_ps_state; ---- a/drivers/net/wireless/ath/ath12k/trace.h 2024-09-13 13:31:32.071704265 +0200 -+++ b/drivers/net/wireless/ath/ath12k/trace.h 2024-09-13 13:38:04.682139931 +0200 -@@ -36,8 +36,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->ab->dev)); -- __assign_str(driver, dev_driver_string(ar->ab->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->buf_len = buf_len; - __entry->pktlog_checksum = pktlog_checksum; - memcpy(__get_dynamic_array(pktlog), buf, buf_len); -@@ -73,8 +73,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->ab->dev)); -- __assign_str(driver, dev_driver_string(ar->ab->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->len = len; - __entry->info = ar->pdev->timestamp.info; - __entry->sync_tstmp_lo_us = ar->pdev->timestamp.sync_timestamp_hi_us; -@@ -117,8 +117,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ar->ab->dev)); -- __assign_str(driver, dev_driver_string(ar->ab->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->len = len; - __entry->type = type; - __entry->info = ar->pdev->timestamp.info; -@@ -153,8 +153,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, dev_name(ab->dev)); -- __assign_str(driver, dev_driver_string(ab->dev)); -+ __assign_str(device); -+ __assign_str(driver); - __entry->len = len; - memcpy(__get_dynamic_array(data), data, len); - ), ---- a/drivers/net/wireless/ath/ath6kl/trace.h 2024-09-13 13:31:32.079704151 +0200 -+++ b/drivers/net/wireless/ath/ath6kl/trace.h 2024-09-13 13:33:01.462437360 +0200 -@@ -304,8 +304,8 @@ - ), - - TP_fast_assign( -- __assign_str(msg, msg); -- __assign_str(prefix, prefix); -+ __assign_str(msg); -+ __assign_str(prefix); - __entry->buf_len = buf_len; - memcpy(__get_dynamic_array(buf), buf, buf_len); - ), ---- a/drivers/net/wireless/ath/trace.h 2024-09-13 13:31:32.043704662 +0200 -+++ b/drivers/net/wireless/ath/trace.h 2024-09-13 13:44:05.849032491 +0200 -@@ -44,8 +44,8 @@ - ), - - TP_fast_assign( -- __assign_str(device, wiphy_name(wiphy)); -- __assign_str(driver, KBUILD_MODNAME); -+ __assign_str(device); -+ __assign_str(driver); - __assign_vstr(msg, vaf->fmt, vaf->va); - ), - ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h 2024-09-13 13:31:31.999705285 +0200 -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h 2024-09-13 13:42:28.746405624 +0200 -@@ -41,7 +41,7 @@ - __vstring(msg, vaf->fmt, vaf->va) - ), - TP_fast_assign( -- __assign_str(func, func); -+ __assign_str(func); - __assign_vstr(msg, vaf->fmt, vaf->va); - ), - TP_printk("%s: %s", __get_str(func), __get_str(msg)) -@@ -57,7 +57,7 @@ - ), - TP_fast_assign( - __entry->level = level; -- __assign_str(func, func); -+ __assign_str(func); - __assign_vstr(msg, vaf->fmt, vaf->va); - ), - TP_printk("%s: %s", __get_str(func), __get_str(msg)) ---- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac.h 2024-09-13 13:31:32.011705114 +0200 -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac.h 2024-09-13 13:42:44.218186836 +0200 -@@ -81,7 +81,7 @@ - __field(u32, mask) - ), - TP_fast_assign( -- __assign_str(dev, dev_name(dev)); -+ __assign_str(dev); - __entry->in_isr = in_isr; - __entry->macintstatus = macintstatus; - __entry->mask = mask; ---- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac_msg.h 2024-09-13 13:31:32.011705114 +0200 -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac_msg.h 2024-09-13 13:42:52.242073370 +0200 -@@ -71,7 +71,7 @@ - ), - TP_fast_assign( - __entry->level = level; -- __assign_str(func, func); -+ __assign_str(func); - __assign_vstr(msg, vaf->fmt, vaf->va); - ), - TP_printk("%s: %s", __get_str(func), __get_str(msg)) ---- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac_tx.h 2024-09-13 13:31:32.011705114 +0200 -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac_tx.h 2024-09-13 13:43:12.721783766 +0200 -@@ -31,7 +31,7 @@ - __dynamic_array(u8, txh, txh_len) - ), - TP_fast_assign( -- __assign_str(dev, dev_name(dev)); -+ __assign_str(dev); - memcpy(__get_dynamic_array(txh), txh, txh_len); - ), - TP_printk("[%s] txdesc", __get_str(dev)) -@@ -54,7 +54,7 @@ - __field(u16, ackphyrxsh) - ), - TP_fast_assign( -- __assign_str(dev, dev_name(dev)); -+ __assign_str(dev); - __entry->framelen = framelen; - __entry->frameid = frameid; - __entry->status = status; -@@ -85,7 +85,7 @@ - __field(u16, dma_len) - ), - TP_fast_assign( -- __assign_str(dev, dev_name(dev)); -+ __assign_str(dev); - __entry->max_ampdu_len = max_ampdu_len; - __entry->max_ampdu_frames = max_ampdu_frames; - __entry->ampdu_len = ampdu_len; ---- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h 2024-09-13 13:31:31.915706475 +0200 -+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h 2024-09-13 13:41:47.314991509 +0200 -@@ -87,7 +87,7 @@ - #endif - - #define DEV_ENTRY __string(dev, dev_name(dev)) --#define DEV_ASSIGN __assign_str(dev, dev_name(dev)) -+#define DEV_ASSIGN __assign_str(dev) - - #include "iwl-devtrace-io.h" - #include "iwl-devtrace-ucode.h" ---- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-msg.h 2024-09-13 13:31:31.915706475 +0200 -+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-msg.h 2024-09-13 13:41:36.363146379 +0200 -@@ -57,7 +57,7 @@ - ), - TP_fast_assign( - __entry->level = level; -- __assign_str(function, function); -+ __assign_str(function); - __assign_vstr(msg, vaf->fmt, vaf->va); - ), - TP_printk("%s", __get_str(msg)) ---- a/include/trace/events/qrtr.h 2024-09-13 13:31:32.207702337 +0200 -+++ b/include/trace/events/qrtr.h 2024-09-13 13:39:51.068635354 +0200 -@@ -102,7 +102,7 @@ - ), - - TP_fast_assign( -- __assign_str(ctrl_pkt_str, ctrl_pkt_str); -+ __assign_str(ctrl_pkt_str); - __entry->sq_node = sq_node; - __entry->sq_port = sq_port; - ), diff --git a/6.12/target/linux/generic/backport-6.12/410-v6.13-01-block-add-support-for-defining-read-only-partitions.patch b/6.12/target/linux/generic/backport-6.12/410-v6.13-01-block-add-support-for-defining-read-only-partitions.patch index ffd65253..d40a483f 100644 --- a/6.12/target/linux/generic/backport-6.12/410-v6.13-01-block-add-support-for-defining-read-only-partitions.patch +++ b/6.12/target/linux/generic/backport-6.12/410-v6.13-01-block-add-support-for-defining-read-only-partitions.patch @@ -19,7 +19,7 @@ Signed-off-by: Jens Axboe --- a/block/blk.h +++ b/block/blk.h -@@ -564,6 +564,7 @@ void blk_free_ext_minor(unsigned int min +@@ -555,6 +555,7 @@ void blk_free_ext_minor(unsigned int min #define ADDPART_FLAG_NONE 0 #define ADDPART_FLAG_RAID 1 #define ADDPART_FLAG_WHOLEDISK 2 diff --git a/6.12/target/linux/generic/backport-6.12/410-v6.13-03-block-introduce-add_disk_fwnode.patch b/6.12/target/linux/generic/backport-6.12/410-v6.13-03-block-introduce-add_disk_fwnode.patch index 772584a9..8ed91047 100644 --- a/6.12/target/linux/generic/backport-6.12/410-v6.13-03-block-introduce-add_disk_fwnode.patch +++ b/6.12/target/linux/generic/backport-6.12/410-v6.13-03-block-introduce-add_disk_fwnode.patch @@ -82,7 +82,7 @@ Signed-off-by: Jens Axboe static void blk_report_disk_dead(struct gendisk *disk, bool surprise) --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h -@@ -735,6 +735,9 @@ static inline unsigned int blk_queue_dep +@@ -733,6 +733,9 @@ static inline unsigned int blk_queue_dep #define for_each_bio(_bio) \ for (; _bio; _bio = _bio->bi_next) diff --git a/6.12/target/linux/generic/backport-6.12/780-25-v6.13-r8169-remove-original-workaround-for-RTL8125-broken-.patch b/6.12/target/linux/generic/backport-6.12/780-25-v6.13-r8169-remove-original-workaround-for-RTL8125-broken-.patch new file mode 100644 index 00000000..46d41fb2 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-25-v6.13-r8169-remove-original-workaround-for-RTL8125-broken-.patch @@ -0,0 +1,33 @@ +From 854d71c555dfc3383c1fde7d9989b6046e21093d Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 9 Oct 2024 07:48:05 +0200 +Subject: [PATCH] r8169: remove original workaround for RTL8125 broken rx issue + +Now that we have b9c7ac4fe22c ("r8169: disable ALDPS per default for +RTL8125"), the first attempt to fix the issue shouldn't be needed +any longer. So let's effectively revert 621735f59064 ("r8169: fix +rare issue with broken rx after link-down on RTL8125") and see +whether anybody complains. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/382d8c88-cbce-400f-ad62-fda0181c7e38@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -4777,11 +4777,7 @@ static void r8169_phylink_handler(struct + if (netif_carrier_ok(ndev)) { + rtl_link_chg_patch(tp); + pm_request_resume(d); +- netif_wake_queue(tp->dev); + } else { +- /* In few cases rx is broken after link-down otherwise */ +- if (rtl_is_8125(tp)) +- rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE); + pm_runtime_idle(d); + } + diff --git a/6.12/target/linux/generic/backport-6.12/780-26-v6.13-r8169-enable-SG-TSO-on-selected-chip-versions-per-de.patch b/6.12/target/linux/generic/backport-6.12/780-26-v6.13-r8169-enable-SG-TSO-on-selected-chip-versions-per-de.patch new file mode 100644 index 00000000..5a27cc4b --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-26-v6.13-r8169-enable-SG-TSO-on-selected-chip-versions-per-de.patch @@ -0,0 +1,52 @@ +From b8bf38440ba94e8ed8e2ae55c5dfb0276d30e843 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 10 Oct 2024 12:58:02 +0200 +Subject: [PATCH] r8169: enable SG/TSO on selected chip versions per default + +Due to problem reports in the past SG and TSO/TSO6 are disabled per +default. It's not fully clear which chip versions are affected, so we +may impact also users of unaffected chip versions, unless they know +how to use ethtool for enabling SG/TSO/TSO6. +Vendor drivers r8168/r8125 enable SG/TSO/TSO6 for selected chip +versions per default, I'd interpret this as confirmation that these +chip versions are unaffected. So let's do the same here. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/realtek/r8169_main.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -5489,11 +5489,6 @@ static int rtl_init_one(struct pci_dev * + + dev->features |= dev->hw_features; + +- /* There has been a number of reports that using SG/TSO results in +- * tx timeouts. However for a lot of people SG/TSO works fine. +- * Therefore disable both features by default, but allow users to +- * enable them. Use at own risk! +- */ + if (rtl_chip_supports_csum_v2(tp)) { + dev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6; + netif_set_tso_max_size(dev, RTL_GSO_MAX_SIZE_V2); +@@ -5504,6 +5499,17 @@ static int rtl_init_one(struct pci_dev * + netif_set_tso_max_segs(dev, RTL_GSO_MAX_SEGS_V1); + } + ++ /* There has been a number of reports that using SG/TSO results in ++ * tx timeouts. However for a lot of people SG/TSO works fine. ++ * It's not fully clear which chip versions are affected. Vendor ++ * drivers enable SG/TSO for certain chip versions per default, ++ * let's mimic this here. On other chip versions users can ++ * use ethtool to enable SG/TSO, use at own risk! ++ */ ++ if (tp->mac_version >= RTL_GIGA_MAC_VER_46 && ++ tp->mac_version != RTL_GIGA_MAC_VER_61) ++ dev->features |= dev->hw_features; ++ + dev->hw_features |= NETIF_F_RXALL; + dev->hw_features |= NETIF_F_RXFCS; + diff --git a/6.12/target/linux/generic/backport-6.12/780-27-v6.13-r8169-implement-additional-ethtool-stats-ops.patch b/6.12/target/linux/generic/backport-6.12/780-27-v6.13-r8169-implement-additional-ethtool-stats-ops.patch new file mode 100644 index 00000000..bb0b77e6 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-27-v6.13-r8169-implement-additional-ethtool-stats-ops.patch @@ -0,0 +1,130 @@ +From e3fc5139bd8ffaa1498adc21be4e8ecbc6aed508 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sun, 13 Oct 2024 11:17:39 +0200 +Subject: [PATCH] r8169: implement additional ethtool stats ops + +This adds support for ethtool standard statistics, and makes use of the +extended hardware statistics being available from RTl8125. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/58e0da73-a7dd-4be3-82ae-d5b3f9069bde@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 82 +++++++++++++++++++++++ + 1 file changed, 82 insertions(+) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -2160,6 +2160,19 @@ static void rtl8169_get_ringparam(struct + data->tx_pending = NUM_TX_DESC; + } + ++static void rtl8169_get_pause_stats(struct net_device *dev, ++ struct ethtool_pause_stats *pause_stats) ++{ ++ struct rtl8169_private *tp = netdev_priv(dev); ++ ++ if (!rtl_is_8125(tp)) ++ return; ++ ++ rtl8169_update_counters(tp); ++ pause_stats->tx_pause_frames = le32_to_cpu(tp->counters->tx_pause_on); ++ pause_stats->rx_pause_frames = le32_to_cpu(tp->counters->rx_pause_on); ++} ++ + static void rtl8169_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *data) + { +@@ -2186,6 +2199,69 @@ static int rtl8169_set_pauseparam(struct + return 0; + } + ++static void rtl8169_get_eth_mac_stats(struct net_device *dev, ++ struct ethtool_eth_mac_stats *mac_stats) ++{ ++ struct rtl8169_private *tp = netdev_priv(dev); ++ ++ rtl8169_update_counters(tp); ++ ++ mac_stats->FramesTransmittedOK = ++ le64_to_cpu(tp->counters->tx_packets); ++ mac_stats->SingleCollisionFrames = ++ le32_to_cpu(tp->counters->tx_one_collision); ++ mac_stats->MultipleCollisionFrames = ++ le32_to_cpu(tp->counters->tx_multi_collision); ++ mac_stats->FramesReceivedOK = ++ le64_to_cpu(tp->counters->rx_packets); ++ mac_stats->AlignmentErrors = ++ le16_to_cpu(tp->counters->align_errors); ++ mac_stats->FramesLostDueToIntMACXmitError = ++ le64_to_cpu(tp->counters->tx_errors); ++ mac_stats->BroadcastFramesReceivedOK = ++ le64_to_cpu(tp->counters->rx_broadcast); ++ mac_stats->MulticastFramesReceivedOK = ++ le32_to_cpu(tp->counters->rx_multicast); ++ ++ if (!rtl_is_8125(tp)) ++ return; ++ ++ mac_stats->AlignmentErrors = ++ le32_to_cpu(tp->counters->align_errors32); ++ mac_stats->OctetsTransmittedOK = ++ le64_to_cpu(tp->counters->tx_octets); ++ mac_stats->LateCollisions = ++ le32_to_cpu(tp->counters->tx_late_collision); ++ mac_stats->FramesAbortedDueToXSColls = ++ le32_to_cpu(tp->counters->tx_aborted32); ++ mac_stats->OctetsReceivedOK = ++ le64_to_cpu(tp->counters->rx_octets); ++ mac_stats->FramesLostDueToIntMACRcvError = ++ le32_to_cpu(tp->counters->rx_mac_error); ++ mac_stats->MulticastFramesXmittedOK = ++ le64_to_cpu(tp->counters->tx_multicast64); ++ mac_stats->BroadcastFramesXmittedOK = ++ le64_to_cpu(tp->counters->tx_broadcast64); ++ mac_stats->MulticastFramesReceivedOK = ++ le64_to_cpu(tp->counters->rx_multicast64); ++ mac_stats->FrameTooLongErrors = ++ le32_to_cpu(tp->counters->rx_frame_too_long); ++} ++ ++static void rtl8169_get_eth_ctrl_stats(struct net_device *dev, ++ struct ethtool_eth_ctrl_stats *ctrl_stats) ++{ ++ struct rtl8169_private *tp = netdev_priv(dev); ++ ++ if (!rtl_is_8125(tp)) ++ return; ++ ++ rtl8169_update_counters(tp); ++ ++ ctrl_stats->UnsupportedOpcodesReceived = ++ le32_to_cpu(tp->counters->rx_unknown_opcode); ++} ++ + static const struct ethtool_ops rtl8169_ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | + ETHTOOL_COALESCE_MAX_FRAMES, +@@ -2207,8 +2283,11 @@ static const struct ethtool_ops rtl8169_ + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, + .get_ringparam = rtl8169_get_ringparam, ++ .get_pause_stats = rtl8169_get_pause_stats, + .get_pauseparam = rtl8169_get_pauseparam, + .set_pauseparam = rtl8169_set_pauseparam, ++ .get_eth_mac_stats = rtl8169_get_eth_mac_stats, ++ .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats, + }; + + static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) +@@ -3893,6 +3972,9 @@ static void rtl_hw_start_8125(struct rtl + break; + } + ++ /* enable extended tally counter */ ++ r8168_mac_ocp_modify(tp, 0xea84, 0, BIT(1) | BIT(0)); ++ + rtl_hw_config(tp); + } + diff --git a/6.12/target/linux/generic/backport-6.12/780-28-v6.13-r8169-don-t-take-RTNL-lock-in-rtl_task.patch b/6.12/target/linux/generic/backport-6.12/780-28-v6.13-r8169-don-t-take-RTNL-lock-in-rtl_task.patch new file mode 100644 index 00000000..77e7b432 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-28-v6.13-r8169-don-t-take-RTNL-lock-in-rtl_task.patch @@ -0,0 +1,50 @@ +From ac48430368c1a4f4e6c2fa92243b4b93fd25bee4 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 16 Oct 2024 22:05:57 +0200 +Subject: [PATCH] r8169: don't take RTNL lock in rtl_task() + +There's not really a benefit here in taking the RTNL lock. The task +handler does exception handling only, so we're in trouble anyway when +we come here, and there's no need to protect against e.g. a parallel +ethtool call. +A benefit of removing the RTNL lock here is that we now can +synchronously cancel the workqueue from a context holding the RTNL mutex. + +Signed-off-by: Heiner Kallweit +Signed-off-by: Andrew Lunn +--- + drivers/net/ethernet/realtek/r8169_main.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -4800,10 +4800,8 @@ static void rtl_task(struct work_struct + container_of(work, struct rtl8169_private, wk.work); + int ret; + +- rtnl_lock(); +- + if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) +- goto out_unlock; ++ return; + + if (test_and_clear_bit(RTL_FLAG_TASK_TX_TIMEOUT, tp->wk.flags)) { + /* if chip isn't accessible, reset bus to revive it */ +@@ -4812,7 +4810,7 @@ static void rtl_task(struct work_struct + if (ret < 0) { + netdev_err(tp->dev, "Can't reset secondary PCI bus, detach NIC\n"); + netif_device_detach(tp->dev); +- goto out_unlock; ++ return; + } + } + +@@ -4831,8 +4829,6 @@ reset: + } else if (test_and_clear_bit(RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, tp->wk.flags)) { + rtl_reset_work(tp); + } +-out_unlock: +- rtnl_unlock(); + } + + static int rtl8169_poll(struct napi_struct *napi, int budget) diff --git a/6.12/target/linux/generic/backport-6.12/780-30-v6.13-r8169-avoid-duplicated-messages-if-loading-firmware-.patch b/6.12/target/linux/generic/backport-6.12/780-30-v6.13-r8169-avoid-duplicated-messages-if-loading-firmware-.patch new file mode 100644 index 00000000..6430d322 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-30-v6.13-r8169-avoid-duplicated-messages-if-loading-firmware-.patch @@ -0,0 +1,41 @@ +From 1c105bacb160b5918e917ab811552b7be69fc69c Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 16 Oct 2024 22:29:39 +0200 +Subject: [PATCH] r8169: avoid duplicated messages if loading firmware fails + and switch to warn level + +In case of a problem with firmware loading we inform at the driver level, +in addition the firmware load code itself issues warnings. Therefore +switch to firmware_request_nowarn() to avoid duplicated error messages. +In addition switch to warn level because the firmware is optional and +typically just fixes compatibility issues. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Message-ID: +Signed-off-by: Andrew Lunn +--- + drivers/net/ethernet/realtek/r8169_firmware.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169_firmware.c ++++ b/drivers/net/ethernet/realtek/r8169_firmware.c +@@ -215,7 +215,7 @@ int rtl_fw_request_firmware(struct rtl_f + { + int rc; + +- rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev); ++ rc = firmware_request_nowarn(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev); + if (rc < 0) + goto out; + +@@ -227,7 +227,7 @@ int rtl_fw_request_firmware(struct rtl_f + + return 0; + out: +- dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n", +- rtl_fw->fw_name, rc); ++ dev_warn(rtl_fw->dev, "Unable to load firmware %s (%d)\n", ++ rtl_fw->fw_name, rc); + return rc; + } diff --git a/6.12/target/linux/generic/backport-6.12/780-31-v6.13-r8169-remove-rtl_dash_loop_wait_high-low.patch b/6.12/target/linux/generic/backport-6.12/780-31-v6.13-r8169-remove-rtl_dash_loop_wait_high-low.patch new file mode 100644 index 00000000..0c0e80c9 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-31-v6.13-r8169-remove-rtl_dash_loop_wait_high-low.patch @@ -0,0 +1,82 @@ +From d64113c6bb5ea5a70b7c9c3a6bcadef307638187 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 16 Oct 2024 22:31:10 +0200 +Subject: [PATCH] r8169: remove rtl_dash_loop_wait_high/low + +Remove rtl_dash_loop_wait_high/low to simplify the code. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Message-ID: +Signed-off-by: Andrew Lunn +--- + drivers/net/ethernet/realtek/r8169_main.c | 35 ++++++----------------- + 1 file changed, 8 insertions(+), 27 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -1346,40 +1346,19 @@ static void rtl8168ep_stop_cmac(struct r + RTL_W8(tp, IBCR0, RTL_R8(tp, IBCR0) & ~0x01); + } + +-static void rtl_dash_loop_wait(struct rtl8169_private *tp, +- const struct rtl_cond *c, +- unsigned long usecs, int n, bool high) +-{ +- if (!tp->dash_enabled) +- return; +- rtl_loop_wait(tp, c, usecs, n, high); +-} +- +-static void rtl_dash_loop_wait_high(struct rtl8169_private *tp, +- const struct rtl_cond *c, +- unsigned long d, int n) +-{ +- rtl_dash_loop_wait(tp, c, d, n, true); +-} +- +-static void rtl_dash_loop_wait_low(struct rtl8169_private *tp, +- const struct rtl_cond *c, +- unsigned long d, int n) +-{ +- rtl_dash_loop_wait(tp, c, d, n, false); +-} +- + static void rtl8168dp_driver_start(struct rtl8169_private *tp) + { + r8168dp_oob_notify(tp, OOB_CMD_DRIVER_START); +- rtl_dash_loop_wait_high(tp, &rtl_dp_ocp_read_cond, 10000, 10); ++ if (tp->dash_enabled) ++ rtl_loop_wait_high(tp, &rtl_dp_ocp_read_cond, 10000, 10); + } + + static void rtl8168ep_driver_start(struct rtl8169_private *tp) + { + r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_START); + r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01); +- rtl_dash_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30); ++ if (tp->dash_enabled) ++ rtl_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30); + } + + static void rtl8168_driver_start(struct rtl8169_private *tp) +@@ -1393,7 +1372,8 @@ static void rtl8168_driver_start(struct + static void rtl8168dp_driver_stop(struct rtl8169_private *tp) + { + r8168dp_oob_notify(tp, OOB_CMD_DRIVER_STOP); +- rtl_dash_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10); ++ if (tp->dash_enabled) ++ rtl_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10); + } + + static void rtl8168ep_driver_stop(struct rtl8169_private *tp) +@@ -1401,7 +1381,8 @@ static void rtl8168ep_driver_stop(struct + rtl8168ep_stop_cmac(tp); + r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_STOP); + r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01); +- rtl_dash_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10); ++ if (tp->dash_enabled) ++ rtl_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10); + } + + static void rtl8168_driver_stop(struct rtl8169_private *tp) diff --git a/6.12/target/linux/generic/backport-6.12/780-32-v6.13-r8169-enable-EEE-at-2.5G-per-default-on-RTL8125B.patch b/6.12/target/linux/generic/backport-6.12/780-32-v6.13-r8169-enable-EEE-at-2.5G-per-default-on-RTL8125B.patch new file mode 100644 index 00000000..4ec06cc6 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-32-v6.13-r8169-enable-EEE-at-2.5G-per-default-on-RTL8125B.patch @@ -0,0 +1,28 @@ +From c4e64095c00cb2de413cd6b90be047c273bcd491 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 17 Oct 2024 22:27:44 +0200 +Subject: [PATCH] r8169: enable EEE at 2.5G per default on RTL8125B + +Register a6d/12 is shadowing register MDIO_AN_EEE_ADV2. So this line +disables advertisement of EEE at 2.5G. Latest vendor driver r8125 +doesn't do this (any longer?), so this mode seems to be safe. +EEE saves quite some energy, therefore enable this mode per default. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Message-ID: <95dd5a0c-09ea-4847-94d9-b7aa3063e8ff@gmail.com> +Signed-off-by: Andrew Lunn +--- + drivers/net/ethernet/realtek/r8169_phy_config.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -99,7 +99,6 @@ static void rtl8125a_config_eee_phy(stru + + static void rtl8125b_config_eee_phy(struct phy_device *phydev) + { +- phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000); + phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); + phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000); + phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); diff --git a/6.12/target/linux/generic/backport-6.12/780-33-v6.13-r8169-add-support-for-RTL8125D.patch b/6.12/target/linux/generic/backport-6.12/780-33-v6.13-r8169-add-support-for-RTL8125D.patch new file mode 100644 index 00000000..1c322795 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-33-v6.13-r8169-add-support-for-RTL8125D.patch @@ -0,0 +1,143 @@ +From f75d1fbe7809bc5ed134204b920fd9e2fc5db1df Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 24 Oct 2024 22:42:33 +0200 +Subject: [PATCH] r8169: add support for RTL8125D + +This adds support for new chip version RTL8125D, which can be found on +boards like Gigabyte X870E AORUS ELITE WIFI7. Firmware rtl8125d-1.fw +for this chip version is available in linux-firmware already. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/d0306912-e88e-4c25-8b5d-545ae8834c0c@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169.h | 1 + + drivers/net/ethernet/realtek/r8169_main.c | 23 +++++++++++++------ + .../net/ethernet/realtek/r8169_phy_config.c | 10 ++++++++ + 3 files changed, 27 insertions(+), 7 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -68,6 +68,7 @@ enum mac_version { + /* support for RTL_GIGA_MAC_VER_60 has been removed */ + RTL_GIGA_MAC_VER_61, + RTL_GIGA_MAC_VER_63, ++ RTL_GIGA_MAC_VER_64, + RTL_GIGA_MAC_VER_65, + RTL_GIGA_MAC_VER_66, + RTL_GIGA_MAC_NONE +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -55,6 +55,7 @@ + #define FIRMWARE_8107E_2 "rtl_nic/rtl8107e-2.fw" + #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw" + #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" ++#define FIRMWARE_8125D_1 "rtl_nic/rtl8125d-1.fw" + #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw" + #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw" + +@@ -138,6 +139,7 @@ static const struct { + [RTL_GIGA_MAC_VER_61] = {"RTL8125A", FIRMWARE_8125A_3}, + /* reserve 62 for CFG_METHOD_4 in the vendor driver */ + [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, ++ [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1}, + [RTL_GIGA_MAC_VER_65] = {"RTL8126A", FIRMWARE_8126A_2}, + [RTL_GIGA_MAC_VER_66] = {"RTL8126A", FIRMWARE_8126A_3}, + }; +@@ -707,6 +709,7 @@ MODULE_FIRMWARE(FIRMWARE_8168FP_3); + MODULE_FIRMWARE(FIRMWARE_8107E_2); + MODULE_FIRMWARE(FIRMWARE_8125A_3); + MODULE_FIRMWARE(FIRMWARE_8125B_2); ++MODULE_FIRMWARE(FIRMWARE_8125D_1); + MODULE_FIRMWARE(FIRMWARE_8126A_2); + MODULE_FIRMWARE(FIRMWARE_8126A_3); + +@@ -2079,10 +2082,7 @@ static void rtl_set_eee_txidle_timer(str + tp->tx_lpi_timer = timer_val; + r8168_mac_ocp_write(tp, 0xe048, timer_val); + break; +- case RTL_GIGA_MAC_VER_61: +- case RTL_GIGA_MAC_VER_63: +- case RTL_GIGA_MAC_VER_65: +- case RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: + tp->tx_lpi_timer = timer_val; + RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val); + break; +@@ -2293,6 +2293,9 @@ static enum mac_version rtl8169_get_mac_ + { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_66 }, + { 0x7cf, 0x649, RTL_GIGA_MAC_VER_65 }, + ++ /* 8125D family. */ ++ { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 }, ++ + /* 8125B family. */ + { 0x7cf, 0x641, RTL_GIGA_MAC_VER_63 }, + +@@ -2560,9 +2563,7 @@ static void rtl_init_rxcfg(struct rtl816 + case RTL_GIGA_MAC_VER_61: + RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST); + break; +- case RTL_GIGA_MAC_VER_63: +- case RTL_GIGA_MAC_VER_65: +- case RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_66: + RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST | + RX_PAUSE_SLOT_ON); + break; +@@ -3874,6 +3875,12 @@ static void rtl_hw_start_8125b(struct rt + rtl_hw_start_8125_common(tp); + } + ++static void rtl_hw_start_8125d(struct rtl8169_private *tp) ++{ ++ rtl_set_def_aspm_entry_latency(tp); ++ rtl_hw_start_8125_common(tp); ++} ++ + static void rtl_hw_start_8126a(struct rtl8169_private *tp) + { + rtl_set_def_aspm_entry_latency(tp); +@@ -3922,6 +3929,7 @@ static void rtl_hw_config(struct rtl8169 + [RTL_GIGA_MAC_VER_53] = rtl_hw_start_8117, + [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, + [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, ++ [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8126a, + [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8126a, + }; +@@ -3939,6 +3947,7 @@ static void rtl_hw_start_8125(struct rtl + /* disable interrupt coalescing */ + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_61: ++ case RTL_GIGA_MAC_VER_64: + for (i = 0xa00; i < 0xb00; i += 4) + RTL_W32(tp, i, 0); + break; +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1103,6 +1103,15 @@ static void rtl8125b_hw_phy_config(struc + rtl8125b_config_eee_phy(phydev); + } + ++static void rtl8125d_hw_phy_config(struct rtl8169_private *tp, ++ struct phy_device *phydev) ++{ ++ r8169_apply_firmware(tp); ++ rtl8125_legacy_force_mode(phydev); ++ rtl8168g_disable_aldps(phydev); ++ rtl8125b_config_eee_phy(phydev); ++} ++ + static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) + { +@@ -1159,6 +1168,7 @@ void r8169_hw_phy_config(struct rtl8169_ + [RTL_GIGA_MAC_VER_53] = rtl8117_hw_phy_config, + [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, + [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, ++ [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, + [RTL_GIGA_MAC_VER_65] = rtl8126a_hw_phy_config, + [RTL_GIGA_MAC_VER_66] = rtl8126a_hw_phy_config, + }; diff --git a/6.12/target/linux/generic/backport-6.12/780-34-v6.13-r8169-fix-inconsistent-indenting-in-rtl8169_get_eth_.patch b/6.12/target/linux/generic/backport-6.12/780-34-v6.13-r8169-fix-inconsistent-indenting-in-rtl8169_get_eth_.patch new file mode 100644 index 00000000..5ab37cb1 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-34-v6.13-r8169-fix-inconsistent-indenting-in-rtl8169_get_eth_.patch @@ -0,0 +1,30 @@ +From b8bd8c44a266c9a7dcb907eab10fbb119e3f6494 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 24 Oct 2024 22:48:59 +0200 +Subject: [PATCH] r8169: fix inconsistent indenting in + rtl8169_get_eth_mac_stats + +This fixes an inconsistent indenting introduced with e3fc5139bd8f +("r8169: implement additional ethtool stats ops"). + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202410220413.1gAxIJ4t-lkp@intel.com/ +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20fd6f39-3c1b-4af0-9adc-7d1f49728fad@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -2225,7 +2225,7 @@ static void rtl8169_get_eth_mac_stats(st + le64_to_cpu(tp->counters->tx_broadcast64); + mac_stats->MulticastFramesReceivedOK = + le64_to_cpu(tp->counters->rx_multicast64); +- mac_stats->FrameTooLongErrors = ++ mac_stats->FrameTooLongErrors = + le32_to_cpu(tp->counters->rx_frame_too_long); + } + diff --git a/6.12/target/linux/generic/backport-6.12/780-35-v6.13-r8169-align-RTL8125-EEE-config-with-vendor-driver.patch b/6.12/target/linux/generic/backport-6.12/780-35-v6.13-r8169-align-RTL8125-EEE-config-with-vendor-driver.patch new file mode 100644 index 00000000..de2be016 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-35-v6.13-r8169-align-RTL8125-EEE-config-with-vendor-driver.patch @@ -0,0 +1,49 @@ +From eb90f876b7961d702d7fc549e14614860f531e60 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 31 Oct 2024 22:42:52 +0100 +Subject: [PATCH] r8169: align RTL8125 EEE config with vendor driver + +Align the EEE config for RTL8125A/RTL8125B with vendor driver r8125. +This should help to avoid compatibility issues. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/044c925e-8669-4b98-87df-95b4056f4f5f@gmail.com +Signed-off-by: Jakub Kicinski +--- + .../net/ethernet/realtek/r8169_phy_config.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -89,19 +89,25 @@ static void rtl8168h_config_eee_phy(stru + phy_modify_paged(phydev, 0xa42, 0x14, 0x0000, 0x0080); + } + +-static void rtl8125a_config_eee_phy(struct phy_device *phydev) ++static void rtl8125_common_config_eee_phy(struct phy_device *phydev) + { +- rtl8168h_config_eee_phy(phydev); ++ phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); ++ phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000); ++ phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); ++} + ++static void rtl8125a_config_eee_phy(struct phy_device *phydev) ++{ ++ rtl8168g_config_eee_phy(phydev); ++ /* disable EEE at 2.5Gbps */ + phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000); +- phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); ++ rtl8125_common_config_eee_phy(phydev); + } + + static void rtl8125b_config_eee_phy(struct phy_device *phydev) + { +- phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); +- phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000); +- phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); ++ rtl8168g_config_eee_phy(phydev); ++ rtl8125_common_config_eee_phy(phydev); + } + + static void rtl8169s_hw_phy_config(struct rtl8169_private *tp, diff --git a/6.12/target/linux/generic/backport-6.12/780-36-v6.13-r8169-align-RTL8125-RTL8126-PHY-config-with-vendor-d.patch b/6.12/target/linux/generic/backport-6.12/780-36-v6.13-r8169-align-RTL8125-RTL8126-PHY-config-with-vendor-d.patch new file mode 100644 index 00000000..a546c426 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-36-v6.13-r8169-align-RTL8125-RTL8126-PHY-config-with-vendor-d.patch @@ -0,0 +1,46 @@ +From 4af2f60bf7378bd5c92b15a528d8c6c7d02bed6c Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 31 Oct 2024 22:43:45 +0100 +Subject: [PATCH] r8169: align RTL8125/RTL8126 PHY config with vendor driver + +This aligns some parameters with vendor driver r8125/r8126 to avoid +compatibility issues. Note that for RTL8125B there's no functional +change, just the open-coded version of the function is replaced. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/a8a9d896-fbe6-41f2-bf87-666567d3cdb3@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_phy_config.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1073,8 +1073,8 @@ static void rtl8125b_hw_phy_config(struc + struct phy_device *phydev) + { + r8169_apply_firmware(tp); ++ rtl8168g_enable_gphy_10m(phydev); + +- phy_modify_paged(phydev, 0xa44, 0x11, 0x0000, 0x0800); + phy_modify_paged(phydev, 0xac4, 0x13, 0x00f0, 0x0090); + phy_modify_paged(phydev, 0xad3, 0x10, 0x0003, 0x0001); + +@@ -1113,6 +1113,7 @@ static void rtl8125d_hw_phy_config(struc + struct phy_device *phydev) + { + r8169_apply_firmware(tp); ++ rtl8168g_enable_gphy_10m(phydev); + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); + rtl8125b_config_eee_phy(phydev); +@@ -1122,6 +1123,9 @@ static void rtl8126a_hw_phy_config(struc + struct phy_device *phydev) + { + r8169_apply_firmware(tp); ++ rtl8168g_enable_gphy_10m(phydev); ++ rtl8125_legacy_force_mode(phydev); ++ rtl8168g_disable_aldps(phydev); + } + + void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, diff --git a/6.12/target/linux/generic/backport-6.12/780-37-v6.13-r8169-align-RTL8126-EEE-config-with-vendor-driver.patch b/6.12/target/linux/generic/backport-6.12/780-37-v6.13-r8169-align-RTL8126-EEE-config-with-vendor-driver.patch new file mode 100644 index 00000000..36c8041c --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-37-v6.13-r8169-align-RTL8126-EEE-config-with-vendor-driver.patch @@ -0,0 +1,25 @@ +From a3d8520e6a19ab018da6c7fc22512c913697a829 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 31 Oct 2024 22:44:36 +0100 +Subject: [PATCH] r8169: align RTL8126 EEE config with vendor driver + +Align the EEE config for RTL8126A with vendor driver r8126 to avoid +compatibility issues. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/71e4859e-4cd0-4b6b-b7fa-621d7721992f@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_phy_config.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1126,6 +1126,7 @@ static void rtl8126a_hw_phy_config(struc + rtl8168g_enable_gphy_10m(phydev); + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); ++ rtl8125_common_config_eee_phy(phydev); + } + + void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, diff --git a/6.12/target/linux/generic/backport-6.12/780-38-v6.13-r8169-improve-initialization-of-RSS-registers-on-RTL.patch b/6.12/target/linux/generic/backport-6.12/780-38-v6.13-r8169-improve-initialization-of-RSS-registers-on-RTL.patch new file mode 100644 index 00000000..95e126f1 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-38-v6.13-r8169-improve-initialization-of-RSS-registers-on-RTL.patch @@ -0,0 +1,38 @@ +From 2cd02f2fdd8a92e5b6b85ff64eab0fc549b30c07 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 2 Nov 2024 14:49:01 +0100 +Subject: [PATCH] r8169: improve initialization of RSS registers on + RTL8125/RTL8126 + +Replace the register addresses with the names used in r8125/r8126 +vendor driver, and consider that RSS_CTRL_8125 is a 32 bit register. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/3bf2f340-b369-4174-97bf-fd38d4217492@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -346,6 +346,8 @@ enum rtl8125_registers { + TxPoll_8125 = 0x90, + LEDSEL3 = 0x96, + MAC0_BKP = 0x19e0, ++ RSS_CTRL_8125 = 0x4500, ++ Q_NUM_CTRL_8125 = 0x4800, + EEE_TXIDLE_TIMER_8125 = 0x6048, + }; + +@@ -3768,8 +3770,8 @@ static void rtl_hw_start_8125_common(str + rtl_pcie_state_l2l3_disable(tp); + + RTL_W16(tp, 0x382, 0x221b); +- RTL_W8(tp, 0x4500, 0); +- RTL_W16(tp, 0x4800, 0); ++ RTL_W32(tp, RSS_CTRL_8125, 0); ++ RTL_W16(tp, Q_NUM_CTRL_8125, 0); + + /* disable UPS */ + r8168_mac_ocp_modify(tp, 0xd40a, 0x0010, 0x0000); diff --git a/6.12/target/linux/generic/backport-6.12/780-39-v6.13-r8169-remove-leftover-locks-after-reverted-change.patch b/6.12/target/linux/generic/backport-6.12/780-39-v6.13-r8169-remove-leftover-locks-after-reverted-change.patch new file mode 100644 index 00000000..43515de4 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-39-v6.13-r8169-remove-leftover-locks-after-reverted-change.patch @@ -0,0 +1,113 @@ +From 83cb4b470c66b37b19a347a35cea01e0cbdd258d Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Mon, 4 Nov 2024 23:16:20 +0100 +Subject: [PATCH] r8169: remove leftover locks after reverted change + +After e31a9fedc7d8 ("Revert "r8169: disable ASPM during NAPI poll"") +these locks aren't needed any longer. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/680f2606-ac7d-4ced-8694-e5033855da9b@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 29 ++--------------------- + 1 file changed, 2 insertions(+), 27 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -662,13 +662,9 @@ struct rtl8169_private { + struct work_struct work; + } wk; + +- raw_spinlock_t config25_lock; + raw_spinlock_t mac_ocp_lock; + struct mutex led_lock; /* serialize LED ctrl RMW access */ + +- raw_spinlock_t cfg9346_usage_lock; +- int cfg9346_usage_count; +- + unsigned supports_gmii:1; + unsigned aspm_manageable:1; + unsigned dash_enabled:1; +@@ -722,22 +718,12 @@ static inline struct device *tp_to_dev(s + + static void rtl_lock_config_regs(struct rtl8169_private *tp) + { +- unsigned long flags; +- +- raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags); +- if (!--tp->cfg9346_usage_count) +- RTL_W8(tp, Cfg9346, Cfg9346_Lock); +- raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags); ++ RTL_W8(tp, Cfg9346, Cfg9346_Lock); + } + + static void rtl_unlock_config_regs(struct rtl8169_private *tp) + { +- unsigned long flags; +- +- raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags); +- if (!tp->cfg9346_usage_count++) +- RTL_W8(tp, Cfg9346, Cfg9346_Unlock); +- raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags); ++ RTL_W8(tp, Cfg9346, Cfg9346_Unlock); + } + + static void rtl_pci_commit(struct rtl8169_private *tp) +@@ -748,24 +734,18 @@ static void rtl_pci_commit(struct rtl816 + + static void rtl_mod_config2(struct rtl8169_private *tp, u8 clear, u8 set) + { +- unsigned long flags; + u8 val; + +- raw_spin_lock_irqsave(&tp->config25_lock, flags); + val = RTL_R8(tp, Config2); + RTL_W8(tp, Config2, (val & ~clear) | set); +- raw_spin_unlock_irqrestore(&tp->config25_lock, flags); + } + + static void rtl_mod_config5(struct rtl8169_private *tp, u8 clear, u8 set) + { +- unsigned long flags; + u8 val; + +- raw_spin_lock_irqsave(&tp->config25_lock, flags); + val = RTL_R8(tp, Config5); + RTL_W8(tp, Config5, (val & ~clear) | set); +- raw_spin_unlock_irqrestore(&tp->config25_lock, flags); + } + + static bool rtl_is_8125(struct rtl8169_private *tp) +@@ -1571,7 +1551,6 @@ static void __rtl8169_set_wol(struct rtl + { WAKE_MAGIC, Config3, MagicPacket } + }; + unsigned int i, tmp = ARRAY_SIZE(cfg); +- unsigned long flags; + u8 options; + + rtl_unlock_config_regs(tp); +@@ -1590,14 +1569,12 @@ static void __rtl8169_set_wol(struct rtl + r8168_mac_ocp_modify(tp, 0xc0b6, BIT(0), 0); + } + +- raw_spin_lock_irqsave(&tp->config25_lock, flags); + for (i = 0; i < tmp; i++) { + options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask; + if (wolopts & cfg[i].opt) + options |= cfg[i].mask; + RTL_W8(tp, cfg[i].reg, options); + } +- raw_spin_unlock_irqrestore(&tp->config25_lock, flags); + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: +@@ -5458,8 +5435,6 @@ static int rtl_init_one(struct pci_dev * + tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1; + tp->ocp_base = OCP_STD_PHY_BASE; + +- raw_spin_lock_init(&tp->cfg9346_usage_lock); +- raw_spin_lock_init(&tp->config25_lock); + raw_spin_lock_init(&tp->mac_ocp_lock); + mutex_init(&tp->led_lock); + diff --git a/6.12/target/linux/generic/backport-6.12/780-40-v6.13-r8169-improve-__rtl8169_set_wol.patch b/6.12/target/linux/generic/backport-6.12/780-40-v6.13-r8169-improve-__rtl8169_set_wol.patch new file mode 100644 index 00000000..e468d637 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-40-v6.13-r8169-improve-__rtl8169_set_wol.patch @@ -0,0 +1,108 @@ +From c507e96b5763b36b63ad50ad804341f72ea000e4 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 6 Nov 2024 17:55:45 +0100 +Subject: [PATCH] r8169: improve __rtl8169_set_wol + +Add helper r8169_mod_reg8_cond() what allows to significantly simplify +__rtl8169_set_wol(). + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/697b197a-8eac-40c6-8847-27093cacec36@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 55 ++++++++++------------- + 1 file changed, 24 insertions(+), 31 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -748,6 +748,20 @@ static void rtl_mod_config5(struct rtl81 + RTL_W8(tp, Config5, (val & ~clear) | set); + } + ++static void r8169_mod_reg8_cond(struct rtl8169_private *tp, int reg, ++ u8 bits, bool cond) ++{ ++ u8 val, old_val; ++ ++ old_val = RTL_R8(tp, reg); ++ if (cond) ++ val = old_val | bits; ++ else ++ val = old_val & ~bits; ++ if (val != old_val) ++ RTL_W8(tp, reg, val); ++} ++ + static bool rtl_is_8125(struct rtl8169_private *tp) + { + return tp->mac_version >= RTL_GIGA_MAC_VER_61; +@@ -1538,58 +1552,37 @@ static void rtl8169_get_wol(struct net_d + + static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) + { +- static const struct { +- u32 opt; +- u16 reg; +- u8 mask; +- } cfg[] = { +- { WAKE_PHY, Config3, LinkUp }, +- { WAKE_UCAST, Config5, UWF }, +- { WAKE_BCAST, Config5, BWF }, +- { WAKE_MCAST, Config5, MWF }, +- { WAKE_ANY, Config5, LanWake }, +- { WAKE_MAGIC, Config3, MagicPacket } +- }; +- unsigned int i, tmp = ARRAY_SIZE(cfg); +- u8 options; +- + rtl_unlock_config_regs(tp); + + if (rtl_is_8168evl_up(tp)) { +- tmp--; + if (wolopts & WAKE_MAGIC) + rtl_eri_set_bits(tp, 0x0dc, MagicPacket_v2); + else + rtl_eri_clear_bits(tp, 0x0dc, MagicPacket_v2); + } else if (rtl_is_8125(tp)) { +- tmp--; + if (wolopts & WAKE_MAGIC) + r8168_mac_ocp_modify(tp, 0xc0b6, 0, BIT(0)); + else + r8168_mac_ocp_modify(tp, 0xc0b6, BIT(0), 0); ++ } else { ++ r8169_mod_reg8_cond(tp, Config3, MagicPacket, ++ wolopts & WAKE_MAGIC); + } + +- for (i = 0; i < tmp; i++) { +- options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask; +- if (wolopts & cfg[i].opt) +- options |= cfg[i].mask; +- RTL_W8(tp, cfg[i].reg, options); +- } ++ r8169_mod_reg8_cond(tp, Config3, LinkUp, wolopts & WAKE_PHY); ++ r8169_mod_reg8_cond(tp, Config5, UWF, wolopts & WAKE_UCAST); ++ r8169_mod_reg8_cond(tp, Config5, BWF, wolopts & WAKE_BCAST); ++ r8169_mod_reg8_cond(tp, Config5, MWF, wolopts & WAKE_MCAST); ++ r8169_mod_reg8_cond(tp, Config5, LanWake, wolopts); + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: +- options = RTL_R8(tp, Config1) & ~PMEnable; +- if (wolopts) +- options |= PMEnable; +- RTL_W8(tp, Config1, options); ++ r8169_mod_reg8_cond(tp, Config1, PMEnable, wolopts); + break; + case RTL_GIGA_MAC_VER_34: + case RTL_GIGA_MAC_VER_37: + case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66: +- if (wolopts) +- rtl_mod_config2(tp, 0, PME_SIGNAL); +- else +- rtl_mod_config2(tp, PME_SIGNAL, 0); ++ r8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts); + break; + default: + break; diff --git a/6.12/target/linux/generic/backport-6.12/780-41-v6.13-r8169-improve-rtl_set_d3_pll_down.patch b/6.12/target/linux/generic/backport-6.12/780-41-v6.13-r8169-improve-rtl_set_d3_pll_down.patch new file mode 100644 index 00000000..aeafebb2 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-41-v6.13-r8169-improve-rtl_set_d3_pll_down.patch @@ -0,0 +1,44 @@ +From 330dc2297c82953dff402e0b4176a5383a618538 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 6 Nov 2024 17:56:28 +0100 +Subject: [PATCH] r8169: improve rtl_set_d3_pll_down + +Make use of new helper r8169_mod_reg8_cond() and move from a switch() +to an if() clause. Benefit is that we don't have to touch this piece of +code each time support for a new chip version is added. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/e1ccdb85-a4ed-4800-89c2-89770ff06452@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 18 +++++------------- + 1 file changed, 5 insertions(+), 13 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -1431,19 +1431,11 @@ static enum rtl_dash_type rtl_get_dash_t + + static void rtl_set_d3_pll_down(struct rtl8169_private *tp, bool enable) + { +- switch (tp->mac_version) { +- case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26: +- case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30: +- case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_37: +- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66: +- if (enable) +- RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~D3_NO_PLL_DOWN); +- else +- RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | D3_NO_PLL_DOWN); +- break; +- default: +- break; +- } ++ if (tp->mac_version >= RTL_GIGA_MAC_VER_25 && ++ tp->mac_version != RTL_GIGA_MAC_VER_28 && ++ tp->mac_version != RTL_GIGA_MAC_VER_31 && ++ tp->mac_version != RTL_GIGA_MAC_VER_38) ++ r8169_mod_reg8_cond(tp, PMCH, D3_NO_PLL_DOWN, !enable); + } + + static void rtl_reset_packet_filter(struct rtl8169_private *tp) diff --git a/6.12/target/linux/generic/backport-6.12/780-42-v6.13-r8169-align-WAKE_PHY-handling-with-r8125-r8126-vendo.patch b/6.12/target/linux/generic/backport-6.12/780-42-v6.13-r8169-align-WAKE_PHY-handling-with-r8125-r8126-vendo.patch new file mode 100644 index 00000000..26c362dd --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-42-v6.13-r8169-align-WAKE_PHY-handling-with-r8125-r8126-vendo.patch @@ -0,0 +1,29 @@ +From e3e9e9039fa6ae885c7d5c954d7b9f105fa23e8f Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 6 Nov 2024 17:57:08 +0100 +Subject: [PATCH] r8169: align WAKE_PHY handling with r8125/r8126 vendor + drivers + +Vendor drivers r8125/r8126 apply this additional magic setting when +enabling WAKE_PHY, so do the same here. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/51130715-45be-4db5-abb7-05d87e1f5df9@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -1562,6 +1562,9 @@ static void __rtl8169_set_wol(struct rtl + } + + r8169_mod_reg8_cond(tp, Config3, LinkUp, wolopts & WAKE_PHY); ++ if (rtl_is_8125(tp)) ++ r8168_mac_ocp_modify(tp, 0xe0c6, 0x3f, ++ wolopts & WAKE_PHY ? 0x13 : 0); + r8169_mod_reg8_cond(tp, Config5, UWF, wolopts & WAKE_UCAST); + r8169_mod_reg8_cond(tp, Config5, BWF, wolopts & WAKE_BCAST); + r8169_mod_reg8_cond(tp, Config5, MWF, wolopts & WAKE_MCAST); diff --git a/6.12/target/linux/generic/backport-6.12/780-43-v6.13-r8169-use-helper-r8169_mod_reg8_cond-to-simplify-rtl.patch b/6.12/target/linux/generic/backport-6.12/780-43-v6.13-r8169-use-helper-r8169_mod_reg8_cond-to-simplify-rtl.patch new file mode 100644 index 00000000..4bb0a941 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-43-v6.13-r8169-use-helper-r8169_mod_reg8_cond-to-simplify-rtl.patch @@ -0,0 +1,117 @@ +From 7a3bcd39ae1f0e3ab896d9df62339ab4297a0bfd Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 9 Nov 2024 23:12:12 +0100 +Subject: [PATCH] r8169: use helper r8169_mod_reg8_cond to simplify + rtl_jumbo_config + +Use recently added helper r8169_mod_reg8_cond() to simplify jumbo +mode configuration. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/3df1d484-a02e-46e7-8f75-db5b428e422e@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 77 ++++------------------- + 1 file changed, 11 insertions(+), 66 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -2545,86 +2545,31 @@ static void rtl8169_init_ring_indexes(st + tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0; + } + +-static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); +- RTL_W8(tp, Config4, RTL_R8(tp, Config4) | Jumbo_En1); +-} +- +-static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); +- RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~Jumbo_En1); +-} +- +-static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); +-} +- +-static void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); +-} +- +-static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, MaxTxPacketSize, 0x24); +- RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); +- RTL_W8(tp, Config4, RTL_R8(tp, Config4) | 0x01); +-} +- +-static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, MaxTxPacketSize, 0x3f); +- RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); +- RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~0x01); +-} +- +-static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, Config4, RTL_R8(tp, Config4) | (1 << 0)); +-} +- +-static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0)); +-} +- + static void rtl_jumbo_config(struct rtl8169_private *tp) + { + bool jumbo = tp->dev->mtu > ETH_DATA_LEN; + int readrq = 4096; + ++ if (jumbo && tp->mac_version >= RTL_GIGA_MAC_VER_17 && ++ tp->mac_version <= RTL_GIGA_MAC_VER_26) ++ readrq = 512; ++ + rtl_unlock_config_regs(tp); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_17: +- if (jumbo) { +- readrq = 512; +- r8168b_1_hw_jumbo_enable(tp); +- } else { +- r8168b_1_hw_jumbo_disable(tp); +- } ++ r8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo); + break; + case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26: +- if (jumbo) { +- readrq = 512; +- r8168c_hw_jumbo_enable(tp); +- } else { +- r8168c_hw_jumbo_disable(tp); +- } ++ r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); ++ r8169_mod_reg8_cond(tp, Config4, Jumbo_En1, jumbo); + break; + case RTL_GIGA_MAC_VER_28: +- if (jumbo) +- r8168dp_hw_jumbo_enable(tp); +- else +- r8168dp_hw_jumbo_disable(tp); ++ r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); + break; + case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33: +- if (jumbo) +- r8168e_hw_jumbo_enable(tp); +- else +- r8168e_hw_jumbo_disable(tp); ++ RTL_W8(tp, MaxTxPacketSize, jumbo ? 0x24 : 0x3f); ++ r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); ++ r8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo); + break; + default: + break; diff --git a/6.12/target/linux/generic/backport-6.12/780-44-v6.13-r8169-copy-vendor-driver-2.5G-5G-EEE-advertisement-c.patch b/6.12/target/linux/generic/backport-6.12/780-44-v6.13-r8169-copy-vendor-driver-2.5G-5G-EEE-advertisement-c.patch new file mode 100644 index 00000000..9bdbaf27 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-44-v6.13-r8169-copy-vendor-driver-2.5G-5G-EEE-advertisement-c.patch @@ -0,0 +1,82 @@ +From e340bff27e63ed61a1e9895bed546107859e48a7 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Fri, 8 Nov 2024 08:08:24 +0100 +Subject: [PATCH] r8169: copy vendor driver 2.5G/5G EEE advertisement + constraints + +Vendor driver r8125 doesn't advertise 2.5G EEE on RTL8125A, and r8126 +doesn't advertise 5G EEE. Likely there are compatibility issues, +therefore do the same in r8169. +With this change we don't have to disable 2.5G EEE advertisement in +rtl8125a_config_eee_phy() any longer. +We use new phylib accessor phy_set_eee_broken() to mark the respective +EEE modes as broken. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/ce185e10-8a2f-4cf8-a49b-fd8fb3c3c8a1@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 6 ++++++ + drivers/net/ethernet/realtek/r8169_phy_config.c | 16 ++++------------ + 2 files changed, 10 insertions(+), 12 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -5234,6 +5234,11 @@ static int r8169_mdio_register(struct rt + phy_support_eee(tp->phydev); + phy_support_asym_pause(tp->phydev); + ++ /* mimic behavior of r8125/r8126 vendor drivers */ ++ if (tp->mac_version == RTL_GIGA_MAC_VER_61) ++ tp->phydev->eee_broken_modes |= MDIO_EEE_2_5GT; ++ tp->phydev->eee_broken_modes |= MDIO_EEE_5GT; ++ + /* PHY will be woken up in rtl_open() */ + phy_suspend(tp->phydev); + +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -96,15 +96,7 @@ static void rtl8125_common_config_eee_ph + phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); + } + +-static void rtl8125a_config_eee_phy(struct phy_device *phydev) +-{ +- rtl8168g_config_eee_phy(phydev); +- /* disable EEE at 2.5Gbps */ +- phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000); +- rtl8125_common_config_eee_phy(phydev); +-} +- +-static void rtl8125b_config_eee_phy(struct phy_device *phydev) ++static void rtl8125_config_eee_phy(struct phy_device *phydev) + { + rtl8168g_config_eee_phy(phydev); + rtl8125_common_config_eee_phy(phydev); +@@ -1066,7 +1058,7 @@ static void rtl8125a_2_hw_phy_config(str + rtl8168g_enable_gphy_10m(phydev); + + rtl8168g_disable_aldps(phydev); +- rtl8125a_config_eee_phy(phydev); ++ rtl8125_config_eee_phy(phydev); + } + + static void rtl8125b_hw_phy_config(struct rtl8169_private *tp, +@@ -1106,7 +1098,7 @@ static void rtl8125b_hw_phy_config(struc + + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); +- rtl8125b_config_eee_phy(phydev); ++ rtl8125_config_eee_phy(phydev); + } + + static void rtl8125d_hw_phy_config(struct rtl8169_private *tp, +@@ -1116,7 +1108,7 @@ static void rtl8125d_hw_phy_config(struc + rtl8168g_enable_gphy_10m(phydev); + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); +- rtl8125b_config_eee_phy(phydev); ++ rtl8125_config_eee_phy(phydev); + } + + static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, diff --git a/6.12/target/linux/generic/backport-6.12/780-45-v6.14-r8169-remove-unused-flag-RTL_FLAG_TASK_RESET_NO_QUEU.patch b/6.12/target/linux/generic/backport-6.12/780-45-v6.14-r8169-remove-unused-flag-RTL_FLAG_TASK_RESET_NO_QUEU.patch new file mode 100644 index 00000000..54152e63 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-45-v6.14-r8169-remove-unused-flag-RTL_FLAG_TASK_RESET_NO_QUEU.patch @@ -0,0 +1,35 @@ +From 2e20bf8cc05766dcd0357cdfcada49e1bc45512b Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Mon, 2 Dec 2024 21:14:35 +0100 +Subject: [PATCH] r8169: remove unused flag RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE + +After 854d71c555dfc3 ("r8169: remove original workaround for RTL8125 +broken rx issue") this flag isn't used any longer. So remove it. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Michal Swiatkowski +Link: https://patch.msgid.link/d9dd214b-3027-4f60-b0e8-6f34a0c76582@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -623,7 +623,6 @@ struct rtl8169_tc_offsets { + enum rtl_flag { + RTL_FLAG_TASK_ENABLED = 0, + RTL_FLAG_TASK_RESET_PENDING, +- RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, + RTL_FLAG_TASK_TX_TIMEOUT, + RTL_FLAG_MAX + }; +@@ -4728,8 +4727,6 @@ static void rtl_task(struct work_struct + reset: + rtl_reset_work(tp); + netif_wake_queue(tp->dev); +- } else if (test_and_clear_bit(RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, tp->wk.flags)) { +- rtl_reset_work(tp); + } + } + diff --git a/6.12/target/linux/generic/backport-6.12/780-46-v6.14-r8169-remove-support-for-chip-version-11.patch b/6.12/target/linux/generic/backport-6.12/780-46-v6.14-r8169-remove-support-for-chip-version-11.patch new file mode 100644 index 00000000..0f253f99 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-46-v6.14-r8169-remove-support-for-chip-version-11.patch @@ -0,0 +1,114 @@ +From bb18265c3aba92b91a1355609769f3e967b65dee Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Mon, 2 Dec 2024 21:20:02 +0100 +Subject: [PATCH] r8169: remove support for chip version 11 + +This is a follow-up to 982300c115d2 ("r8169: remove detection of chip +version 11 (early RTL8168b)"). Nobody complained yet, so remove +support for this chip version. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/b689ab6d-20b5-4b64-bd7e-531a0a972ba3@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169.h | 2 +- + drivers/net/ethernet/realtek/r8169_main.c | 14 +------------- + drivers/net/ethernet/realtek/r8169_phy_config.c | 10 ---------- + 3 files changed, 2 insertions(+), 24 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -23,7 +23,7 @@ enum mac_version { + RTL_GIGA_MAC_VER_08, + RTL_GIGA_MAC_VER_09, + RTL_GIGA_MAC_VER_10, +- RTL_GIGA_MAC_VER_11, ++ /* support for RTL_GIGA_MAC_VER_11 has been removed */ + /* RTL_GIGA_MAC_VER_12 was handled the same as VER_17 */ + /* RTL_GIGA_MAC_VER_13 was merged with VER_10 */ + RTL_GIGA_MAC_VER_14, +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -103,7 +103,6 @@ static const struct { + [RTL_GIGA_MAC_VER_08] = {"RTL8102e" }, + [RTL_GIGA_MAC_VER_09] = {"RTL8102e/RTL8103e" }, + [RTL_GIGA_MAC_VER_10] = {"RTL8101e/RTL8100e" }, +- [RTL_GIGA_MAC_VER_11] = {"RTL8168b/8111b" }, + [RTL_GIGA_MAC_VER_14] = {"RTL8401" }, + [RTL_GIGA_MAC_VER_17] = {"RTL8168b/8111b" }, + [RTL_GIGA_MAC_VER_18] = {"RTL8168cp/8111cp" }, +@@ -2335,7 +2334,7 @@ static enum mac_version rtl8169_get_mac_ + + /* 8168B family. */ + { 0x7c8, 0x380, RTL_GIGA_MAC_VER_17 }, +- /* This one is very old and rare, let's see if anybody complains. ++ /* This one is very old and rare, support has been removed. + * { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11 }, + */ + +@@ -3805,7 +3804,6 @@ static void rtl_hw_config(struct rtl8169 + [RTL_GIGA_MAC_VER_08] = rtl_hw_start_8102e_3, + [RTL_GIGA_MAC_VER_09] = rtl_hw_start_8102e_2, + [RTL_GIGA_MAC_VER_10] = NULL, +- [RTL_GIGA_MAC_VER_11] = rtl_hw_start_8168b, + [RTL_GIGA_MAC_VER_14] = rtl_hw_start_8401, + [RTL_GIGA_MAC_VER_17] = rtl_hw_start_8168b, + [RTL_GIGA_MAC_VER_18] = rtl_hw_start_8168cp_1, +@@ -4681,12 +4679,6 @@ static irqreturn_t rtl8169_interrupt(int + if (status & LinkChg) + phy_mac_interrupt(tp->phydev); + +- if (unlikely(status & RxFIFOOver && +- tp->mac_version == RTL_GIGA_MAC_VER_11)) { +- netif_stop_queue(tp->dev); +- rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); +- } +- + rtl_irq_disable(tp); + napi_schedule(&tp->napi); + out: +@@ -5106,9 +5098,6 @@ static void rtl_set_irq_mask(struct rtl8 + + if (tp->mac_version <= RTL_GIGA_MAC_VER_06) + tp->irq_mask |= SYSErr | RxFIFOOver; +- else if (tp->mac_version == RTL_GIGA_MAC_VER_11) +- /* special workaround needed */ +- tp->irq_mask |= RxFIFOOver; + } + + static int rtl_alloc_irq(struct rtl8169_private *tp) +@@ -5302,7 +5291,6 @@ static int rtl_jumbo_max(struct rtl8169_ + case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: + return JUMBO_7K; + /* RTL8168b */ +- case RTL_GIGA_MAC_VER_11: + case RTL_GIGA_MAC_VER_17: + return JUMBO_4K; + /* RTL8168c */ +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -276,15 +276,6 @@ static void rtl8169sce_hw_phy_config(str + rtl_writephy_batch(phydev, phy_reg_init); + } + +-static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp, +- struct phy_device *phydev) +-{ +- phy_write(phydev, 0x1f, 0x0001); +- phy_set_bits(phydev, 0x16, BIT(0)); +- phy_write(phydev, 0x10, 0xf41b); +- phy_write(phydev, 0x1f, 0x0000); +-} +- + static void rtl8168bef_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) + { +@@ -1136,7 +1127,6 @@ void r8169_hw_phy_config(struct rtl8169_ + [RTL_GIGA_MAC_VER_08] = rtl8102e_hw_phy_config, + [RTL_GIGA_MAC_VER_09] = rtl8102e_hw_phy_config, + [RTL_GIGA_MAC_VER_10] = NULL, +- [RTL_GIGA_MAC_VER_11] = rtl8168bb_hw_phy_config, + [RTL_GIGA_MAC_VER_14] = rtl8401_hw_phy_config, + [RTL_GIGA_MAC_VER_17] = rtl8168bef_hw_phy_config, + [RTL_GIGA_MAC_VER_18] = rtl8168cp_1_hw_phy_config, diff --git a/6.12/target/linux/generic/backport-6.12/780-47-v6.14-r8169-adjust-version-numbering-for-RTL8126.patch b/6.12/target/linux/generic/backport-6.12/780-47-v6.14-r8169-adjust-version-numbering-for-RTL8126.patch new file mode 100644 index 00000000..b5c0eee6 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-47-v6.14-r8169-adjust-version-numbering-for-RTL8126.patch @@ -0,0 +1,257 @@ +From b299ea0069284186b0d3d54aebe87f0d195d457a Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Fri, 13 Dec 2024 20:01:41 +0100 +Subject: [PATCH] r8169: adjust version numbering for RTL8126 + +Adjust version numbering for RTL8126, so that it doesn't overlap with +new RTL8125 versions. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/6a354364-20e9-48ad-a198-468264288757@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169.h | 4 +- + drivers/net/ethernet/realtek/r8169_main.c | 62 +++++++++---------- + .../net/ethernet/realtek/r8169_phy_config.c | 4 +- + 3 files changed, 35 insertions(+), 35 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -69,8 +69,8 @@ enum mac_version { + RTL_GIGA_MAC_VER_61, + RTL_GIGA_MAC_VER_63, + RTL_GIGA_MAC_VER_64, +- RTL_GIGA_MAC_VER_65, +- RTL_GIGA_MAC_VER_66, ++ RTL_GIGA_MAC_VER_70, ++ RTL_GIGA_MAC_VER_71, + RTL_GIGA_MAC_NONE + }; + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -139,8 +139,8 @@ static const struct { + /* reserve 62 for CFG_METHOD_4 in the vendor driver */ + [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, + [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1}, +- [RTL_GIGA_MAC_VER_65] = {"RTL8126A", FIRMWARE_8126A_2}, +- [RTL_GIGA_MAC_VER_66] = {"RTL8126A", FIRMWARE_8126A_3}, ++ [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2}, ++ [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3}, + }; + + static const struct pci_device_id rtl8169_pci_tbl[] = { +@@ -1228,7 +1228,7 @@ static void rtl_writephy(struct rtl8169_ + case RTL_GIGA_MAC_VER_31: + r8168dp_2_mdio_write(tp, location, val); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + r8168g_mdio_write(tp, location, val); + break; + default: +@@ -1243,7 +1243,7 @@ static int rtl_readphy(struct rtl8169_pr + case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + return r8168dp_2_mdio_read(tp, location); +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + return r8168g_mdio_read(tp, location); + default: + return r8169_mdio_read(tp, location); +@@ -1574,7 +1574,7 @@ static void __rtl8169_set_wol(struct rtl + break; + case RTL_GIGA_MAC_VER_34: + case RTL_GIGA_MAC_VER_37: +- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_71: + r8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts); + break; + default: +@@ -2047,7 +2047,7 @@ static void rtl_set_eee_txidle_timer(str + tp->tx_lpi_timer = timer_val; + r8168_mac_ocp_write(tp, 0xe048, timer_val); + break; +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + tp->tx_lpi_timer = timer_val; + RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val); + break; +@@ -2255,8 +2255,8 @@ static enum mac_version rtl8169_get_mac_ + enum mac_version ver; + } mac_info[] = { + /* 8126A family. */ +- { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_66 }, +- { 0x7cf, 0x649, RTL_GIGA_MAC_VER_65 }, ++ { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71 }, ++ { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 }, + + /* 8125D family. */ + { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 }, +@@ -2528,7 +2528,7 @@ static void rtl_init_rxcfg(struct rtl816 + case RTL_GIGA_MAC_VER_61: + RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST); + break; +- case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71: + RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST | + RX_PAUSE_SLOT_ON); + break; +@@ -2660,7 +2660,7 @@ static void rtl_wait_txrx_fifo_empty(str + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_61: + rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); + break; +- case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71: + RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); + rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); + rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond_2, 100, 42); +@@ -2903,7 +2903,7 @@ static void rtl_enable_exit_l1(struct rt + case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_38: + rtl_eri_set_bits(tp, 0xd4, 0x0c00); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + r8168_mac_ocp_modify(tp, 0xc0ac, 0, 0x1f80); + break; + default: +@@ -2917,7 +2917,7 @@ static void rtl_disable_exit_l1(struct r + case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38: + rtl_eri_clear_bits(tp, 0xd4, 0x1f00); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + r8168_mac_ocp_modify(tp, 0xc0ac, 0x1f80, 0); + break; + default: +@@ -2943,8 +2943,8 @@ static void rtl_hw_aspm_clkreq_enable(st + + rtl_mod_config5(tp, 0, ASPM_en); + switch (tp->mac_version) { +- case RTL_GIGA_MAC_VER_65: +- case RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_70: ++ case RTL_GIGA_MAC_VER_71: + val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN; + RTL_W8(tp, INT_CFG0_8125, val8); + break; +@@ -2955,7 +2955,7 @@ static void rtl_hw_aspm_clkreq_enable(st + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + /* reset ephy tx/rx disable timer */ + r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0); + /* chip can trigger L1.2 */ +@@ -2967,7 +2967,7 @@ static void rtl_hw_aspm_clkreq_enable(st + } else { + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0); + break; + default: +@@ -2975,8 +2975,8 @@ static void rtl_hw_aspm_clkreq_enable(st + } + + switch (tp->mac_version) { +- case RTL_GIGA_MAC_VER_65: +- case RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_70: ++ case RTL_GIGA_MAC_VER_71: + val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN; + RTL_W8(tp, INT_CFG0_8125, val8); + break; +@@ -3696,12 +3696,12 @@ static void rtl_hw_start_8125_common(str + /* disable new tx descriptor format */ + r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000); + +- if (tp->mac_version == RTL_GIGA_MAC_VER_65 || +- tp->mac_version == RTL_GIGA_MAC_VER_66) ++ if (tp->mac_version == RTL_GIGA_MAC_VER_70 || ++ tp->mac_version == RTL_GIGA_MAC_VER_71) + RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02); + +- if (tp->mac_version == RTL_GIGA_MAC_VER_65 || +- tp->mac_version == RTL_GIGA_MAC_VER_66) ++ if (tp->mac_version == RTL_GIGA_MAC_VER_70 || ++ tp->mac_version == RTL_GIGA_MAC_VER_71) + r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); + else if (tp->mac_version == RTL_GIGA_MAC_VER_63) + r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200); +@@ -3719,8 +3719,8 @@ static void rtl_hw_start_8125_common(str + r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0030); + r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000); + r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001); +- if (tp->mac_version == RTL_GIGA_MAC_VER_65 || +- tp->mac_version == RTL_GIGA_MAC_VER_66) ++ if (tp->mac_version == RTL_GIGA_MAC_VER_70 || ++ tp->mac_version == RTL_GIGA_MAC_VER_71) + r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000); + else + r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000); +@@ -3839,8 +3839,8 @@ static void rtl_hw_config(struct rtl8169 + [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, + [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, + [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, +- [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8126a, +- [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8126a, ++ [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, ++ [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a, + }; + + if (hw_configs[tp->mac_version]) +@@ -3861,8 +3861,8 @@ static void rtl_hw_start_8125(struct rtl + RTL_W32(tp, i, 0); + break; + case RTL_GIGA_MAC_VER_63: +- case RTL_GIGA_MAC_VER_65: +- case RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_70: ++ case RTL_GIGA_MAC_VER_71: + for (i = 0xa00; i < 0xa80; i += 4) + RTL_W32(tp, i, 0); + RTL_W16(tp, INT_CFG1_8125, 0x0000); +@@ -4094,7 +4094,7 @@ static void rtl8169_cleanup(struct rtl81 + RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); + rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + rtl_enable_rxdvgate(tp); + fsleep(2000); + break; +@@ -4251,7 +4251,7 @@ static unsigned int rtl_quirk_packet_pad + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_34: +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + padto = max_t(unsigned int, padto, ETH_ZLEN); + break; + default: +@@ -5272,7 +5272,7 @@ static void rtl_hw_initialize(struct rtl + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48: + rtl_hw_init_8168g(tp); + break; +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + rtl_hw_init_8125(tp); + break; + default: +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1162,8 +1162,8 @@ void r8169_hw_phy_config(struct rtl8169_ + [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, + [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, + [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, +- [RTL_GIGA_MAC_VER_65] = rtl8126a_hw_phy_config, +- [RTL_GIGA_MAC_VER_66] = rtl8126a_hw_phy_config, ++ [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, ++ [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config, + }; + + if (phy_configs[ver]) diff --git a/6.12/target/linux/generic/backport-6.12/780-48-v6.14-r8169-add-support-for-RTL8125D-rev.b.patch b/6.12/target/linux/generic/backport-6.12/780-48-v6.14-r8169-add-support-for-RTL8125D-rev.b.patch new file mode 100644 index 00000000..70505806 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-48-v6.14-r8169-add-support-for-RTL8125D-rev.b.patch @@ -0,0 +1,90 @@ +From b3593df26ab19f114d613693fa8a92ab202803d0 Mon Sep 17 00:00:00 2001 +From: ChunHao Lin +Date: Fri, 13 Dec 2024 20:02:58 +0100 +Subject: [PATCH] r8169: add support for RTL8125D rev.b + +Add support for RTL8125D rev.b. Its XID is 0x689. It is basically +based on the one with XID 0x688, but with different firmware file. + +Signed-off-by: ChunHao Lin +[hkallweit1@gmail.com: rebased after adjusted version numbering] +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/75e5e9ec-d01f-43ac-b0f4-e7456baf18d1@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169.h | 1 + + drivers/net/ethernet/realtek/r8169_main.c | 6 ++++++ + drivers/net/ethernet/realtek/r8169_phy_config.c | 1 + + 3 files changed, 8 insertions(+) + +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -69,6 +69,7 @@ enum mac_version { + RTL_GIGA_MAC_VER_61, + RTL_GIGA_MAC_VER_63, + RTL_GIGA_MAC_VER_64, ++ RTL_GIGA_MAC_VER_65, + RTL_GIGA_MAC_VER_70, + RTL_GIGA_MAC_VER_71, + RTL_GIGA_MAC_NONE +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -56,6 +56,7 @@ + #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw" + #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" + #define FIRMWARE_8125D_1 "rtl_nic/rtl8125d-1.fw" ++#define FIRMWARE_8125D_2 "rtl_nic/rtl8125d-2.fw" + #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw" + #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw" + +@@ -139,6 +140,7 @@ static const struct { + /* reserve 62 for CFG_METHOD_4 in the vendor driver */ + [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, + [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1}, ++ [RTL_GIGA_MAC_VER_65] = {"RTL8125D", FIRMWARE_8125D_2}, + [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2}, + [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3}, + }; +@@ -706,6 +708,7 @@ MODULE_FIRMWARE(FIRMWARE_8107E_2); + MODULE_FIRMWARE(FIRMWARE_8125A_3); + MODULE_FIRMWARE(FIRMWARE_8125B_2); + MODULE_FIRMWARE(FIRMWARE_8125D_1); ++MODULE_FIRMWARE(FIRMWARE_8125D_2); + MODULE_FIRMWARE(FIRMWARE_8126A_2); + MODULE_FIRMWARE(FIRMWARE_8126A_3); + +@@ -2259,6 +2262,7 @@ static enum mac_version rtl8169_get_mac_ + { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 }, + + /* 8125D family. */ ++ { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65 }, + { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 }, + + /* 8125B family. */ +@@ -3839,6 +3843,7 @@ static void rtl_hw_config(struct rtl8169 + [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, + [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, + [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, ++ [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, + [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a, + }; +@@ -3857,6 +3862,7 @@ static void rtl_hw_start_8125(struct rtl + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_61: + case RTL_GIGA_MAC_VER_64: ++ case RTL_GIGA_MAC_VER_65: + for (i = 0xa00; i < 0xb00; i += 4) + RTL_W32(tp, i, 0); + break; +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1162,6 +1162,7 @@ void r8169_hw_phy_config(struct rtl8169_ + [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, + [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, + [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, ++ [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config, + [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, + [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config, + }; diff --git a/6.12/target/linux/generic/backport-6.12/780-49-v6.14-r8169-add-support-for-RTL8125BP-rev.b.patch b/6.12/target/linux/generic/backport-6.12/780-49-v6.14-r8169-add-support-for-RTL8125BP-rev.b.patch new file mode 100644 index 00000000..09a45cad --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/780-49-v6.14-r8169-add-support-for-RTL8125BP-rev.b.patch @@ -0,0 +1,184 @@ +From b11bff90f2ad52c5c55c822ecd20326619a73898 Mon Sep 17 00:00:00 2001 +From: ChunHao Lin +Date: Tue, 7 Jan 2025 14:43:55 +0800 +Subject: [PATCH] r8169: add support for RTL8125BP rev.b + +Add support for RTL8125BP rev.b. Its XID is 0x689. This chip supports +DASH and its dash type is "RTL_DASH_25_BP". + +Signed-off-by: ChunHao Lin +Reviewed-by: Heiner Kallweit +Link: https://patch.msgid.link/20250107064355.104711-1-hau@realtek.com +Signed-off-by: Paolo Abeni +--- + drivers/net/ethernet/realtek/r8169.h | 1 + + drivers/net/ethernet/realtek/r8169_main.c | 30 +++++++++++++++++++ + .../net/ethernet/realtek/r8169_phy_config.c | 23 ++++++++++++++ + 3 files changed, 54 insertions(+) + +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -70,6 +70,7 @@ enum mac_version { + RTL_GIGA_MAC_VER_63, + RTL_GIGA_MAC_VER_64, + RTL_GIGA_MAC_VER_65, ++ RTL_GIGA_MAC_VER_66, + RTL_GIGA_MAC_VER_70, + RTL_GIGA_MAC_VER_71, + RTL_GIGA_MAC_NONE +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -57,6 +57,7 @@ + #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" + #define FIRMWARE_8125D_1 "rtl_nic/rtl8125d-1.fw" + #define FIRMWARE_8125D_2 "rtl_nic/rtl8125d-2.fw" ++#define FIRMWARE_8125BP_2 "rtl_nic/rtl8125bp-2.fw" + #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw" + #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw" + +@@ -141,6 +142,7 @@ static const struct { + [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, + [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1}, + [RTL_GIGA_MAC_VER_65] = {"RTL8125D", FIRMWARE_8125D_2}, ++ [RTL_GIGA_MAC_VER_66] = {"RTL8125BP", FIRMWARE_8125BP_2}, + [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2}, + [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3}, + }; +@@ -632,6 +634,7 @@ enum rtl_dash_type { + RTL_DASH_NONE, + RTL_DASH_DP, + RTL_DASH_EP, ++ RTL_DASH_25_BP, + }; + + struct rtl8169_private { +@@ -709,6 +712,7 @@ MODULE_FIRMWARE(FIRMWARE_8125A_3); + MODULE_FIRMWARE(FIRMWARE_8125B_2); + MODULE_FIRMWARE(FIRMWARE_8125D_1); + MODULE_FIRMWARE(FIRMWARE_8125D_2); ++MODULE_FIRMWARE(FIRMWARE_8125BP_2); + MODULE_FIRMWARE(FIRMWARE_8126A_2); + MODULE_FIRMWARE(FIRMWARE_8126A_3); + +@@ -1361,10 +1365,19 @@ static void rtl8168ep_driver_start(struc + rtl_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30); + } + ++static void rtl8125bp_driver_start(struct rtl8169_private *tp) ++{ ++ r8168ep_ocp_write(tp, 0x01, 0x14, OOB_CMD_DRIVER_START); ++ r8168ep_ocp_write(tp, 0x01, 0x18, 0x00); ++ r8168ep_ocp_write(tp, 0x01, 0x10, 0x01); ++} ++ + static void rtl8168_driver_start(struct rtl8169_private *tp) + { + if (tp->dash_type == RTL_DASH_DP) + rtl8168dp_driver_start(tp); ++ else if (tp->dash_type == RTL_DASH_25_BP) ++ rtl8125bp_driver_start(tp); + else + rtl8168ep_driver_start(tp); + } +@@ -1385,10 +1398,19 @@ static void rtl8168ep_driver_stop(struct + rtl_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10); + } + ++static void rtl8125bp_driver_stop(struct rtl8169_private *tp) ++{ ++ r8168ep_ocp_write(tp, 0x01, 0x14, OOB_CMD_DRIVER_STOP); ++ r8168ep_ocp_write(tp, 0x01, 0x18, 0x00); ++ r8168ep_ocp_write(tp, 0x01, 0x10, 0x01); ++} ++ + static void rtl8168_driver_stop(struct rtl8169_private *tp) + { + if (tp->dash_type == RTL_DASH_DP) + rtl8168dp_driver_stop(tp); ++ else if (tp->dash_type == RTL_DASH_25_BP) ++ rtl8125bp_driver_stop(tp); + else + rtl8168ep_driver_stop(tp); + } +@@ -1411,6 +1433,7 @@ static bool rtl_dash_is_enabled(struct r + case RTL_DASH_DP: + return r8168dp_check_dash(tp); + case RTL_DASH_EP: ++ case RTL_DASH_25_BP: + return r8168ep_check_dash(tp); + default: + return false; +@@ -1425,6 +1448,8 @@ static enum rtl_dash_type rtl_get_dash_t + return RTL_DASH_DP; + case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_53: + return RTL_DASH_EP; ++ case RTL_GIGA_MAC_VER_66: ++ return RTL_DASH_25_BP; + default: + return RTL_DASH_NONE; + } +@@ -2261,6 +2286,9 @@ static enum mac_version rtl8169_get_mac_ + { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71 }, + { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 }, + ++ /* 8125BP family. */ ++ { 0x7cf, 0x681, RTL_GIGA_MAC_VER_66 }, ++ + /* 8125D family. */ + { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65 }, + { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 }, +@@ -3844,6 +3872,7 @@ static void rtl_hw_config(struct rtl8169 + [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, + [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d, ++ [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, + [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a, + }; +@@ -3863,6 +3892,7 @@ static void rtl_hw_start_8125(struct rtl + case RTL_GIGA_MAC_VER_61: + case RTL_GIGA_MAC_VER_64: + case RTL_GIGA_MAC_VER_65: ++ case RTL_GIGA_MAC_VER_66: + for (i = 0xa00; i < 0xb00; i += 4) + RTL_W32(tp, i, 0); + break; +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1102,6 +1102,28 @@ static void rtl8125d_hw_phy_config(struc + rtl8125_config_eee_phy(phydev); + } + ++static void rtl8125bp_hw_phy_config(struct rtl8169_private *tp, ++ struct phy_device *phydev) ++{ ++ r8169_apply_firmware(tp); ++ rtl8168g_enable_gphy_10m(phydev); ++ ++ r8168g_phy_param(phydev, 0x8010, 0x0800, 0x0000); ++ ++ phy_write(phydev, 0x1f, 0x0b87); ++ phy_write(phydev, 0x16, 0x8088); ++ phy_modify(phydev, 0x17, 0xff00, 0x9000); ++ phy_write(phydev, 0x16, 0x808f); ++ phy_modify(phydev, 0x17, 0xff00, 0x9000); ++ phy_write(phydev, 0x1f, 0x0000); ++ ++ r8168g_phy_param(phydev, 0x8174, 0x2000, 0x1800); ++ ++ rtl8125_legacy_force_mode(phydev); ++ rtl8168g_disable_aldps(phydev); ++ rtl8125_config_eee_phy(phydev); ++} ++ + static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) + { +@@ -1163,6 +1185,7 @@ void r8169_hw_phy_config(struct rtl8169_ + [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, + [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, + [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config, ++ [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config, + [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, + [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config, + }; diff --git a/6.12/target/linux/generic/backport-6.12/781-18-v6.13-net-phy-realtek-merge-the-drivers-for-internal-NBase.patch b/6.12/target/linux/generic/backport-6.12/781-18-v6.13-net-phy-realtek-merge-the-drivers-for-internal-NBase.patch new file mode 100644 index 00000000..771f60df --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/781-18-v6.13-net-phy-realtek-merge-the-drivers-for-internal-NBase.patch @@ -0,0 +1,136 @@ +From f87a17ed3b51fba4dfdd8f8b643b5423a85fc551 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Tue, 15 Oct 2024 07:47:14 +0200 +Subject: [PATCH] net: phy: realtek: merge the drivers for internal NBase-T + PHY's + +The Realtek RTL8125/RTL8126 NBase-T MAC/PHY chips have internal PHY's +which are register-compatible, at least for the registers we use here. +So let's use just one PHY driver to support all of them. +These internal PHY's exist also as external C45 PHY's, but on the +internal PHY's no access to MMD registers is possible. This can be +used to differentiate between the internal and external version. + +As a side effect the drivers for two now external-only drivers don't +require read_mmd/write_mmd hooks any longer. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/c57081a6-811f-4571-ab35-34f4ca6de9af@gmail.com +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek.c | 53 +++++++++++++++++++++++++++++++-------- + 1 file changed, 43 insertions(+), 10 deletions(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -95,6 +95,7 @@ + + #define RTL_GENERIC_PHYID 0x001cc800 + #define RTL_8211FVD_PHYID 0x001cc878 ++#define RTL_8221B 0x001cc840 + #define RTL_8221B_VB_CG 0x001cc849 + #define RTL_8221B_VN_CG 0x001cc84a + #define RTL_8251B 0x001cc862 +@@ -1077,6 +1078,23 @@ static bool rtlgen_supports_2_5gbps(stru + return val >= 0 && val & MDIO_PMA_SPEED_2_5G; + } + ++/* On internal PHY's MMD reads over C22 always return 0. ++ * Check a MMD register which is known to be non-zero. ++ */ ++static bool rtlgen_supports_mmd(struct phy_device *phydev) ++{ ++ int val; ++ ++ phy_lock_mdio_bus(phydev); ++ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS); ++ __phy_write(phydev, MII_MMD_DATA, MDIO_PCS_EEE_ABLE); ++ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS | MII_MMD_CTRL_NOINCR); ++ val = __phy_read(phydev, MII_MMD_DATA); ++ phy_unlock_mdio_bus(phydev); ++ ++ return val > 0; ++} ++ + static int rtlgen_match_phy_device(struct phy_device *phydev) + { + return phydev->phy_id == RTL_GENERIC_PHYID && +@@ -1086,7 +1104,8 @@ static int rtlgen_match_phy_device(struc + static int rtl8226_match_phy_device(struct phy_device *phydev) + { + return phydev->phy_id == RTL_GENERIC_PHYID && +- rtlgen_supports_2_5gbps(phydev); ++ rtlgen_supports_2_5gbps(phydev) && ++ rtlgen_supports_mmd(phydev); + } + + static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, +@@ -1098,6 +1117,11 @@ static int rtlgen_is_c45_match(struct ph + return !is_c45 && (id == phydev->phy_id); + } + ++static int rtl8221b_match_phy_device(struct phy_device *phydev) ++{ ++ return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev); ++} ++ + static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) + { + return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false); +@@ -1118,9 +1142,21 @@ static int rtl8221b_vn_cg_c45_match_phy_ + return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true); + } + +-static int rtl8251b_c22_match_phy_device(struct phy_device *phydev) ++static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) + { +- return rtlgen_is_c45_match(phydev, RTL_8251B, false); ++ if (phydev->is_c45) ++ return false; ++ ++ switch (phydev->phy_id) { ++ case RTL_GENERIC_PHYID: ++ case RTL_8221B: ++ case RTL_8251B: ++ break; ++ default: ++ return false; ++ } ++ ++ return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev); + } + + static int rtl8251b_c45_match_phy_device(struct phy_device *phydev) +@@ -1382,10 +1418,8 @@ static struct phy_driver realtek_drvs[] + .resume = rtlgen_resume, + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, +- .read_mmd = rtl822x_read_mmd, +- .write_mmd = rtl822x_write_mmd, + }, { +- PHY_ID_MATCH_EXACT(0x001cc840), ++ .match_phy_device = rtl8221b_match_phy_device, + .name = "RTL8226B_RTL8221B 2.5Gbps PHY", + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, +@@ -1396,8 +1430,6 @@ static struct phy_driver realtek_drvs[] + .resume = rtlgen_resume, + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, +- .read_mmd = rtl822x_read_mmd, +- .write_mmd = rtl822x_write_mmd, + }, { + PHY_ID_MATCH_EXACT(0x001cc838), + .name = "RTL8226-CG 2.5Gbps PHY", +@@ -1475,8 +1507,9 @@ static struct phy_driver realtek_drvs[] + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, + }, { +- .match_phy_device = rtl8251b_c22_match_phy_device, +- .name = "RTL8126A-internal 5Gbps PHY", ++ .match_phy_device = rtl_internal_nbaset_match_phy_device, ++ .name = "Realtek Internal NBASE-T PHY", ++ .flags = PHY_IS_INTERNAL, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .read_status = rtl822x_read_status, diff --git a/6.12/target/linux/generic/backport-6.12/781-19-v6.13-net-phy-realtek-add-RTL8125D-internal-PHY.patch b/6.12/target/linux/generic/backport-6.12/781-19-v6.13-net-phy-realtek-add-RTL8125D-internal-PHY.patch new file mode 100644 index 00000000..4b9b9e8d --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/781-19-v6.13-net-phy-realtek-add-RTL8125D-internal-PHY.patch @@ -0,0 +1,29 @@ +From 8989bad541133c43550bff2b80edbe37b8fb9659 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 17 Oct 2024 18:01:13 +0200 +Subject: [PATCH] net: phy: realtek: add RTL8125D-internal PHY + +The first boards show up with Realtek's RTL8125D. This MAC/PHY chip +comes with an integrated 2.5Gbps PHY with ID 0x001cc841. It's not +clear yet whether there's an external version of this PHY and how +Realtek calls it, therefore use the numeric id for now. + +Link: https://lore.kernel.org/netdev/2ada65e1-5dfa-456c-9334-2bc51272e9da@gmail.com/T/ +Signed-off-by: Heiner Kallweit +Message-ID: <7d2924de-053b-44d2-a479-870dc3878170@gmail.com> +Reviewed-by: Andrew Lunn +Signed-off-by: Andrew Lunn +--- + drivers/net/phy/realtek.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -1151,6 +1151,7 @@ static int rtl_internal_nbaset_match_phy + case RTL_GENERIC_PHYID: + case RTL_8221B: + case RTL_8251B: ++ case 0x001cc841: + break; + default: + return false; diff --git a/6.12/target/linux/generic/backport-6.12/781-20-v6.14-net-phy-realtek-clear-1000Base-T-lpa-if-link-is-down.patch b/6.12/target/linux/generic/backport-6.12/781-20-v6.14-net-phy-realtek-clear-1000Base-T-lpa-if-link-is-down.patch new file mode 100644 index 00000000..3e9631e4 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/781-20-v6.14-net-phy-realtek-clear-1000Base-T-lpa-if-link-is-down.patch @@ -0,0 +1,52 @@ +From 34d5a86ff7bbe225fba3ad91f9b4dc85fb408e18 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 15 Jan 2025 14:43:35 +0000 +Subject: [PATCH] net: phy: realtek: clear 1000Base-T lpa if link is down + +Only read 1000Base-T link partner advertisement if autonegotiation has +completed and otherwise 1000Base-T link partner advertisement bits. + +This fixes bogus 1000Base-T link partner advertisement after link goes +down (eg. by disconnecting the wire). +Fixes: 5cb409b3960e ("net: phy: realtek: clear 1000Base-T link partner advertisement") +Signed-off-by: Daniel Golle +Reviewed-by: Michal Swiatkowski +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -1023,23 +1023,20 @@ static int rtl822x_c45_read_status(struc + { + int ret, val; + +- ret = genphy_c45_read_status(phydev); +- if (ret < 0) +- return ret; +- +- if (phydev->autoneg == AUTONEG_DISABLE || +- !genphy_c45_aneg_done(phydev)) +- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, 0); +- + /* Vendor register as C45 has no standardized support for 1000BaseT */ +- if (phydev->autoneg == AUTONEG_ENABLE) { ++ if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, + RTL822X_VND2_GANLPAR); + if (val < 0) + return val; +- +- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); ++ } else { ++ val = 0; + } ++ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); ++ ++ ret = genphy_c45_read_status(phydev); ++ if (ret < 0) ++ return ret; + + if (!phydev->link) + return 0; diff --git a/6.12/target/linux/generic/backport-6.12/781-21-v6.14-net-phy-realtek-clear-master_slave_state-if-link-is-.patch b/6.12/target/linux/generic/backport-6.12/781-21-v6.14-net-phy-realtek-clear-master_slave_state-if-link-is-.patch new file mode 100644 index 00000000..778602d3 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/781-21-v6.14-net-phy-realtek-clear-master_slave_state-if-link-is-.patch @@ -0,0 +1,35 @@ +From ea8318cb33e593bbfc59d637eae45a69732c5387 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 15 Jan 2025 14:43:43 +0000 +Subject: [PATCH] net: phy: realtek: clear master_slave_state if link is down + +rtlgen_decode_physr() which sets master_slave_state isn't called in case +the link is down and other than rtlgen_read_status(), +rtl822x_c45_read_status() doesn't implicitely clear master_slave_state. + +Avoid stale master_slave_state by always setting it to +MASTER_SLAVE_STATE_UNKNOWN in rtl822x_c45_read_status() in case the link +is down. + +Fixes: 081c9c0265c9 ("net: phy: realtek: read duplex and gbit master from PHYSR register") +Signed-off-by: Daniel Golle +Reviewed-by: Michal Swiatkowski +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -1038,8 +1038,10 @@ static int rtl822x_c45_read_status(struc + if (ret < 0) + return ret; + +- if (!phydev->link) ++ if (!phydev->link) { ++ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; + return 0; ++ } + + /* Read actual speed from vendor register. */ + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); diff --git a/6.12/target/linux/generic/backport-6.12/781-22-v6.14-net-phy-realtek-always-clear-NBase-T-lpa.patch b/6.12/target/linux/generic/backport-6.12/781-22-v6.14-net-phy-realtek-always-clear-NBase-T-lpa.patch new file mode 100644 index 00000000..d365ed0a --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/781-22-v6.14-net-phy-realtek-always-clear-NBase-T-lpa.patch @@ -0,0 +1,42 @@ +From d3eb58549842c60ed46f37da7f4da969e3d6ecd3 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 15 Jan 2025 14:45:00 +0000 +Subject: [PATCH] net: phy: realtek: always clear NBase-T lpa + +Clear NBase-T link partner advertisement before calling +rtlgen_read_status() to avoid phy_resolve_aneg_linkmode() wrongly +setting speed and duplex. + +This fixes bogus 2.5G/5G/10G link partner advertisement and thus +speed and duplex being set by phy_resolve_aneg_linkmode() due to stale +NBase-T lpa. + +Fixes: 68d5cd09e891 ("net: phy: realtek: change order of calls in C22 read_status()") +Signed-off-by: Daniel Golle +Reviewed-by: Michal Swiatkowski +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -952,15 +952,15 @@ static int rtl822x_read_status(struct ph + { + int lpadv, ret; + ++ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); ++ + ret = rtlgen_read_status(phydev); + if (ret < 0) + return ret; + + if (phydev->autoneg == AUTONEG_DISABLE || +- !phydev->autoneg_complete) { +- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); ++ !phydev->autoneg_complete) + return 0; +- } + + lpadv = phy_read_paged(phydev, 0xa5d, 0x13); + if (lpadv < 0) diff --git a/6.12/target/linux/generic/backport-6.12/781-23-v6.14-net-phy-realtek-add-support-for-reading-MDIO_MMD_VEN.patch b/6.12/target/linux/generic/backport-6.12/781-23-v6.14-net-phy-realtek-add-support-for-reading-MDIO_MMD_VEN.patch new file mode 100644 index 00000000..2add672f --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/781-23-v6.14-net-phy-realtek-add-support-for-reading-MDIO_MMD_VEN.patch @@ -0,0 +1,47 @@ +From 3d483a10327f38595f714f9f9e9dde43a622cb0f Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 11 Jan 2025 21:49:31 +0100 +Subject: [PATCH] net: phy: realtek: add support for reading MDIO_MMD_VEND2 + regs on RTL8125/RTL8126 + +RTL8125/RTL8126 don't support MMD access to the internal PHY, but +provide a mechanism to access at least all MDIO_MMD_VEND2 registers. +By exposing this mechanism standard MMD access functions can be used +to access the MDIO_MMD_VEND2 registers. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/e821b302-5fe6-49ab-aabd-05da500581c0@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -736,7 +736,11 @@ static int rtlgen_read_mmd(struct phy_de + { + int ret; + +- if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { ++ if (devnum == MDIO_MMD_VEND2) { ++ rtl821x_write_page(phydev, regnum >> 4); ++ ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { + rtl821x_write_page(phydev, 0xa5c); + ret = __phy_read(phydev, 0x12); + rtl821x_write_page(phydev, 0); +@@ -760,7 +764,11 @@ static int rtlgen_write_mmd(struct phy_d + { + int ret; + +- if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { ++ if (devnum == MDIO_MMD_VEND2) { ++ rtl821x_write_page(phydev, regnum >> 4); ++ ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { + rtl821x_write_page(phydev, 0xa5d); + ret = __phy_write(phydev, 0x10, val); + rtl821x_write_page(phydev, 0); diff --git a/6.12/target/linux/generic/backport-6.12/781-24-v6.14-net-phy-move-realtek-PHY-driver-to-its-own-subdirect.patch b/6.12/target/linux/generic/backport-6.12/781-24-v6.14-net-phy-move-realtek-PHY-driver-to-its-own-subdirect.patch new file mode 100644 index 00000000..5f0b61e0 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/781-24-v6.14-net-phy-move-realtek-PHY-driver-to-its-own-subdirect.patch @@ -0,0 +1,3247 @@ +From 1416a9b2ba710d31954131c06d46f298e340aa2c Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 11 Jan 2025 21:50:19 +0100 +Subject: [PATCH] net: phy: move realtek PHY driver to its own subdirectory + +In preparation of adding a source file with hwmon support, move the +Realtek PHY driver to its own subdirectory and rename realtek.c to +realtek_main.c. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/c566551b-c915-4e34-9b33-129a6ddd6e4c@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/Kconfig | 5 +---- + drivers/net/phy/Makefile | 2 +- + drivers/net/phy/realtek/Kconfig | 5 +++++ + drivers/net/phy/realtek/Makefile | 3 +++ + drivers/net/phy/{realtek.c => realtek/realtek_main.c} | 0 + 5 files changed, 10 insertions(+), 5 deletions(-) + create mode 100644 drivers/net/phy/realtek/Kconfig + create mode 100644 drivers/net/phy/realtek/Makefile + rename drivers/net/phy/{realtek.c => realtek/realtek_main.c} (100%) + +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -358,10 +358,7 @@ config QSEMI_PHY + help + Currently supports the qs6612 + +-config REALTEK_PHY +- tristate "Realtek PHYs" +- help +- Supports the Realtek 821x PHY. ++source "drivers/net/phy/realtek/Kconfig" + + config RENESAS_PHY + tristate "Renesas PHYs" +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -95,7 +95,7 @@ obj-$(CONFIG_NXP_CBTX_PHY) += nxp-cbtx.o + obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o + obj-y += qcom/ + obj-$(CONFIG_QSEMI_PHY) += qsemi.o +-obj-$(CONFIG_REALTEK_PHY) += realtek.o ++obj-$(CONFIG_REALTEK_PHY) += realtek/ + obj-$(CONFIG_RENESAS_PHY) += uPD60620.o + obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o + obj-$(CONFIG_SMSC_PHY) += smsc.o +--- /dev/null ++++ b/drivers/net/phy/realtek/Kconfig +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config REALTEK_PHY ++ tristate "Realtek PHYs" ++ help ++ Currently supports RTL821x/RTL822x and fast ethernet PHYs +--- /dev/null ++++ b/drivers/net/phy/realtek/Makefile +@@ -0,0 +1,3 @@ ++# SPDX-License-Identifier: GPL-2.0 ++realtek-y += realtek_main.o ++obj-$(CONFIG_REALTEK_PHY) += realtek.o +--- a/drivers/net/phy/realtek.c ++++ /dev/null +@@ -1,1589 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0+ +-/* drivers/net/phy/realtek.c +- * +- * Driver for Realtek PHYs +- * +- * Author: Johnson Leung +- * +- * Copyright (c) 2004 Freescale Semiconductor, Inc. +- */ +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define RTL821x_PHYSR 0x11 +-#define RTL821x_PHYSR_DUPLEX BIT(13) +-#define RTL821x_PHYSR_SPEED GENMASK(15, 14) +- +-#define RTL821x_INER 0x12 +-#define RTL8211B_INER_INIT 0x6400 +-#define RTL8211E_INER_LINK_STATUS BIT(10) +-#define RTL8211F_INER_LINK_STATUS BIT(4) +- +-#define RTL821x_INSR 0x13 +- +-#define RTL821x_EXT_PAGE_SELECT 0x1e +-#define RTL821x_PAGE_SELECT 0x1f +- +-#define RTL8211F_PHYCR1 0x18 +-#define RTL8211F_PHYCR2 0x19 +-#define RTL8211F_INSR 0x1d +- +-#define RTL8211F_LEDCR 0x10 +-#define RTL8211F_LEDCR_MODE BIT(15) +-#define RTL8211F_LEDCR_ACT_TXRX BIT(4) +-#define RTL8211F_LEDCR_LINK_1000 BIT(3) +-#define RTL8211F_LEDCR_LINK_100 BIT(1) +-#define RTL8211F_LEDCR_LINK_10 BIT(0) +-#define RTL8211F_LEDCR_MASK GENMASK(4, 0) +-#define RTL8211F_LEDCR_SHIFT 5 +- +-#define RTL8211F_TX_DELAY BIT(8) +-#define RTL8211F_RX_DELAY BIT(3) +- +-#define RTL8211F_ALDPS_PLL_OFF BIT(1) +-#define RTL8211F_ALDPS_ENABLE BIT(2) +-#define RTL8211F_ALDPS_XTAL_OFF BIT(12) +- +-#define RTL8211E_CTRL_DELAY BIT(13) +-#define RTL8211E_TX_DELAY BIT(12) +-#define RTL8211E_RX_DELAY BIT(11) +- +-#define RTL8211F_CLKOUT_EN BIT(0) +- +-#define RTL8201F_ISR 0x1e +-#define RTL8201F_ISR_ANERR BIT(15) +-#define RTL8201F_ISR_DUPLEX BIT(13) +-#define RTL8201F_ISR_LINK BIT(11) +-#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \ +- RTL8201F_ISR_DUPLEX | \ +- RTL8201F_ISR_LINK) +-#define RTL8201F_IER 0x13 +- +-#define RTL822X_VND1_SERDES_OPTION 0x697a +-#define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0) +-#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0 +-#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX 2 +- +-#define RTL822X_VND1_SERDES_CTRL3 0x7580 +-#define RTL822X_VND1_SERDES_CTRL3_MODE_MASK GENMASK(5, 0) +-#define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII 0x02 +-#define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX 0x16 +- +-/* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45 +- * is set, they cannot be accessed by C45-over-C22. +- */ +-#define RTL822X_VND2_GBCR 0xa412 +- +-#define RTL822X_VND2_GANLPAR 0xa414 +- +-#define RTL8366RB_POWER_SAVE 0x15 +-#define RTL8366RB_POWER_SAVE_ON BIT(12) +- +-#define RTL9000A_GINMR 0x14 +-#define RTL9000A_GINMR_LINK_STATUS BIT(4) +- +-#define RTL_VND2_PHYSR 0xa434 +-#define RTL_VND2_PHYSR_DUPLEX BIT(3) +-#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4) +-#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9) +-#define RTL_VND2_PHYSR_MASTER BIT(11) +-#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) +- +-#define RTL_GENERIC_PHYID 0x001cc800 +-#define RTL_8211FVD_PHYID 0x001cc878 +-#define RTL_8221B 0x001cc840 +-#define RTL_8221B_VB_CG 0x001cc849 +-#define RTL_8221B_VN_CG 0x001cc84a +-#define RTL_8251B 0x001cc862 +- +-#define RTL8211F_LED_COUNT 3 +- +-MODULE_DESCRIPTION("Realtek PHY driver"); +-MODULE_AUTHOR("Johnson Leung"); +-MODULE_LICENSE("GPL"); +- +-struct rtl821x_priv { +- u16 phycr1; +- u16 phycr2; +- bool has_phycr2; +- struct clk *clk; +-}; +- +-static int rtl821x_read_page(struct phy_device *phydev) +-{ +- return __phy_read(phydev, RTL821x_PAGE_SELECT); +-} +- +-static int rtl821x_write_page(struct phy_device *phydev, int page) +-{ +- return __phy_write(phydev, RTL821x_PAGE_SELECT, page); +-} +- +-static int rtl821x_probe(struct phy_device *phydev) +-{ +- struct device *dev = &phydev->mdio.dev; +- struct rtl821x_priv *priv; +- u32 phy_id = phydev->drv->phy_id; +- int ret; +- +- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- +- priv->clk = devm_clk_get_optional_enabled(dev, NULL); +- if (IS_ERR(priv->clk)) +- return dev_err_probe(dev, PTR_ERR(priv->clk), +- "failed to get phy clock\n"); +- +- ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1); +- if (ret < 0) +- return ret; +- +- priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF); +- if (of_property_read_bool(dev->of_node, "realtek,aldps-enable")) +- priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF; +- +- priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID); +- if (priv->has_phycr2) { +- ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2); +- if (ret < 0) +- return ret; +- +- priv->phycr2 = ret & RTL8211F_CLKOUT_EN; +- if (of_property_read_bool(dev->of_node, "realtek,clkout-disable")) +- priv->phycr2 &= ~RTL8211F_CLKOUT_EN; +- } +- +- phydev->priv = priv; +- +- return 0; +-} +- +-static int rtl8201_ack_interrupt(struct phy_device *phydev) +-{ +- int err; +- +- err = phy_read(phydev, RTL8201F_ISR); +- +- return (err < 0) ? err : 0; +-} +- +-static int rtl821x_ack_interrupt(struct phy_device *phydev) +-{ +- int err; +- +- err = phy_read(phydev, RTL821x_INSR); +- +- return (err < 0) ? err : 0; +-} +- +-static int rtl8211f_ack_interrupt(struct phy_device *phydev) +-{ +- int err; +- +- err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); +- +- return (err < 0) ? err : 0; +-} +- +-static int rtl8201_config_intr(struct phy_device *phydev) +-{ +- u16 val; +- int err; +- +- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { +- err = rtl8201_ack_interrupt(phydev); +- if (err) +- return err; +- +- val = BIT(13) | BIT(12) | BIT(11); +- err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val); +- } else { +- val = 0; +- err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val); +- if (err) +- return err; +- +- err = rtl8201_ack_interrupt(phydev); +- } +- +- return err; +-} +- +-static int rtl8211b_config_intr(struct phy_device *phydev) +-{ +- int err; +- +- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { +- err = rtl821x_ack_interrupt(phydev); +- if (err) +- return err; +- +- err = phy_write(phydev, RTL821x_INER, +- RTL8211B_INER_INIT); +- } else { +- err = phy_write(phydev, RTL821x_INER, 0); +- if (err) +- return err; +- +- err = rtl821x_ack_interrupt(phydev); +- } +- +- return err; +-} +- +-static int rtl8211e_config_intr(struct phy_device *phydev) +-{ +- int err; +- +- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { +- err = rtl821x_ack_interrupt(phydev); +- if (err) +- return err; +- +- err = phy_write(phydev, RTL821x_INER, +- RTL8211E_INER_LINK_STATUS); +- } else { +- err = phy_write(phydev, RTL821x_INER, 0); +- if (err) +- return err; +- +- err = rtl821x_ack_interrupt(phydev); +- } +- +- return err; +-} +- +-static int rtl8211f_config_intr(struct phy_device *phydev) +-{ +- u16 val; +- int err; +- +- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { +- err = rtl8211f_ack_interrupt(phydev); +- if (err) +- return err; +- +- val = RTL8211F_INER_LINK_STATUS; +- err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val); +- } else { +- val = 0; +- err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val); +- if (err) +- return err; +- +- err = rtl8211f_ack_interrupt(phydev); +- } +- +- return err; +-} +- +-static irqreturn_t rtl8201_handle_interrupt(struct phy_device *phydev) +-{ +- int irq_status; +- +- irq_status = phy_read(phydev, RTL8201F_ISR); +- if (irq_status < 0) { +- phy_error(phydev); +- return IRQ_NONE; +- } +- +- if (!(irq_status & RTL8201F_ISR_MASK)) +- return IRQ_NONE; +- +- phy_trigger_machine(phydev); +- +- return IRQ_HANDLED; +-} +- +-static irqreturn_t rtl821x_handle_interrupt(struct phy_device *phydev) +-{ +- int irq_status, irq_enabled; +- +- irq_status = phy_read(phydev, RTL821x_INSR); +- if (irq_status < 0) { +- phy_error(phydev); +- return IRQ_NONE; +- } +- +- irq_enabled = phy_read(phydev, RTL821x_INER); +- if (irq_enabled < 0) { +- phy_error(phydev); +- return IRQ_NONE; +- } +- +- if (!(irq_status & irq_enabled)) +- return IRQ_NONE; +- +- phy_trigger_machine(phydev); +- +- return IRQ_HANDLED; +-} +- +-static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev) +-{ +- int irq_status; +- +- irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); +- if (irq_status < 0) { +- phy_error(phydev); +- return IRQ_NONE; +- } +- +- if (!(irq_status & RTL8211F_INER_LINK_STATUS)) +- return IRQ_NONE; +- +- phy_trigger_machine(phydev); +- +- return IRQ_HANDLED; +-} +- +-static int rtl8211_config_aneg(struct phy_device *phydev) +-{ +- int ret; +- +- ret = genphy_config_aneg(phydev); +- if (ret < 0) +- return ret; +- +- /* Quirk was copied from vendor driver. Unfortunately it includes no +- * description of the magic numbers. +- */ +- if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) { +- phy_write(phydev, 0x17, 0x2138); +- phy_write(phydev, 0x0e, 0x0260); +- } else { +- phy_write(phydev, 0x17, 0x2108); +- phy_write(phydev, 0x0e, 0x0000); +- } +- +- return 0; +-} +- +-static int rtl8211c_config_init(struct phy_device *phydev) +-{ +- /* RTL8211C has an issue when operating in Gigabit slave mode */ +- return phy_set_bits(phydev, MII_CTRL1000, +- CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER); +-} +- +-static int rtl8211f_config_init(struct phy_device *phydev) +-{ +- struct rtl821x_priv *priv = phydev->priv; +- struct device *dev = &phydev->mdio.dev; +- u16 val_txdly, val_rxdly; +- int ret; +- +- ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1, +- RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, +- priv->phycr1); +- if (ret < 0) { +- dev_err(dev, "aldps mode configuration failed: %pe\n", +- ERR_PTR(ret)); +- return ret; +- } +- +- switch (phydev->interface) { +- case PHY_INTERFACE_MODE_RGMII: +- val_txdly = 0; +- val_rxdly = 0; +- break; +- +- case PHY_INTERFACE_MODE_RGMII_RXID: +- val_txdly = 0; +- val_rxdly = RTL8211F_RX_DELAY; +- break; +- +- case PHY_INTERFACE_MODE_RGMII_TXID: +- val_txdly = RTL8211F_TX_DELAY; +- val_rxdly = 0; +- break; +- +- case PHY_INTERFACE_MODE_RGMII_ID: +- val_txdly = RTL8211F_TX_DELAY; +- val_rxdly = RTL8211F_RX_DELAY; +- break; +- +- default: /* the rest of the modes imply leaving delay as is. */ +- return 0; +- } +- +- ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, +- val_txdly); +- if (ret < 0) { +- dev_err(dev, "Failed to update the TX delay register\n"); +- return ret; +- } else if (ret) { +- dev_dbg(dev, +- "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", +- val_txdly ? "Enabling" : "Disabling"); +- } else { +- dev_dbg(dev, +- "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", +- val_txdly ? "enabled" : "disabled"); +- } +- +- ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, +- val_rxdly); +- if (ret < 0) { +- dev_err(dev, "Failed to update the RX delay register\n"); +- return ret; +- } else if (ret) { +- dev_dbg(dev, +- "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", +- val_rxdly ? "Enabling" : "Disabling"); +- } else { +- dev_dbg(dev, +- "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", +- val_rxdly ? "enabled" : "disabled"); +- } +- +- if (priv->has_phycr2) { +- ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, +- RTL8211F_CLKOUT_EN, priv->phycr2); +- if (ret < 0) { +- dev_err(dev, "clkout configuration failed: %pe\n", +- ERR_PTR(ret)); +- return ret; +- } +- +- return genphy_soft_reset(phydev); +- } +- +- return 0; +-} +- +-static int rtl821x_suspend(struct phy_device *phydev) +-{ +- struct rtl821x_priv *priv = phydev->priv; +- int ret = 0; +- +- if (!phydev->wol_enabled) { +- ret = genphy_suspend(phydev); +- +- if (ret) +- return ret; +- +- clk_disable_unprepare(priv->clk); +- } +- +- return ret; +-} +- +-static int rtl821x_resume(struct phy_device *phydev) +-{ +- struct rtl821x_priv *priv = phydev->priv; +- int ret; +- +- if (!phydev->wol_enabled) +- clk_prepare_enable(priv->clk); +- +- ret = genphy_resume(phydev); +- if (ret < 0) +- return ret; +- +- msleep(20); +- +- return 0; +-} +- +-static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index, +- unsigned long rules) +-{ +- const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) | +- BIT(TRIGGER_NETDEV_LINK_100) | +- BIT(TRIGGER_NETDEV_LINK_1000) | +- BIT(TRIGGER_NETDEV_RX) | +- BIT(TRIGGER_NETDEV_TX); +- +- /* The RTL8211F PHY supports these LED settings on up to three LEDs: +- * - Link: Configurable subset of 10/100/1000 link rates +- * - Active: Blink on activity, RX or TX is not differentiated +- * The Active option has two modes, A and B: +- * - A: Link and Active indication at configurable, but matching, +- * subset of 10/100/1000 link rates +- * - B: Link indication at configurable subset of 10/100/1000 link +- * rates and Active indication always at all three 10+100+1000 +- * link rates. +- * This code currently uses mode B only. +- */ +- +- if (index >= RTL8211F_LED_COUNT) +- return -EINVAL; +- +- /* Filter out any other unsupported triggers. */ +- if (rules & ~mask) +- return -EOPNOTSUPP; +- +- /* RX and TX are not differentiated, either both are set or not set. */ +- if (!(rules & BIT(TRIGGER_NETDEV_RX)) ^ !(rules & BIT(TRIGGER_NETDEV_TX))) +- return -EOPNOTSUPP; +- +- return 0; +-} +- +-static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index, +- unsigned long *rules) +-{ +- int val; +- +- if (index >= RTL8211F_LED_COUNT) +- return -EINVAL; +- +- val = phy_read_paged(phydev, 0xd04, RTL8211F_LEDCR); +- if (val < 0) +- return val; +- +- val >>= RTL8211F_LEDCR_SHIFT * index; +- val &= RTL8211F_LEDCR_MASK; +- +- if (val & RTL8211F_LEDCR_LINK_10) +- set_bit(TRIGGER_NETDEV_LINK_10, rules); +- +- if (val & RTL8211F_LEDCR_LINK_100) +- set_bit(TRIGGER_NETDEV_LINK_100, rules); +- +- if (val & RTL8211F_LEDCR_LINK_1000) +- set_bit(TRIGGER_NETDEV_LINK_1000, rules); +- +- if (val & RTL8211F_LEDCR_ACT_TXRX) { +- set_bit(TRIGGER_NETDEV_RX, rules); +- set_bit(TRIGGER_NETDEV_TX, rules); +- } +- +- return 0; +-} +- +-static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index, +- unsigned long rules) +-{ +- const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index); +- u16 reg = 0; +- +- if (index >= RTL8211F_LED_COUNT) +- return -EINVAL; +- +- if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) +- reg |= RTL8211F_LEDCR_LINK_10; +- +- if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) +- reg |= RTL8211F_LEDCR_LINK_100; +- +- if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) +- reg |= RTL8211F_LEDCR_LINK_1000; +- +- if (test_bit(TRIGGER_NETDEV_RX, &rules) || +- test_bit(TRIGGER_NETDEV_TX, &rules)) { +- reg |= RTL8211F_LEDCR_ACT_TXRX; +- } +- +- reg <<= RTL8211F_LEDCR_SHIFT * index; +- reg |= RTL8211F_LEDCR_MODE; /* Mode B */ +- +- return phy_modify_paged(phydev, 0xd04, RTL8211F_LEDCR, mask, reg); +-} +- +-static int rtl8211e_config_init(struct phy_device *phydev) +-{ +- int ret = 0, oldpage; +- u16 val; +- +- /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */ +- switch (phydev->interface) { +- case PHY_INTERFACE_MODE_RGMII: +- val = RTL8211E_CTRL_DELAY | 0; +- break; +- case PHY_INTERFACE_MODE_RGMII_ID: +- val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY; +- break; +- case PHY_INTERFACE_MODE_RGMII_RXID: +- val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY; +- break; +- case PHY_INTERFACE_MODE_RGMII_TXID: +- val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY; +- break; +- default: /* the rest of the modes imply leaving delays as is. */ +- return 0; +- } +- +- /* According to a sample driver there is a 0x1c config register on the +- * 0xa4 extension page (0x7) layout. It can be used to disable/enable +- * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. +- * The configuration register definition: +- * 14 = reserved +- * 13 = Force Tx RX Delay controlled by bit12 bit11, +- * 12 = RX Delay, 11 = TX Delay +- * 10:0 = Test && debug settings reserved by realtek +- */ +- oldpage = phy_select_page(phydev, 0x7); +- if (oldpage < 0) +- goto err_restore_page; +- +- ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4); +- if (ret) +- goto err_restore_page; +- +- ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY +- | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY, +- val); +- +-err_restore_page: +- return phy_restore_page(phydev, oldpage, ret); +-} +- +-static int rtl8211b_suspend(struct phy_device *phydev) +-{ +- phy_write(phydev, MII_MMD_DATA, BIT(9)); +- +- return genphy_suspend(phydev); +-} +- +-static int rtl8211b_resume(struct phy_device *phydev) +-{ +- phy_write(phydev, MII_MMD_DATA, 0); +- +- return genphy_resume(phydev); +-} +- +-static int rtl8366rb_config_init(struct phy_device *phydev) +-{ +- int ret; +- +- ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE, +- RTL8366RB_POWER_SAVE_ON); +- if (ret) { +- dev_err(&phydev->mdio.dev, +- "error enabling power management\n"); +- } +- +- return ret; +-} +- +-/* get actual speed to cover the downshift case */ +-static void rtlgen_decode_physr(struct phy_device *phydev, int val) +-{ +- /* bit 3 +- * 0: Half Duplex +- * 1: Full Duplex +- */ +- if (val & RTL_VND2_PHYSR_DUPLEX) +- phydev->duplex = DUPLEX_FULL; +- else +- phydev->duplex = DUPLEX_HALF; +- +- switch (val & RTL_VND2_PHYSR_SPEED_MASK) { +- case 0x0000: +- phydev->speed = SPEED_10; +- break; +- case 0x0010: +- phydev->speed = SPEED_100; +- break; +- case 0x0020: +- phydev->speed = SPEED_1000; +- break; +- case 0x0200: +- phydev->speed = SPEED_10000; +- break; +- case 0x0210: +- phydev->speed = SPEED_2500; +- break; +- case 0x0220: +- phydev->speed = SPEED_5000; +- break; +- default: +- break; +- } +- +- /* bit 11 +- * 0: Slave Mode +- * 1: Master Mode +- */ +- if (phydev->speed >= 1000) { +- if (val & RTL_VND2_PHYSR_MASTER) +- phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; +- else +- phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; +- } else { +- phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED; +- } +-} +- +-static int rtlgen_read_status(struct phy_device *phydev) +-{ +- int ret, val; +- +- ret = genphy_read_status(phydev); +- if (ret < 0) +- return ret; +- +- if (!phydev->link) +- return 0; +- +- val = phy_read_paged(phydev, 0xa43, 0x12); +- if (val < 0) +- return val; +- +- rtlgen_decode_physr(phydev, val); +- +- return 0; +-} +- +-static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) +-{ +- int ret; +- +- if (devnum == MDIO_MMD_VEND2) { +- rtl821x_write_page(phydev, regnum >> 4); +- ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { +- rtl821x_write_page(phydev, 0xa5c); +- ret = __phy_read(phydev, 0x12); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { +- rtl821x_write_page(phydev, 0xa5d); +- ret = __phy_read(phydev, 0x10); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) { +- rtl821x_write_page(phydev, 0xa5d); +- ret = __phy_read(phydev, 0x11); +- rtl821x_write_page(phydev, 0); +- } else { +- ret = -EOPNOTSUPP; +- } +- +- return ret; +-} +- +-static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, +- u16 val) +-{ +- int ret; +- +- if (devnum == MDIO_MMD_VEND2) { +- rtl821x_write_page(phydev, regnum >> 4); +- ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { +- rtl821x_write_page(phydev, 0xa5d); +- ret = __phy_write(phydev, 0x10, val); +- rtl821x_write_page(phydev, 0); +- } else { +- ret = -EOPNOTSUPP; +- } +- +- return ret; +-} +- +-static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) +-{ +- int ret = rtlgen_read_mmd(phydev, devnum, regnum); +- +- if (ret != -EOPNOTSUPP) +- return ret; +- +- if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) { +- rtl821x_write_page(phydev, 0xa6e); +- ret = __phy_read(phydev, 0x16); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { +- rtl821x_write_page(phydev, 0xa6d); +- ret = __phy_read(phydev, 0x12); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) { +- rtl821x_write_page(phydev, 0xa6d); +- ret = __phy_read(phydev, 0x10); +- rtl821x_write_page(phydev, 0); +- } +- +- return ret; +-} +- +-static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, +- u16 val) +-{ +- int ret = rtlgen_write_mmd(phydev, devnum, regnum, val); +- +- if (ret != -EOPNOTSUPP) +- return ret; +- +- if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { +- rtl821x_write_page(phydev, 0xa6d); +- ret = __phy_write(phydev, 0x12, val); +- rtl821x_write_page(phydev, 0); +- } +- +- return ret; +-} +- +-static int rtl822xb_config_init(struct phy_device *phydev) +-{ +- bool has_2500, has_sgmii; +- u16 mode; +- int ret; +- +- has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX, +- phydev->host_interfaces) || +- phydev->interface == PHY_INTERFACE_MODE_2500BASEX; +- +- has_sgmii = test_bit(PHY_INTERFACE_MODE_SGMII, +- phydev->host_interfaces) || +- phydev->interface == PHY_INTERFACE_MODE_SGMII; +- +- /* fill in possible interfaces */ +- __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces, +- has_2500); +- __assign_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces, +- has_sgmii); +- +- if (!has_2500 && !has_sgmii) +- return 0; +- +- /* determine SerDes option mode */ +- if (has_2500 && !has_sgmii) { +- mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX; +- phydev->rate_matching = RATE_MATCH_PAUSE; +- } else { +- mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII; +- phydev->rate_matching = RATE_MATCH_NONE; +- } +- +- /* the following sequence with magic numbers sets up the SerDes +- * option mode +- */ +- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); +- if (ret < 0) +- return ret; +- +- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1, +- RTL822X_VND1_SERDES_OPTION, +- RTL822X_VND1_SERDES_OPTION_MODE_MASK, +- mode); +- if (ret < 0) +- return ret; +- +- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); +- if (ret < 0) +- return ret; +- +- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455); +- if (ret < 0) +- return ret; +- +- return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); +-} +- +-static int rtl822xb_get_rate_matching(struct phy_device *phydev, +- phy_interface_t iface) +-{ +- int val; +- +- /* Only rate matching at 2500base-x */ +- if (iface != PHY_INTERFACE_MODE_2500BASEX) +- return RATE_MATCH_NONE; +- +- val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION); +- if (val < 0) +- return val; +- +- if ((val & RTL822X_VND1_SERDES_OPTION_MODE_MASK) == +- RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX) +- return RATE_MATCH_PAUSE; +- +- /* RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII */ +- return RATE_MATCH_NONE; +-} +- +-static int rtl822x_get_features(struct phy_device *phydev) +-{ +- int val; +- +- val = phy_read_paged(phydev, 0xa61, 0x13); +- if (val < 0) +- return val; +- +- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, +- phydev->supported, val & MDIO_PMA_SPEED_2_5G); +- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, +- phydev->supported, val & MDIO_PMA_SPEED_5G); +- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, +- phydev->supported, val & MDIO_SPEED_10G); +- +- return genphy_read_abilities(phydev); +-} +- +-static int rtl822x_config_aneg(struct phy_device *phydev) +-{ +- int ret = 0; +- +- if (phydev->autoneg == AUTONEG_ENABLE) { +- u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); +- +- ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, +- MDIO_AN_10GBT_CTRL_ADV2_5G | +- MDIO_AN_10GBT_CTRL_ADV5G, +- adv); +- if (ret < 0) +- return ret; +- } +- +- return __genphy_config_aneg(phydev, ret); +-} +- +-static void rtl822xb_update_interface(struct phy_device *phydev) +-{ +- int val; +- +- if (!phydev->link) +- return; +- +- /* Change interface according to serdes mode */ +- val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3); +- if (val < 0) +- return; +- +- switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) { +- case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX: +- phydev->interface = PHY_INTERFACE_MODE_2500BASEX; +- break; +- case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII: +- phydev->interface = PHY_INTERFACE_MODE_SGMII; +- break; +- } +-} +- +-static int rtl822x_read_status(struct phy_device *phydev) +-{ +- int lpadv, ret; +- +- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); +- +- ret = rtlgen_read_status(phydev); +- if (ret < 0) +- return ret; +- +- if (phydev->autoneg == AUTONEG_DISABLE || +- !phydev->autoneg_complete) +- return 0; +- +- lpadv = phy_read_paged(phydev, 0xa5d, 0x13); +- if (lpadv < 0) +- return lpadv; +- +- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv); +- +- return 0; +-} +- +-static int rtl822xb_read_status(struct phy_device *phydev) +-{ +- int ret; +- +- ret = rtl822x_read_status(phydev); +- if (ret < 0) +- return ret; +- +- rtl822xb_update_interface(phydev); +- +- return 0; +-} +- +-static int rtl822x_c45_get_features(struct phy_device *phydev) +-{ +- linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, +- phydev->supported); +- +- return genphy_c45_pma_read_abilities(phydev); +-} +- +-static int rtl822x_c45_config_aneg(struct phy_device *phydev) +-{ +- bool changed = false; +- int ret, val; +- +- if (phydev->autoneg == AUTONEG_DISABLE) +- return genphy_c45_pma_setup_forced(phydev); +- +- ret = genphy_c45_an_config_aneg(phydev); +- if (ret < 0) +- return ret; +- if (ret > 0) +- changed = true; +- +- val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); +- +- /* Vendor register as C45 has no standardized support for 1000BaseT */ +- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR, +- ADVERTISE_1000FULL, val); +- if (ret < 0) +- return ret; +- if (ret > 0) +- changed = true; +- +- return genphy_c45_check_and_restart_aneg(phydev, changed); +-} +- +-static int rtl822x_c45_read_status(struct phy_device *phydev) +-{ +- int ret, val; +- +- /* Vendor register as C45 has no standardized support for 1000BaseT */ +- if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { +- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, +- RTL822X_VND2_GANLPAR); +- if (val < 0) +- return val; +- } else { +- val = 0; +- } +- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); +- +- ret = genphy_c45_read_status(phydev); +- if (ret < 0) +- return ret; +- +- if (!phydev->link) { +- phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; +- return 0; +- } +- +- /* Read actual speed from vendor register. */ +- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); +- if (val < 0) +- return val; +- +- rtlgen_decode_physr(phydev, val); +- +- return 0; +-} +- +-static int rtl822xb_c45_read_status(struct phy_device *phydev) +-{ +- int ret; +- +- ret = rtl822x_c45_read_status(phydev); +- if (ret < 0) +- return ret; +- +- rtl822xb_update_interface(phydev); +- +- return 0; +-} +- +-static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) +-{ +- int val; +- +- phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61); +- val = phy_read(phydev, 0x13); +- phy_write(phydev, RTL821x_PAGE_SELECT, 0); +- +- return val >= 0 && val & MDIO_PMA_SPEED_2_5G; +-} +- +-/* On internal PHY's MMD reads over C22 always return 0. +- * Check a MMD register which is known to be non-zero. +- */ +-static bool rtlgen_supports_mmd(struct phy_device *phydev) +-{ +- int val; +- +- phy_lock_mdio_bus(phydev); +- __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS); +- __phy_write(phydev, MII_MMD_DATA, MDIO_PCS_EEE_ABLE); +- __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS | MII_MMD_CTRL_NOINCR); +- val = __phy_read(phydev, MII_MMD_DATA); +- phy_unlock_mdio_bus(phydev); +- +- return val > 0; +-} +- +-static int rtlgen_match_phy_device(struct phy_device *phydev) +-{ +- return phydev->phy_id == RTL_GENERIC_PHYID && +- !rtlgen_supports_2_5gbps(phydev); +-} +- +-static int rtl8226_match_phy_device(struct phy_device *phydev) +-{ +- return phydev->phy_id == RTL_GENERIC_PHYID && +- rtlgen_supports_2_5gbps(phydev) && +- rtlgen_supports_mmd(phydev); +-} +- +-static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, +- bool is_c45) +-{ +- if (phydev->is_c45) +- return is_c45 && (id == phydev->c45_ids.device_ids[1]); +- else +- return !is_c45 && (id == phydev->phy_id); +-} +- +-static int rtl8221b_match_phy_device(struct phy_device *phydev) +-{ +- return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev); +-} +- +-static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) +-{ +- return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false); +-} +- +-static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev) +-{ +- return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true); +-} +- +-static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev) +-{ +- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false); +-} +- +-static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev) +-{ +- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true); +-} +- +-static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) +-{ +- if (phydev->is_c45) +- return false; +- +- switch (phydev->phy_id) { +- case RTL_GENERIC_PHYID: +- case RTL_8221B: +- case RTL_8251B: +- case 0x001cc841: +- break; +- default: +- return false; +- } +- +- return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev); +-} +- +-static int rtl8251b_c45_match_phy_device(struct phy_device *phydev) +-{ +- return rtlgen_is_c45_match(phydev, RTL_8251B, true); +-} +- +-static int rtlgen_resume(struct phy_device *phydev) +-{ +- int ret = genphy_resume(phydev); +- +- /* Internal PHY's from RTL8168h up may not be instantly ready */ +- msleep(20); +- +- return ret; +-} +- +-static int rtlgen_c45_resume(struct phy_device *phydev) +-{ +- int ret = genphy_c45_pma_resume(phydev); +- +- msleep(20); +- +- return ret; +-} +- +-static int rtl9000a_config_init(struct phy_device *phydev) +-{ +- phydev->autoneg = AUTONEG_DISABLE; +- phydev->speed = SPEED_100; +- phydev->duplex = DUPLEX_FULL; +- +- return 0; +-} +- +-static int rtl9000a_config_aneg(struct phy_device *phydev) +-{ +- int ret; +- u16 ctl = 0; +- +- switch (phydev->master_slave_set) { +- case MASTER_SLAVE_CFG_MASTER_FORCE: +- ctl |= CTL1000_AS_MASTER; +- break; +- case MASTER_SLAVE_CFG_SLAVE_FORCE: +- break; +- case MASTER_SLAVE_CFG_UNKNOWN: +- case MASTER_SLAVE_CFG_UNSUPPORTED: +- return 0; +- default: +- phydev_warn(phydev, "Unsupported Master/Slave mode\n"); +- return -EOPNOTSUPP; +- } +- +- ret = phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, ctl); +- if (ret == 1) +- ret = genphy_soft_reset(phydev); +- +- return ret; +-} +- +-static int rtl9000a_read_status(struct phy_device *phydev) +-{ +- int ret; +- +- phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN; +- phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; +- +- ret = genphy_update_link(phydev); +- if (ret) +- return ret; +- +- ret = phy_read(phydev, MII_CTRL1000); +- if (ret < 0) +- return ret; +- if (ret & CTL1000_AS_MASTER) +- phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE; +- else +- phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE; +- +- ret = phy_read(phydev, MII_STAT1000); +- if (ret < 0) +- return ret; +- if (ret & LPA_1000MSRES) +- phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; +- else +- phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; +- +- return 0; +-} +- +-static int rtl9000a_ack_interrupt(struct phy_device *phydev) +-{ +- int err; +- +- err = phy_read(phydev, RTL8211F_INSR); +- +- return (err < 0) ? err : 0; +-} +- +-static int rtl9000a_config_intr(struct phy_device *phydev) +-{ +- u16 val; +- int err; +- +- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { +- err = rtl9000a_ack_interrupt(phydev); +- if (err) +- return err; +- +- val = (u16)~RTL9000A_GINMR_LINK_STATUS; +- err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); +- } else { +- val = ~0; +- err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); +- if (err) +- return err; +- +- err = rtl9000a_ack_interrupt(phydev); +- } +- +- return phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); +-} +- +-static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev) +-{ +- int irq_status; +- +- irq_status = phy_read(phydev, RTL8211F_INSR); +- if (irq_status < 0) { +- phy_error(phydev); +- return IRQ_NONE; +- } +- +- if (!(irq_status & RTL8211F_INER_LINK_STATUS)) +- return IRQ_NONE; +- +- phy_trigger_machine(phydev); +- +- return IRQ_HANDLED; +-} +- +-static struct phy_driver realtek_drvs[] = { +- { +- PHY_ID_MATCH_EXACT(0x00008201), +- .name = "RTL8201CP Ethernet", +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc816), +- .name = "RTL8201F Fast Ethernet", +- .config_intr = &rtl8201_config_intr, +- .handle_interrupt = rtl8201_handle_interrupt, +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_MODEL(0x001cc880), +- .name = "RTL8208 Fast Ethernet", +- .read_mmd = genphy_read_mmd_unsupported, +- .write_mmd = genphy_write_mmd_unsupported, +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc910), +- .name = "RTL8211 Gigabit Ethernet", +- .config_aneg = rtl8211_config_aneg, +- .read_mmd = &genphy_read_mmd_unsupported, +- .write_mmd = &genphy_write_mmd_unsupported, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc912), +- .name = "RTL8211B Gigabit Ethernet", +- .config_intr = &rtl8211b_config_intr, +- .handle_interrupt = rtl821x_handle_interrupt, +- .read_mmd = &genphy_read_mmd_unsupported, +- .write_mmd = &genphy_write_mmd_unsupported, +- .suspend = rtl8211b_suspend, +- .resume = rtl8211b_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc913), +- .name = "RTL8211C Gigabit Ethernet", +- .config_init = rtl8211c_config_init, +- .read_mmd = &genphy_read_mmd_unsupported, +- .write_mmd = &genphy_write_mmd_unsupported, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc914), +- .name = "RTL8211DN Gigabit Ethernet", +- .config_intr = rtl8211e_config_intr, +- .handle_interrupt = rtl821x_handle_interrupt, +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc915), +- .name = "RTL8211E Gigabit Ethernet", +- .config_init = &rtl8211e_config_init, +- .config_intr = &rtl8211e_config_intr, +- .handle_interrupt = rtl821x_handle_interrupt, +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc916), +- .name = "RTL8211F Gigabit Ethernet", +- .probe = rtl821x_probe, +- .config_init = &rtl8211f_config_init, +- .read_status = rtlgen_read_status, +- .config_intr = &rtl8211f_config_intr, +- .handle_interrupt = rtl8211f_handle_interrupt, +- .suspend = rtl821x_suspend, +- .resume = rtl821x_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- .flags = PHY_ALWAYS_CALL_SUSPEND, +- .led_hw_is_supported = rtl8211f_led_hw_is_supported, +- .led_hw_control_get = rtl8211f_led_hw_control_get, +- .led_hw_control_set = rtl8211f_led_hw_control_set, +- }, { +- PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID), +- .name = "RTL8211F-VD Gigabit Ethernet", +- .probe = rtl821x_probe, +- .config_init = &rtl8211f_config_init, +- .read_status = rtlgen_read_status, +- .config_intr = &rtl8211f_config_intr, +- .handle_interrupt = rtl8211f_handle_interrupt, +- .suspend = rtl821x_suspend, +- .resume = rtl821x_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- .flags = PHY_ALWAYS_CALL_SUSPEND, +- }, { +- .name = "Generic FE-GE Realtek PHY", +- .match_phy_device = rtlgen_match_phy_device, +- .read_status = rtlgen_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- .read_mmd = rtlgen_read_mmd, +- .write_mmd = rtlgen_write_mmd, +- }, { +- .name = "RTL8226 2.5Gbps PHY", +- .match_phy_device = rtl8226_match_phy_device, +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .read_status = rtl822x_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- .match_phy_device = rtl8221b_match_phy_device, +- .name = "RTL8226B_RTL8221B 2.5Gbps PHY", +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .config_init = rtl822xb_config_init, +- .get_rate_matching = rtl822xb_get_rate_matching, +- .read_status = rtl822xb_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc838), +- .name = "RTL8226-CG 2.5Gbps PHY", +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .read_status = rtl822x_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc848), +- .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .config_init = rtl822xb_config_init, +- .get_rate_matching = rtl822xb_get_rate_matching, +- .read_status = rtl822xb_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, +- .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .config_init = rtl822xb_config_init, +- .get_rate_matching = rtl822xb_get_rate_matching, +- .read_status = rtl822xb_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, +- .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", +- .config_init = rtl822xb_config_init, +- .get_rate_matching = rtl822xb_get_rate_matching, +- .get_features = rtl822x_c45_get_features, +- .config_aneg = rtl822x_c45_config_aneg, +- .read_status = rtl822xb_c45_read_status, +- .suspend = genphy_c45_pma_suspend, +- .resume = rtlgen_c45_resume, +- }, { +- .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, +- .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .config_init = rtl822xb_config_init, +- .get_rate_matching = rtl822xb_get_rate_matching, +- .read_status = rtl822xb_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, +- .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", +- .config_init = rtl822xb_config_init, +- .get_rate_matching = rtl822xb_get_rate_matching, +- .get_features = rtl822x_c45_get_features, +- .config_aneg = rtl822x_c45_config_aneg, +- .read_status = rtl822xb_c45_read_status, +- .suspend = genphy_c45_pma_suspend, +- .resume = rtlgen_c45_resume, +- }, { +- .match_phy_device = rtl8251b_c45_match_phy_device, +- .name = "RTL8251B 5Gbps PHY", +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .read_status = rtl822x_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- .match_phy_device = rtl_internal_nbaset_match_phy_device, +- .name = "Realtek Internal NBASE-T PHY", +- .flags = PHY_IS_INTERNAL, +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .read_status = rtl822x_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- .read_mmd = rtl822x_read_mmd, +- .write_mmd = rtl822x_write_mmd, +- }, { +- PHY_ID_MATCH_EXACT(0x001ccad0), +- .name = "RTL8224 2.5Gbps PHY", +- .get_features = rtl822x_c45_get_features, +- .config_aneg = rtl822x_c45_config_aneg, +- .read_status = rtl822x_c45_read_status, +- .suspend = genphy_c45_pma_suspend, +- .resume = rtlgen_c45_resume, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc961), +- .name = "RTL8366RB Gigabit Ethernet", +- .config_init = &rtl8366rb_config_init, +- /* These interrupts are handled by the irq controller +- * embedded inside the RTL8366RB, they get unmasked when the +- * irq is requested and ACKed by reading the status register, +- * which is done by the irqchip code. +- */ +- .config_intr = genphy_no_config_intr, +- .handle_interrupt = genphy_handle_interrupt_no_ack, +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- }, { +- PHY_ID_MATCH_EXACT(0x001ccb00), +- .name = "RTL9000AA_RTL9000AN Ethernet", +- .features = PHY_BASIC_T1_FEATURES, +- .config_init = rtl9000a_config_init, +- .config_aneg = rtl9000a_config_aneg, +- .read_status = rtl9000a_read_status, +- .config_intr = rtl9000a_config_intr, +- .handle_interrupt = rtl9000a_handle_interrupt, +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc942), +- .name = "RTL8365MB-VC Gigabit Ethernet", +- /* Interrupt handling analogous to RTL8366RB */ +- .config_intr = genphy_no_config_intr, +- .handle_interrupt = genphy_handle_interrupt_no_ack, +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc960), +- .name = "RTL8366S Gigabit Ethernet", +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- .read_mmd = genphy_read_mmd_unsupported, +- .write_mmd = genphy_write_mmd_unsupported, +- }, +-}; +- +-module_phy_driver(realtek_drvs); +- +-static const struct mdio_device_id __maybe_unused realtek_tbl[] = { +- { PHY_ID_MATCH_VENDOR(0x001cc800) }, +- { } +-}; +- +-MODULE_DEVICE_TABLE(mdio, realtek_tbl); +--- /dev/null ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -0,0 +1,1589 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* drivers/net/phy/realtek.c ++ * ++ * Driver for Realtek PHYs ++ * ++ * Author: Johnson Leung ++ * ++ * Copyright (c) 2004 Freescale Semiconductor, Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define RTL821x_PHYSR 0x11 ++#define RTL821x_PHYSR_DUPLEX BIT(13) ++#define RTL821x_PHYSR_SPEED GENMASK(15, 14) ++ ++#define RTL821x_INER 0x12 ++#define RTL8211B_INER_INIT 0x6400 ++#define RTL8211E_INER_LINK_STATUS BIT(10) ++#define RTL8211F_INER_LINK_STATUS BIT(4) ++ ++#define RTL821x_INSR 0x13 ++ ++#define RTL821x_EXT_PAGE_SELECT 0x1e ++#define RTL821x_PAGE_SELECT 0x1f ++ ++#define RTL8211F_PHYCR1 0x18 ++#define RTL8211F_PHYCR2 0x19 ++#define RTL8211F_INSR 0x1d ++ ++#define RTL8211F_LEDCR 0x10 ++#define RTL8211F_LEDCR_MODE BIT(15) ++#define RTL8211F_LEDCR_ACT_TXRX BIT(4) ++#define RTL8211F_LEDCR_LINK_1000 BIT(3) ++#define RTL8211F_LEDCR_LINK_100 BIT(1) ++#define RTL8211F_LEDCR_LINK_10 BIT(0) ++#define RTL8211F_LEDCR_MASK GENMASK(4, 0) ++#define RTL8211F_LEDCR_SHIFT 5 ++ ++#define RTL8211F_TX_DELAY BIT(8) ++#define RTL8211F_RX_DELAY BIT(3) ++ ++#define RTL8211F_ALDPS_PLL_OFF BIT(1) ++#define RTL8211F_ALDPS_ENABLE BIT(2) ++#define RTL8211F_ALDPS_XTAL_OFF BIT(12) ++ ++#define RTL8211E_CTRL_DELAY BIT(13) ++#define RTL8211E_TX_DELAY BIT(12) ++#define RTL8211E_RX_DELAY BIT(11) ++ ++#define RTL8211F_CLKOUT_EN BIT(0) ++ ++#define RTL8201F_ISR 0x1e ++#define RTL8201F_ISR_ANERR BIT(15) ++#define RTL8201F_ISR_DUPLEX BIT(13) ++#define RTL8201F_ISR_LINK BIT(11) ++#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \ ++ RTL8201F_ISR_DUPLEX | \ ++ RTL8201F_ISR_LINK) ++#define RTL8201F_IER 0x13 ++ ++#define RTL822X_VND1_SERDES_OPTION 0x697a ++#define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0) ++#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0 ++#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX 2 ++ ++#define RTL822X_VND1_SERDES_CTRL3 0x7580 ++#define RTL822X_VND1_SERDES_CTRL3_MODE_MASK GENMASK(5, 0) ++#define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII 0x02 ++#define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX 0x16 ++ ++/* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45 ++ * is set, they cannot be accessed by C45-over-C22. ++ */ ++#define RTL822X_VND2_GBCR 0xa412 ++ ++#define RTL822X_VND2_GANLPAR 0xa414 ++ ++#define RTL8366RB_POWER_SAVE 0x15 ++#define RTL8366RB_POWER_SAVE_ON BIT(12) ++ ++#define RTL9000A_GINMR 0x14 ++#define RTL9000A_GINMR_LINK_STATUS BIT(4) ++ ++#define RTL_VND2_PHYSR 0xa434 ++#define RTL_VND2_PHYSR_DUPLEX BIT(3) ++#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4) ++#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9) ++#define RTL_VND2_PHYSR_MASTER BIT(11) ++#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) ++ ++#define RTL_GENERIC_PHYID 0x001cc800 ++#define RTL_8211FVD_PHYID 0x001cc878 ++#define RTL_8221B 0x001cc840 ++#define RTL_8221B_VB_CG 0x001cc849 ++#define RTL_8221B_VN_CG 0x001cc84a ++#define RTL_8251B 0x001cc862 ++ ++#define RTL8211F_LED_COUNT 3 ++ ++MODULE_DESCRIPTION("Realtek PHY driver"); ++MODULE_AUTHOR("Johnson Leung"); ++MODULE_LICENSE("GPL"); ++ ++struct rtl821x_priv { ++ u16 phycr1; ++ u16 phycr2; ++ bool has_phycr2; ++ struct clk *clk; ++}; ++ ++static int rtl821x_read_page(struct phy_device *phydev) ++{ ++ return __phy_read(phydev, RTL821x_PAGE_SELECT); ++} ++ ++static int rtl821x_write_page(struct phy_device *phydev, int page) ++{ ++ return __phy_write(phydev, RTL821x_PAGE_SELECT, page); ++} ++ ++static int rtl821x_probe(struct phy_device *phydev) ++{ ++ struct device *dev = &phydev->mdio.dev; ++ struct rtl821x_priv *priv; ++ u32 phy_id = phydev->drv->phy_id; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->clk = devm_clk_get_optional_enabled(dev, NULL); ++ if (IS_ERR(priv->clk)) ++ return dev_err_probe(dev, PTR_ERR(priv->clk), ++ "failed to get phy clock\n"); ++ ++ ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1); ++ if (ret < 0) ++ return ret; ++ ++ priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF); ++ if (of_property_read_bool(dev->of_node, "realtek,aldps-enable")) ++ priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF; ++ ++ priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID); ++ if (priv->has_phycr2) { ++ ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2); ++ if (ret < 0) ++ return ret; ++ ++ priv->phycr2 = ret & RTL8211F_CLKOUT_EN; ++ if (of_property_read_bool(dev->of_node, "realtek,clkout-disable")) ++ priv->phycr2 &= ~RTL8211F_CLKOUT_EN; ++ } ++ ++ phydev->priv = priv; ++ ++ return 0; ++} ++ ++static int rtl8201_ack_interrupt(struct phy_device *phydev) ++{ ++ int err; ++ ++ err = phy_read(phydev, RTL8201F_ISR); ++ ++ return (err < 0) ? err : 0; ++} ++ ++static int rtl821x_ack_interrupt(struct phy_device *phydev) ++{ ++ int err; ++ ++ err = phy_read(phydev, RTL821x_INSR); ++ ++ return (err < 0) ? err : 0; ++} ++ ++static int rtl8211f_ack_interrupt(struct phy_device *phydev) ++{ ++ int err; ++ ++ err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); ++ ++ return (err < 0) ? err : 0; ++} ++ ++static int rtl8201_config_intr(struct phy_device *phydev) ++{ ++ u16 val; ++ int err; ++ ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { ++ err = rtl8201_ack_interrupt(phydev); ++ if (err) ++ return err; ++ ++ val = BIT(13) | BIT(12) | BIT(11); ++ err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val); ++ } else { ++ val = 0; ++ err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val); ++ if (err) ++ return err; ++ ++ err = rtl8201_ack_interrupt(phydev); ++ } ++ ++ return err; ++} ++ ++static int rtl8211b_config_intr(struct phy_device *phydev) ++{ ++ int err; ++ ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { ++ err = rtl821x_ack_interrupt(phydev); ++ if (err) ++ return err; ++ ++ err = phy_write(phydev, RTL821x_INER, ++ RTL8211B_INER_INIT); ++ } else { ++ err = phy_write(phydev, RTL821x_INER, 0); ++ if (err) ++ return err; ++ ++ err = rtl821x_ack_interrupt(phydev); ++ } ++ ++ return err; ++} ++ ++static int rtl8211e_config_intr(struct phy_device *phydev) ++{ ++ int err; ++ ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { ++ err = rtl821x_ack_interrupt(phydev); ++ if (err) ++ return err; ++ ++ err = phy_write(phydev, RTL821x_INER, ++ RTL8211E_INER_LINK_STATUS); ++ } else { ++ err = phy_write(phydev, RTL821x_INER, 0); ++ if (err) ++ return err; ++ ++ err = rtl821x_ack_interrupt(phydev); ++ } ++ ++ return err; ++} ++ ++static int rtl8211f_config_intr(struct phy_device *phydev) ++{ ++ u16 val; ++ int err; ++ ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { ++ err = rtl8211f_ack_interrupt(phydev); ++ if (err) ++ return err; ++ ++ val = RTL8211F_INER_LINK_STATUS; ++ err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val); ++ } else { ++ val = 0; ++ err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val); ++ if (err) ++ return err; ++ ++ err = rtl8211f_ack_interrupt(phydev); ++ } ++ ++ return err; ++} ++ ++static irqreturn_t rtl8201_handle_interrupt(struct phy_device *phydev) ++{ ++ int irq_status; ++ ++ irq_status = phy_read(phydev, RTL8201F_ISR); ++ if (irq_status < 0) { ++ phy_error(phydev); ++ return IRQ_NONE; ++ } ++ ++ if (!(irq_status & RTL8201F_ISR_MASK)) ++ return IRQ_NONE; ++ ++ phy_trigger_machine(phydev); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t rtl821x_handle_interrupt(struct phy_device *phydev) ++{ ++ int irq_status, irq_enabled; ++ ++ irq_status = phy_read(phydev, RTL821x_INSR); ++ if (irq_status < 0) { ++ phy_error(phydev); ++ return IRQ_NONE; ++ } ++ ++ irq_enabled = phy_read(phydev, RTL821x_INER); ++ if (irq_enabled < 0) { ++ phy_error(phydev); ++ return IRQ_NONE; ++ } ++ ++ if (!(irq_status & irq_enabled)) ++ return IRQ_NONE; ++ ++ phy_trigger_machine(phydev); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev) ++{ ++ int irq_status; ++ ++ irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); ++ if (irq_status < 0) { ++ phy_error(phydev); ++ return IRQ_NONE; ++ } ++ ++ if (!(irq_status & RTL8211F_INER_LINK_STATUS)) ++ return IRQ_NONE; ++ ++ phy_trigger_machine(phydev); ++ ++ return IRQ_HANDLED; ++} ++ ++static int rtl8211_config_aneg(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = genphy_config_aneg(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* Quirk was copied from vendor driver. Unfortunately it includes no ++ * description of the magic numbers. ++ */ ++ if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) { ++ phy_write(phydev, 0x17, 0x2138); ++ phy_write(phydev, 0x0e, 0x0260); ++ } else { ++ phy_write(phydev, 0x17, 0x2108); ++ phy_write(phydev, 0x0e, 0x0000); ++ } ++ ++ return 0; ++} ++ ++static int rtl8211c_config_init(struct phy_device *phydev) ++{ ++ /* RTL8211C has an issue when operating in Gigabit slave mode */ ++ return phy_set_bits(phydev, MII_CTRL1000, ++ CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER); ++} ++ ++static int rtl8211f_config_init(struct phy_device *phydev) ++{ ++ struct rtl821x_priv *priv = phydev->priv; ++ struct device *dev = &phydev->mdio.dev; ++ u16 val_txdly, val_rxdly; ++ int ret; ++ ++ ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1, ++ RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, ++ priv->phycr1); ++ if (ret < 0) { ++ dev_err(dev, "aldps mode configuration failed: %pe\n", ++ ERR_PTR(ret)); ++ return ret; ++ } ++ ++ switch (phydev->interface) { ++ case PHY_INTERFACE_MODE_RGMII: ++ val_txdly = 0; ++ val_rxdly = 0; ++ break; ++ ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ val_txdly = 0; ++ val_rxdly = RTL8211F_RX_DELAY; ++ break; ++ ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ val_txdly = RTL8211F_TX_DELAY; ++ val_rxdly = 0; ++ break; ++ ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ val_txdly = RTL8211F_TX_DELAY; ++ val_rxdly = RTL8211F_RX_DELAY; ++ break; ++ ++ default: /* the rest of the modes imply leaving delay as is. */ ++ return 0; ++ } ++ ++ ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, ++ val_txdly); ++ if (ret < 0) { ++ dev_err(dev, "Failed to update the TX delay register\n"); ++ return ret; ++ } else if (ret) { ++ dev_dbg(dev, ++ "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", ++ val_txdly ? "Enabling" : "Disabling"); ++ } else { ++ dev_dbg(dev, ++ "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", ++ val_txdly ? "enabled" : "disabled"); ++ } ++ ++ ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, ++ val_rxdly); ++ if (ret < 0) { ++ dev_err(dev, "Failed to update the RX delay register\n"); ++ return ret; ++ } else if (ret) { ++ dev_dbg(dev, ++ "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", ++ val_rxdly ? "Enabling" : "Disabling"); ++ } else { ++ dev_dbg(dev, ++ "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", ++ val_rxdly ? "enabled" : "disabled"); ++ } ++ ++ if (priv->has_phycr2) { ++ ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, ++ RTL8211F_CLKOUT_EN, priv->phycr2); ++ if (ret < 0) { ++ dev_err(dev, "clkout configuration failed: %pe\n", ++ ERR_PTR(ret)); ++ return ret; ++ } ++ ++ return genphy_soft_reset(phydev); ++ } ++ ++ return 0; ++} ++ ++static int rtl821x_suspend(struct phy_device *phydev) ++{ ++ struct rtl821x_priv *priv = phydev->priv; ++ int ret = 0; ++ ++ if (!phydev->wol_enabled) { ++ ret = genphy_suspend(phydev); ++ ++ if (ret) ++ return ret; ++ ++ clk_disable_unprepare(priv->clk); ++ } ++ ++ return ret; ++} ++ ++static int rtl821x_resume(struct phy_device *phydev) ++{ ++ struct rtl821x_priv *priv = phydev->priv; ++ int ret; ++ ++ if (!phydev->wol_enabled) ++ clk_prepare_enable(priv->clk); ++ ++ ret = genphy_resume(phydev); ++ if (ret < 0) ++ return ret; ++ ++ msleep(20); ++ ++ return 0; ++} ++ ++static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index, ++ unsigned long rules) ++{ ++ const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) | ++ BIT(TRIGGER_NETDEV_LINK_100) | ++ BIT(TRIGGER_NETDEV_LINK_1000) | ++ BIT(TRIGGER_NETDEV_RX) | ++ BIT(TRIGGER_NETDEV_TX); ++ ++ /* The RTL8211F PHY supports these LED settings on up to three LEDs: ++ * - Link: Configurable subset of 10/100/1000 link rates ++ * - Active: Blink on activity, RX or TX is not differentiated ++ * The Active option has two modes, A and B: ++ * - A: Link and Active indication at configurable, but matching, ++ * subset of 10/100/1000 link rates ++ * - B: Link indication at configurable subset of 10/100/1000 link ++ * rates and Active indication always at all three 10+100+1000 ++ * link rates. ++ * This code currently uses mode B only. ++ */ ++ ++ if (index >= RTL8211F_LED_COUNT) ++ return -EINVAL; ++ ++ /* Filter out any other unsupported triggers. */ ++ if (rules & ~mask) ++ return -EOPNOTSUPP; ++ ++ /* RX and TX are not differentiated, either both are set or not set. */ ++ if (!(rules & BIT(TRIGGER_NETDEV_RX)) ^ !(rules & BIT(TRIGGER_NETDEV_TX))) ++ return -EOPNOTSUPP; ++ ++ return 0; ++} ++ ++static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index, ++ unsigned long *rules) ++{ ++ int val; ++ ++ if (index >= RTL8211F_LED_COUNT) ++ return -EINVAL; ++ ++ val = phy_read_paged(phydev, 0xd04, RTL8211F_LEDCR); ++ if (val < 0) ++ return val; ++ ++ val >>= RTL8211F_LEDCR_SHIFT * index; ++ val &= RTL8211F_LEDCR_MASK; ++ ++ if (val & RTL8211F_LEDCR_LINK_10) ++ set_bit(TRIGGER_NETDEV_LINK_10, rules); ++ ++ if (val & RTL8211F_LEDCR_LINK_100) ++ set_bit(TRIGGER_NETDEV_LINK_100, rules); ++ ++ if (val & RTL8211F_LEDCR_LINK_1000) ++ set_bit(TRIGGER_NETDEV_LINK_1000, rules); ++ ++ if (val & RTL8211F_LEDCR_ACT_TXRX) { ++ set_bit(TRIGGER_NETDEV_RX, rules); ++ set_bit(TRIGGER_NETDEV_TX, rules); ++ } ++ ++ return 0; ++} ++ ++static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index, ++ unsigned long rules) ++{ ++ const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index); ++ u16 reg = 0; ++ ++ if (index >= RTL8211F_LED_COUNT) ++ return -EINVAL; ++ ++ if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) ++ reg |= RTL8211F_LEDCR_LINK_10; ++ ++ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) ++ reg |= RTL8211F_LEDCR_LINK_100; ++ ++ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) ++ reg |= RTL8211F_LEDCR_LINK_1000; ++ ++ if (test_bit(TRIGGER_NETDEV_RX, &rules) || ++ test_bit(TRIGGER_NETDEV_TX, &rules)) { ++ reg |= RTL8211F_LEDCR_ACT_TXRX; ++ } ++ ++ reg <<= RTL8211F_LEDCR_SHIFT * index; ++ reg |= RTL8211F_LEDCR_MODE; /* Mode B */ ++ ++ return phy_modify_paged(phydev, 0xd04, RTL8211F_LEDCR, mask, reg); ++} ++ ++static int rtl8211e_config_init(struct phy_device *phydev) ++{ ++ int ret = 0, oldpage; ++ u16 val; ++ ++ /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */ ++ switch (phydev->interface) { ++ case PHY_INTERFACE_MODE_RGMII: ++ val = RTL8211E_CTRL_DELAY | 0; ++ break; ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY; ++ break; ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY; ++ break; ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY; ++ break; ++ default: /* the rest of the modes imply leaving delays as is. */ ++ return 0; ++ } ++ ++ /* According to a sample driver there is a 0x1c config register on the ++ * 0xa4 extension page (0x7) layout. It can be used to disable/enable ++ * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. ++ * The configuration register definition: ++ * 14 = reserved ++ * 13 = Force Tx RX Delay controlled by bit12 bit11, ++ * 12 = RX Delay, 11 = TX Delay ++ * 10:0 = Test && debug settings reserved by realtek ++ */ ++ oldpage = phy_select_page(phydev, 0x7); ++ if (oldpage < 0) ++ goto err_restore_page; ++ ++ ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4); ++ if (ret) ++ goto err_restore_page; ++ ++ ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY ++ | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY, ++ val); ++ ++err_restore_page: ++ return phy_restore_page(phydev, oldpage, ret); ++} ++ ++static int rtl8211b_suspend(struct phy_device *phydev) ++{ ++ phy_write(phydev, MII_MMD_DATA, BIT(9)); ++ ++ return genphy_suspend(phydev); ++} ++ ++static int rtl8211b_resume(struct phy_device *phydev) ++{ ++ phy_write(phydev, MII_MMD_DATA, 0); ++ ++ return genphy_resume(phydev); ++} ++ ++static int rtl8366rb_config_init(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE, ++ RTL8366RB_POWER_SAVE_ON); ++ if (ret) { ++ dev_err(&phydev->mdio.dev, ++ "error enabling power management\n"); ++ } ++ ++ return ret; ++} ++ ++/* get actual speed to cover the downshift case */ ++static void rtlgen_decode_physr(struct phy_device *phydev, int val) ++{ ++ /* bit 3 ++ * 0: Half Duplex ++ * 1: Full Duplex ++ */ ++ if (val & RTL_VND2_PHYSR_DUPLEX) ++ phydev->duplex = DUPLEX_FULL; ++ else ++ phydev->duplex = DUPLEX_HALF; ++ ++ switch (val & RTL_VND2_PHYSR_SPEED_MASK) { ++ case 0x0000: ++ phydev->speed = SPEED_10; ++ break; ++ case 0x0010: ++ phydev->speed = SPEED_100; ++ break; ++ case 0x0020: ++ phydev->speed = SPEED_1000; ++ break; ++ case 0x0200: ++ phydev->speed = SPEED_10000; ++ break; ++ case 0x0210: ++ phydev->speed = SPEED_2500; ++ break; ++ case 0x0220: ++ phydev->speed = SPEED_5000; ++ break; ++ default: ++ break; ++ } ++ ++ /* bit 11 ++ * 0: Slave Mode ++ * 1: Master Mode ++ */ ++ if (phydev->speed >= 1000) { ++ if (val & RTL_VND2_PHYSR_MASTER) ++ phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; ++ else ++ phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; ++ } else { ++ phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED; ++ } ++} ++ ++static int rtlgen_read_status(struct phy_device *phydev) ++{ ++ int ret, val; ++ ++ ret = genphy_read_status(phydev); ++ if (ret < 0) ++ return ret; ++ ++ if (!phydev->link) ++ return 0; ++ ++ val = phy_read_paged(phydev, 0xa43, 0x12); ++ if (val < 0) ++ return val; ++ ++ rtlgen_decode_physr(phydev, val); ++ ++ return 0; ++} ++ ++static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) ++{ ++ int ret; ++ ++ if (devnum == MDIO_MMD_VEND2) { ++ rtl821x_write_page(phydev, regnum >> 4); ++ ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { ++ rtl821x_write_page(phydev, 0xa5c); ++ ret = __phy_read(phydev, 0x12); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { ++ rtl821x_write_page(phydev, 0xa5d); ++ ret = __phy_read(phydev, 0x10); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) { ++ rtl821x_write_page(phydev, 0xa5d); ++ ret = __phy_read(phydev, 0x11); ++ rtl821x_write_page(phydev, 0); ++ } else { ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, ++ u16 val) ++{ ++ int ret; ++ ++ if (devnum == MDIO_MMD_VEND2) { ++ rtl821x_write_page(phydev, regnum >> 4); ++ ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { ++ rtl821x_write_page(phydev, 0xa5d); ++ ret = __phy_write(phydev, 0x10, val); ++ rtl821x_write_page(phydev, 0); ++ } else { ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) ++{ ++ int ret = rtlgen_read_mmd(phydev, devnum, regnum); ++ ++ if (ret != -EOPNOTSUPP) ++ return ret; ++ ++ if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) { ++ rtl821x_write_page(phydev, 0xa6e); ++ ret = __phy_read(phydev, 0x16); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { ++ rtl821x_write_page(phydev, 0xa6d); ++ ret = __phy_read(phydev, 0x12); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) { ++ rtl821x_write_page(phydev, 0xa6d); ++ ret = __phy_read(phydev, 0x10); ++ rtl821x_write_page(phydev, 0); ++ } ++ ++ return ret; ++} ++ ++static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, ++ u16 val) ++{ ++ int ret = rtlgen_write_mmd(phydev, devnum, regnum, val); ++ ++ if (ret != -EOPNOTSUPP) ++ return ret; ++ ++ if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { ++ rtl821x_write_page(phydev, 0xa6d); ++ ret = __phy_write(phydev, 0x12, val); ++ rtl821x_write_page(phydev, 0); ++ } ++ ++ return ret; ++} ++ ++static int rtl822xb_config_init(struct phy_device *phydev) ++{ ++ bool has_2500, has_sgmii; ++ u16 mode; ++ int ret; ++ ++ has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX, ++ phydev->host_interfaces) || ++ phydev->interface == PHY_INTERFACE_MODE_2500BASEX; ++ ++ has_sgmii = test_bit(PHY_INTERFACE_MODE_SGMII, ++ phydev->host_interfaces) || ++ phydev->interface == PHY_INTERFACE_MODE_SGMII; ++ ++ /* fill in possible interfaces */ ++ __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces, ++ has_2500); ++ __assign_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces, ++ has_sgmii); ++ ++ if (!has_2500 && !has_sgmii) ++ return 0; ++ ++ /* determine SerDes option mode */ ++ if (has_2500 && !has_sgmii) { ++ mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX; ++ phydev->rate_matching = RATE_MATCH_PAUSE; ++ } else { ++ mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII; ++ phydev->rate_matching = RATE_MATCH_NONE; ++ } ++ ++ /* the following sequence with magic numbers sets up the SerDes ++ * option mode ++ */ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1, ++ RTL822X_VND1_SERDES_OPTION, ++ RTL822X_VND1_SERDES_OPTION_MODE_MASK, ++ mode); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455); ++ if (ret < 0) ++ return ret; ++ ++ return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); ++} ++ ++static int rtl822xb_get_rate_matching(struct phy_device *phydev, ++ phy_interface_t iface) ++{ ++ int val; ++ ++ /* Only rate matching at 2500base-x */ ++ if (iface != PHY_INTERFACE_MODE_2500BASEX) ++ return RATE_MATCH_NONE; ++ ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION); ++ if (val < 0) ++ return val; ++ ++ if ((val & RTL822X_VND1_SERDES_OPTION_MODE_MASK) == ++ RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX) ++ return RATE_MATCH_PAUSE; ++ ++ /* RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII */ ++ return RATE_MATCH_NONE; ++} ++ ++static int rtl822x_get_features(struct phy_device *phydev) ++{ ++ int val; ++ ++ val = phy_read_paged(phydev, 0xa61, 0x13); ++ if (val < 0) ++ return val; ++ ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, ++ phydev->supported, val & MDIO_PMA_SPEED_2_5G); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, ++ phydev->supported, val & MDIO_PMA_SPEED_5G); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, ++ phydev->supported, val & MDIO_SPEED_10G); ++ ++ return genphy_read_abilities(phydev); ++} ++ ++static int rtl822x_config_aneg(struct phy_device *phydev) ++{ ++ int ret = 0; ++ ++ if (phydev->autoneg == AUTONEG_ENABLE) { ++ u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); ++ ++ ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, ++ MDIO_AN_10GBT_CTRL_ADV2_5G | ++ MDIO_AN_10GBT_CTRL_ADV5G, ++ adv); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return __genphy_config_aneg(phydev, ret); ++} ++ ++static void rtl822xb_update_interface(struct phy_device *phydev) ++{ ++ int val; ++ ++ if (!phydev->link) ++ return; ++ ++ /* Change interface according to serdes mode */ ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3); ++ if (val < 0) ++ return; ++ ++ switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) { ++ case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX: ++ phydev->interface = PHY_INTERFACE_MODE_2500BASEX; ++ break; ++ case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII: ++ phydev->interface = PHY_INTERFACE_MODE_SGMII; ++ break; ++ } ++} ++ ++static int rtl822x_read_status(struct phy_device *phydev) ++{ ++ int lpadv, ret; ++ ++ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); ++ ++ ret = rtlgen_read_status(phydev); ++ if (ret < 0) ++ return ret; ++ ++ if (phydev->autoneg == AUTONEG_DISABLE || ++ !phydev->autoneg_complete) ++ return 0; ++ ++ lpadv = phy_read_paged(phydev, 0xa5d, 0x13); ++ if (lpadv < 0) ++ return lpadv; ++ ++ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv); ++ ++ return 0; ++} ++ ++static int rtl822xb_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = rtl822x_read_status(phydev); ++ if (ret < 0) ++ return ret; ++ ++ rtl822xb_update_interface(phydev); ++ ++ return 0; ++} ++ ++static int rtl822x_c45_get_features(struct phy_device *phydev) ++{ ++ linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, ++ phydev->supported); ++ ++ return genphy_c45_pma_read_abilities(phydev); ++} ++ ++static int rtl822x_c45_config_aneg(struct phy_device *phydev) ++{ ++ bool changed = false; ++ int ret, val; ++ ++ if (phydev->autoneg == AUTONEG_DISABLE) ++ return genphy_c45_pma_setup_forced(phydev); ++ ++ ret = genphy_c45_an_config_aneg(phydev); ++ if (ret < 0) ++ return ret; ++ if (ret > 0) ++ changed = true; ++ ++ val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); ++ ++ /* Vendor register as C45 has no standardized support for 1000BaseT */ ++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR, ++ ADVERTISE_1000FULL, val); ++ if (ret < 0) ++ return ret; ++ if (ret > 0) ++ changed = true; ++ ++ return genphy_c45_check_and_restart_aneg(phydev, changed); ++} ++ ++static int rtl822x_c45_read_status(struct phy_device *phydev) ++{ ++ int ret, val; ++ ++ /* Vendor register as C45 has no standardized support for 1000BaseT */ ++ if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, ++ RTL822X_VND2_GANLPAR); ++ if (val < 0) ++ return val; ++ } else { ++ val = 0; ++ } ++ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); ++ ++ ret = genphy_c45_read_status(phydev); ++ if (ret < 0) ++ return ret; ++ ++ if (!phydev->link) { ++ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; ++ return 0; ++ } ++ ++ /* Read actual speed from vendor register. */ ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); ++ if (val < 0) ++ return val; ++ ++ rtlgen_decode_physr(phydev, val); ++ ++ return 0; ++} ++ ++static int rtl822xb_c45_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = rtl822x_c45_read_status(phydev); ++ if (ret < 0) ++ return ret; ++ ++ rtl822xb_update_interface(phydev); ++ ++ return 0; ++} ++ ++static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) ++{ ++ int val; ++ ++ phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61); ++ val = phy_read(phydev, 0x13); ++ phy_write(phydev, RTL821x_PAGE_SELECT, 0); ++ ++ return val >= 0 && val & MDIO_PMA_SPEED_2_5G; ++} ++ ++/* On internal PHY's MMD reads over C22 always return 0. ++ * Check a MMD register which is known to be non-zero. ++ */ ++static bool rtlgen_supports_mmd(struct phy_device *phydev) ++{ ++ int val; ++ ++ phy_lock_mdio_bus(phydev); ++ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS); ++ __phy_write(phydev, MII_MMD_DATA, MDIO_PCS_EEE_ABLE); ++ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS | MII_MMD_CTRL_NOINCR); ++ val = __phy_read(phydev, MII_MMD_DATA); ++ phy_unlock_mdio_bus(phydev); ++ ++ return val > 0; ++} ++ ++static int rtlgen_match_phy_device(struct phy_device *phydev) ++{ ++ return phydev->phy_id == RTL_GENERIC_PHYID && ++ !rtlgen_supports_2_5gbps(phydev); ++} ++ ++static int rtl8226_match_phy_device(struct phy_device *phydev) ++{ ++ return phydev->phy_id == RTL_GENERIC_PHYID && ++ rtlgen_supports_2_5gbps(phydev) && ++ rtlgen_supports_mmd(phydev); ++} ++ ++static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, ++ bool is_c45) ++{ ++ if (phydev->is_c45) ++ return is_c45 && (id == phydev->c45_ids.device_ids[1]); ++ else ++ return !is_c45 && (id == phydev->phy_id); ++} ++ ++static int rtl8221b_match_phy_device(struct phy_device *phydev) ++{ ++ return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev); ++} ++ ++static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) ++{ ++ return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false); ++} ++ ++static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev) ++{ ++ return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true); ++} ++ ++static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev) ++{ ++ return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false); ++} ++ ++static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev) ++{ ++ return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true); ++} ++ ++static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) ++{ ++ if (phydev->is_c45) ++ return false; ++ ++ switch (phydev->phy_id) { ++ case RTL_GENERIC_PHYID: ++ case RTL_8221B: ++ case RTL_8251B: ++ case 0x001cc841: ++ break; ++ default: ++ return false; ++ } ++ ++ return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev); ++} ++ ++static int rtl8251b_c45_match_phy_device(struct phy_device *phydev) ++{ ++ return rtlgen_is_c45_match(phydev, RTL_8251B, true); ++} ++ ++static int rtlgen_resume(struct phy_device *phydev) ++{ ++ int ret = genphy_resume(phydev); ++ ++ /* Internal PHY's from RTL8168h up may not be instantly ready */ ++ msleep(20); ++ ++ return ret; ++} ++ ++static int rtlgen_c45_resume(struct phy_device *phydev) ++{ ++ int ret = genphy_c45_pma_resume(phydev); ++ ++ msleep(20); ++ ++ return ret; ++} ++ ++static int rtl9000a_config_init(struct phy_device *phydev) ++{ ++ phydev->autoneg = AUTONEG_DISABLE; ++ phydev->speed = SPEED_100; ++ phydev->duplex = DUPLEX_FULL; ++ ++ return 0; ++} ++ ++static int rtl9000a_config_aneg(struct phy_device *phydev) ++{ ++ int ret; ++ u16 ctl = 0; ++ ++ switch (phydev->master_slave_set) { ++ case MASTER_SLAVE_CFG_MASTER_FORCE: ++ ctl |= CTL1000_AS_MASTER; ++ break; ++ case MASTER_SLAVE_CFG_SLAVE_FORCE: ++ break; ++ case MASTER_SLAVE_CFG_UNKNOWN: ++ case MASTER_SLAVE_CFG_UNSUPPORTED: ++ return 0; ++ default: ++ phydev_warn(phydev, "Unsupported Master/Slave mode\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ ret = phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, ctl); ++ if (ret == 1) ++ ret = genphy_soft_reset(phydev); ++ ++ return ret; ++} ++ ++static int rtl9000a_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ ++ phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN; ++ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; ++ ++ ret = genphy_update_link(phydev); ++ if (ret) ++ return ret; ++ ++ ret = phy_read(phydev, MII_CTRL1000); ++ if (ret < 0) ++ return ret; ++ if (ret & CTL1000_AS_MASTER) ++ phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE; ++ else ++ phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE; ++ ++ ret = phy_read(phydev, MII_STAT1000); ++ if (ret < 0) ++ return ret; ++ if (ret & LPA_1000MSRES) ++ phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; ++ else ++ phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; ++ ++ return 0; ++} ++ ++static int rtl9000a_ack_interrupt(struct phy_device *phydev) ++{ ++ int err; ++ ++ err = phy_read(phydev, RTL8211F_INSR); ++ ++ return (err < 0) ? err : 0; ++} ++ ++static int rtl9000a_config_intr(struct phy_device *phydev) ++{ ++ u16 val; ++ int err; ++ ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { ++ err = rtl9000a_ack_interrupt(phydev); ++ if (err) ++ return err; ++ ++ val = (u16)~RTL9000A_GINMR_LINK_STATUS; ++ err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); ++ } else { ++ val = ~0; ++ err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); ++ if (err) ++ return err; ++ ++ err = rtl9000a_ack_interrupt(phydev); ++ } ++ ++ return phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); ++} ++ ++static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev) ++{ ++ int irq_status; ++ ++ irq_status = phy_read(phydev, RTL8211F_INSR); ++ if (irq_status < 0) { ++ phy_error(phydev); ++ return IRQ_NONE; ++ } ++ ++ if (!(irq_status & RTL8211F_INER_LINK_STATUS)) ++ return IRQ_NONE; ++ ++ phy_trigger_machine(phydev); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct phy_driver realtek_drvs[] = { ++ { ++ PHY_ID_MATCH_EXACT(0x00008201), ++ .name = "RTL8201CP Ethernet", ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc816), ++ .name = "RTL8201F Fast Ethernet", ++ .config_intr = &rtl8201_config_intr, ++ .handle_interrupt = rtl8201_handle_interrupt, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_MODEL(0x001cc880), ++ .name = "RTL8208 Fast Ethernet", ++ .read_mmd = genphy_read_mmd_unsupported, ++ .write_mmd = genphy_write_mmd_unsupported, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc910), ++ .name = "RTL8211 Gigabit Ethernet", ++ .config_aneg = rtl8211_config_aneg, ++ .read_mmd = &genphy_read_mmd_unsupported, ++ .write_mmd = &genphy_write_mmd_unsupported, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc912), ++ .name = "RTL8211B Gigabit Ethernet", ++ .config_intr = &rtl8211b_config_intr, ++ .handle_interrupt = rtl821x_handle_interrupt, ++ .read_mmd = &genphy_read_mmd_unsupported, ++ .write_mmd = &genphy_write_mmd_unsupported, ++ .suspend = rtl8211b_suspend, ++ .resume = rtl8211b_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc913), ++ .name = "RTL8211C Gigabit Ethernet", ++ .config_init = rtl8211c_config_init, ++ .read_mmd = &genphy_read_mmd_unsupported, ++ .write_mmd = &genphy_write_mmd_unsupported, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc914), ++ .name = "RTL8211DN Gigabit Ethernet", ++ .config_intr = rtl8211e_config_intr, ++ .handle_interrupt = rtl821x_handle_interrupt, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc915), ++ .name = "RTL8211E Gigabit Ethernet", ++ .config_init = &rtl8211e_config_init, ++ .config_intr = &rtl8211e_config_intr, ++ .handle_interrupt = rtl821x_handle_interrupt, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc916), ++ .name = "RTL8211F Gigabit Ethernet", ++ .probe = rtl821x_probe, ++ .config_init = &rtl8211f_config_init, ++ .read_status = rtlgen_read_status, ++ .config_intr = &rtl8211f_config_intr, ++ .handle_interrupt = rtl8211f_handle_interrupt, ++ .suspend = rtl821x_suspend, ++ .resume = rtl821x_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ .flags = PHY_ALWAYS_CALL_SUSPEND, ++ .led_hw_is_supported = rtl8211f_led_hw_is_supported, ++ .led_hw_control_get = rtl8211f_led_hw_control_get, ++ .led_hw_control_set = rtl8211f_led_hw_control_set, ++ }, { ++ PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID), ++ .name = "RTL8211F-VD Gigabit Ethernet", ++ .probe = rtl821x_probe, ++ .config_init = &rtl8211f_config_init, ++ .read_status = rtlgen_read_status, ++ .config_intr = &rtl8211f_config_intr, ++ .handle_interrupt = rtl8211f_handle_interrupt, ++ .suspend = rtl821x_suspend, ++ .resume = rtl821x_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ .flags = PHY_ALWAYS_CALL_SUSPEND, ++ }, { ++ .name = "Generic FE-GE Realtek PHY", ++ .match_phy_device = rtlgen_match_phy_device, ++ .read_status = rtlgen_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ .read_mmd = rtlgen_read_mmd, ++ .write_mmd = rtlgen_write_mmd, ++ }, { ++ .name = "RTL8226 2.5Gbps PHY", ++ .match_phy_device = rtl8226_match_phy_device, ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .read_status = rtl822x_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ .match_phy_device = rtl8221b_match_phy_device, ++ .name = "RTL8226B_RTL8221B 2.5Gbps PHY", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl822xb_config_init, ++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc838), ++ .name = "RTL8226-CG 2.5Gbps PHY", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .read_status = rtl822x_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc848), ++ .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl822xb_config_init, ++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, ++ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl822xb_config_init, ++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, ++ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", ++ .config_init = rtl822xb_config_init, ++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .get_features = rtl822x_c45_get_features, ++ .config_aneg = rtl822x_c45_config_aneg, ++ .read_status = rtl822xb_c45_read_status, ++ .suspend = genphy_c45_pma_suspend, ++ .resume = rtlgen_c45_resume, ++ }, { ++ .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, ++ .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl822xb_config_init, ++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, ++ .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", ++ .config_init = rtl822xb_config_init, ++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .get_features = rtl822x_c45_get_features, ++ .config_aneg = rtl822x_c45_config_aneg, ++ .read_status = rtl822xb_c45_read_status, ++ .suspend = genphy_c45_pma_suspend, ++ .resume = rtlgen_c45_resume, ++ }, { ++ .match_phy_device = rtl8251b_c45_match_phy_device, ++ .name = "RTL8251B 5Gbps PHY", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .read_status = rtl822x_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ .match_phy_device = rtl_internal_nbaset_match_phy_device, ++ .name = "Realtek Internal NBASE-T PHY", ++ .flags = PHY_IS_INTERNAL, ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .read_status = rtl822x_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ .read_mmd = rtl822x_read_mmd, ++ .write_mmd = rtl822x_write_mmd, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001ccad0), ++ .name = "RTL8224 2.5Gbps PHY", ++ .get_features = rtl822x_c45_get_features, ++ .config_aneg = rtl822x_c45_config_aneg, ++ .read_status = rtl822x_c45_read_status, ++ .suspend = genphy_c45_pma_suspend, ++ .resume = rtlgen_c45_resume, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc961), ++ .name = "RTL8366RB Gigabit Ethernet", ++ .config_init = &rtl8366rb_config_init, ++ /* These interrupts are handled by the irq controller ++ * embedded inside the RTL8366RB, they get unmasked when the ++ * irq is requested and ACKed by reading the status register, ++ * which is done by the irqchip code. ++ */ ++ .config_intr = genphy_no_config_intr, ++ .handle_interrupt = genphy_handle_interrupt_no_ack, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001ccb00), ++ .name = "RTL9000AA_RTL9000AN Ethernet", ++ .features = PHY_BASIC_T1_FEATURES, ++ .config_init = rtl9000a_config_init, ++ .config_aneg = rtl9000a_config_aneg, ++ .read_status = rtl9000a_read_status, ++ .config_intr = rtl9000a_config_intr, ++ .handle_interrupt = rtl9000a_handle_interrupt, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc942), ++ .name = "RTL8365MB-VC Gigabit Ethernet", ++ /* Interrupt handling analogous to RTL8366RB */ ++ .config_intr = genphy_no_config_intr, ++ .handle_interrupt = genphy_handle_interrupt_no_ack, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc960), ++ .name = "RTL8366S Gigabit Ethernet", ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_mmd = genphy_read_mmd_unsupported, ++ .write_mmd = genphy_write_mmd_unsupported, ++ }, ++}; ++ ++module_phy_driver(realtek_drvs); ++ ++static const struct mdio_device_id __maybe_unused realtek_tbl[] = { ++ { PHY_ID_MATCH_VENDOR(0x001cc800) }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(mdio, realtek_tbl); diff --git a/6.12/target/linux/generic/backport-6.12/781-25-v6.14-net-phy-realtek-add-hwmon-support-for-temp-sensor-on.patch b/6.12/target/linux/generic/backport-6.12/781-25-v6.14-net-phy-realtek-add-hwmon-support-for-temp-sensor-on.patch new file mode 100644 index 00000000..7c1fe542 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/781-25-v6.14-net-phy-realtek-add-hwmon-support-for-temp-sensor-on.patch @@ -0,0 +1,180 @@ +From 33700ca45b7d2e1655d4cad95e25671e8a94e2f0 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 11 Jan 2025 21:51:24 +0100 +Subject: [PATCH] net: phy: realtek: add hwmon support for temp sensor on + RTL822x + +This adds hwmon support for the temperature sensor on RTL822x. +It's available on the standalone versions of the PHY's, and on +the integrated PHY's in RTL8125B/RTL8125D/RTL8126. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/ad6bfe9f-6375-4a00-84b4-bfb38a21bd71@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/Kconfig | 6 ++ + drivers/net/phy/realtek/Makefile | 1 + + drivers/net/phy/realtek/realtek.h | 10 ++++ + drivers/net/phy/realtek/realtek_hwmon.c | 79 +++++++++++++++++++++++++ + drivers/net/phy/realtek/realtek_main.c | 12 ++++ + 5 files changed, 108 insertions(+) + create mode 100644 drivers/net/phy/realtek/realtek.h + create mode 100644 drivers/net/phy/realtek/realtek_hwmon.c + +--- a/drivers/net/phy/realtek/Kconfig ++++ b/drivers/net/phy/realtek/Kconfig +@@ -3,3 +3,9 @@ config REALTEK_PHY + tristate "Realtek PHYs" + help + Currently supports RTL821x/RTL822x and fast ethernet PHYs ++ ++config REALTEK_PHY_HWMON ++ def_bool REALTEK_PHY && HWMON ++ depends on !(REALTEK_PHY=y && HWMON=m) ++ help ++ Optional hwmon support for the temperature sensor +--- a/drivers/net/phy/realtek/Makefile ++++ b/drivers/net/phy/realtek/Makefile +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 + realtek-y += realtek_main.o ++realtek-$(CONFIG_REALTEK_PHY_HWMON) += realtek_hwmon.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o +--- /dev/null ++++ b/drivers/net/phy/realtek/realtek.h +@@ -0,0 +1,10 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++#ifndef REALTEK_H ++#define REALTEK_H ++ ++#include ++ ++int rtl822x_hwmon_init(struct phy_device *phydev); ++ ++#endif /* REALTEK_H */ +--- /dev/null ++++ b/drivers/net/phy/realtek/realtek_hwmon.c +@@ -0,0 +1,86 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * HWMON support for Realtek PHY's ++ * ++ * Author: Heiner Kallweit ++ */ ++ ++#include ++#include ++ ++#include "realtek.h" ++ ++#define RTL822X_VND2_TSALRM 0xa662 ++#define RTL822X_VND2_TSRR 0xbd84 ++#define RTL822X_VND2_TSSR 0xb54c ++ ++static umode_t rtl822x_hwmon_is_visible(const void *drvdata, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ return 0444; ++} ++ ++static int rtl822x_hwmon_get_temp(int raw) ++{ ++ if (raw >= 512) ++ raw -= 1024; ++ ++ return 1000 * raw / 2; ++} ++ ++static int rtl822x_hwmon_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ struct phy_device *phydev = dev_get_drvdata(dev); ++ int raw; ++ ++ switch (attr) { ++ case hwmon_temp_input: ++ raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSRR) & 0x3ff; ++ *val = rtl822x_hwmon_get_temp(raw); ++ break; ++ case hwmon_temp_max: ++ /* Chip reduces speed to 1G if threshold is exceeded */ ++ raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSSR) >> 6; ++ *val = rtl822x_hwmon_get_temp(raw); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static const struct hwmon_ops rtl822x_hwmon_ops = { ++ .is_visible = rtl822x_hwmon_is_visible, ++ .read = rtl822x_hwmon_read, ++}; ++ ++static const struct hwmon_channel_info * const rtl822x_hwmon_info[] = { ++ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX), ++ NULL ++}; ++ ++static const struct hwmon_chip_info rtl822x_hwmon_chip_info = { ++ .ops = &rtl822x_hwmon_ops, ++ .info = rtl822x_hwmon_info, ++}; ++ ++int rtl822x_hwmon_init(struct phy_device *phydev) ++{ ++ struct device *hwdev, *dev = &phydev->mdio.dev; ++ const char *name; ++ ++ /* Ensure over-temp alarm is reset. */ ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSALRM, 3); ++ ++ name = devm_hwmon_sanitize_name(dev, dev_name(dev)); ++ if (IS_ERR(name)) ++ return PTR_ERR(name); ++ ++ hwdev = devm_hwmon_device_register_with_info(dev, name, phydev, ++ &rtl822x_hwmon_chip_info, ++ NULL); ++ return PTR_ERR_OR_ZERO(hwdev); ++} +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -14,6 +14,8 @@ + #include + #include + ++#include "realtek.h" ++ + #define RTL821x_PHYSR 0x11 + #define RTL821x_PHYSR_DUPLEX BIT(13) + #define RTL821x_PHYSR_SPEED GENMASK(15, 14) +@@ -820,6 +822,15 @@ static int rtl822x_write_mmd(struct phy_ + return ret; + } + ++static int rtl822x_probe(struct phy_device *phydev) ++{ ++ if (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON) && ++ phydev->phy_id != RTL_GENERIC_PHYID) ++ return rtl822x_hwmon_init(phydev); ++ ++ return 0; ++} ++ + static int rtl822xb_config_init(struct phy_device *phydev) + { + bool has_2500, has_sgmii; +@@ -1518,6 +1529,7 @@ static struct phy_driver realtek_drvs[] + .match_phy_device = rtl_internal_nbaset_match_phy_device, + .name = "Realtek Internal NBASE-T PHY", + .flags = PHY_IS_INTERNAL, ++ .probe = rtl822x_probe, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .read_status = rtl822x_read_status, diff --git a/6.12/target/linux/generic/backport-6.12/781-26-v6.14-net-phy-realtek-HWMON-support-for-standalone-version.patch b/6.12/target/linux/generic/backport-6.12/781-26-v6.14-net-phy-realtek-HWMON-support-for-standalone-version.patch new file mode 100644 index 00000000..8b8c97c5 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/781-26-v6.14-net-phy-realtek-HWMON-support-for-standalone-version.patch @@ -0,0 +1,64 @@ +From 64ff63aeefb03139ae27454bd4208244579ae88e Mon Sep 17 00:00:00 2001 +From: Aleksander Jan Bajkowski +Date: Fri, 17 Jan 2025 23:24:21 +0100 +Subject: [PATCH] net: phy: realtek: HWMON support for standalone versions of + RTL8221B and RTL8251 + +HWMON support has been added for the RTL8221/8251 PHYs integrated together +with the MAC inside the RTL8125/8126 chips. This patch extends temperature +reading support for standalone variants of the mentioned PHYs. + +I don't know whether the earlier revisions of the RTL8226 also have a +built-in temperature sensor, so they have been skipped for now. + +Tested on RTL8221B-VB-CG. + +Signed-off-by: Aleksander Jan Bajkowski +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek/realtek_main.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1474,6 +1474,7 @@ static struct phy_driver realtek_drvs[] + }, { + .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, + .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", ++ .probe = rtl822x_probe, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .config_init = rtl822xb_config_init, +@@ -1486,6 +1487,7 @@ static struct phy_driver realtek_drvs[] + }, { + .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, + .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", ++ .probe = rtl822x_probe, + .config_init = rtl822xb_config_init, + .get_rate_matching = rtl822xb_get_rate_matching, + .get_features = rtl822x_c45_get_features, +@@ -1496,6 +1498,7 @@ static struct phy_driver realtek_drvs[] + }, { + .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, + .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", ++ .probe = rtl822x_probe, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .config_init = rtl822xb_config_init, +@@ -1508,6 +1511,7 @@ static struct phy_driver realtek_drvs[] + }, { + .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, + .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", ++ .probe = rtl822x_probe, + .config_init = rtl822xb_config_init, + .get_rate_matching = rtl822xb_get_rate_matching, + .get_features = rtl822x_c45_get_features, +@@ -1518,6 +1522,7 @@ static struct phy_driver realtek_drvs[] + }, { + .match_phy_device = rtl8251b_c45_match_phy_device, + .name = "RTL8251B 5Gbps PHY", ++ .probe = rtl822x_probe, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .read_status = rtl822x_read_status, diff --git a/6.12/target/linux/generic/backport-6.12/880-v6.14-gpio-regmap-Use-generic-request-free-ops.patch b/6.12/target/linux/generic/backport-6.12/880-v6.14-gpio-regmap-Use-generic-request-free-ops.patch new file mode 100644 index 00000000..f9299f97 --- /dev/null +++ b/6.12/target/linux/generic/backport-6.12/880-v6.14-gpio-regmap-Use-generic-request-free-ops.patch @@ -0,0 +1,30 @@ +From b0fa00fe38f673c986633c11087274deeb7ce7b0 Mon Sep 17 00:00:00 2001 +From: Sander Vanheule +Date: Tue, 7 Jan 2025 21:16:20 +0100 +Subject: [PATCH] gpio: regmap: Use generic request/free ops + +Set the gpiochip request and free ops to the generic implementations. +This way a user can provide a gpio-ranges property defined for a pinmux, +easing muxing of gpio functions. Provided that the pin controller +implementents the pinmux op .gpio_request_enable(), pins will +automatically be muxed to their GPIO function when requested. + +Signed-off-by: Sander Vanheule +Acked-by: Michael Walle +Link: https://lore.kernel.org/r/20250107201621.12467-1-sander@svanheule.net +Signed-off-by: Bartosz Golaszewski +--- + drivers/gpio/gpio-regmap.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/gpio/gpio-regmap.c ++++ b/drivers/gpio/gpio-regmap.c +@@ -262,6 +262,8 @@ struct gpio_regmap *gpio_regmap_register + chip->label = config->label ?: dev_name(config->parent); + chip->can_sleep = regmap_might_sleep(config->regmap); + ++ chip->request = gpiochip_generic_request; ++ chip->free = gpiochip_generic_free; + chip->get = gpio_regmap_get; + if (gpio->reg_set_base && gpio->reg_clr_base) + chip->set = gpio_regmap_set_with_clear; diff --git a/6.12/target/linux/generic/config-6.12 b/6.12/target/linux/generic/config-6.12 index 33ea0501..2b13e335 100644 --- a/6.12/target/linux/generic/config-6.12 +++ b/6.12/target/linux/generic/config-6.12 @@ -8519,3 +8519,4 @@ CONFIG_PROC_MEM_ALWAYS_FORCE=y # CONFIG_INSPUR_PLATFORM_PROFILE is not set # CONFIG_LENOVO_WMI_CAMERA is not set # CONFIG_IMX_SCMI_MISC_DRV is not set +# CONFIG_NVMEM_LAYOUT_ASCII_ENV is not set diff --git a/6.12/target/linux/generic/pending-6.12/100-compiler.h-only-include-asm-rwonce.h-for-kernel-code.patch b/6.12/target/linux/generic/pending-6.12/100-compiler.h-only-include-asm-rwonce.h-for-kernel-code.patch index 0547d1e4..e28c106d 100644 --- a/6.12/target/linux/generic/pending-6.12/100-compiler.h-only-include-asm-rwonce.h-for-kernel-code.patch +++ b/6.12/target/linux/generic/pending-6.12/100-compiler.h-only-include-asm-rwonce.h-for-kernel-code.patch @@ -19,8 +19,8 @@ Signed-off-by: Felix Fietkau + #endif /* __KERNEL__ */ - /* -@@ -314,6 +316,4 @@ static inline void *offset_to_ptr(const + /** +@@ -329,6 +331,4 @@ static inline void *offset_to_ptr(const */ #define prevent_tail_call_optimization() mb() diff --git a/6.12/target/linux/generic/pending-6.12/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch b/6.12/target/linux/generic/pending-6.12/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch deleted file mode 100644 index 9c903598..00000000 --- a/6.12/target/linux/generic/pending-6.12/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch +++ /dev/null @@ -1,82 +0,0 @@ -From: Tobias Wolf -Subject: mm: Fix alloc_node_mem_map with ARCH_PFN_OFFSET calculation - -An rt288x (ralink) based router (Belkin F5D8235 v1) does not boot with any -kernel beyond version 4.3 resulting in: - -BUG: Bad page state in process swapper pfn:086ac - -bisect resulted in: - -a1c34a3bf00af2cede839879502e12dc68491ad5 is the first bad commit -commit a1c34a3bf00af2cede839879502e12dc68491ad5 -Author: Laura Abbott -Date: Thu Nov 5 18:48:46 2015 -0800 - - mm: Don't offset memmap for flatmem - - Srinivas Kandagatla reported bad page messages when trying to remove the - bottom 2MB on an ARM based IFC6410 board - - BUG: Bad page state in process swapper pfn:fffa8 - page:ef7fb500 count:0 mapcount:0 mapping: (null) index:0x0 - flags: 0x96640253(locked|error|dirty|active|arch_1|reclaim|mlocked) - page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set - bad because of flags: - flags: 0x200041(locked|active|mlocked) - Modules linked in: - CPU: 0 PID: 0 Comm: swapper Not tainted 3.19.0-rc3-00007-g412f9ba-dirty -#816 - Hardware name: Qualcomm (Flattened Device Tree) - unwind_backtrace - show_stack - dump_stack - bad_page - free_pages_prepare - free_hot_cold_page - __free_pages - free_highmem_page - mem_init - start_kernel - Disabling lock debugging due to kernel taint - [...] -:040000 040000 2de013c372345fd471cd58f0553c9b38b0ef1cc4 -0a8156f848733dfa21e16c196dfb6c0a76290709 M mm - -This fix for ARM does not account ARCH_PFN_OFFSET for mem_map as later used by -page_to_pfn anymore. - -The following output was generated with two hacked in printk statements: - -printk("before %p vs. %p or %p\n", mem_map, mem_map - offset, mem_map - -(pgdat->node_start_pfn - ARCH_PFN_OFFSET)); - if (page_to_pfn(mem_map) != pgdat->node_start_pfn) - mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET); -printk("after %p\n", mem_map); - -Output: - -[ 0.000000] before 8861b280 vs. 8861b280 or 8851b280 -[ 0.000000] after 8851b280 - -As seen in the first line mem_map with subtraction of offset does not equal the -mem_map after subtraction of ARCH_PFN_OFFSET. - -After adding the offset of ARCH_PFN_OFFSET as well to mem_map as the -previously calculated offset is zero for the named platform it is able to boot -4.4 and 4.9-rc7 again. - -Signed-off-by: Tobias Wolf ---- - ---- a/mm/mm_init.c -+++ b/mm/mm_init.c -@@ -1632,7 +1632,7 @@ static void __init alloc_node_mem_map(st - if (pgdat == NODE_DATA(0)) { - mem_map = NODE_DATA(0)->node_mem_map; - if (page_to_pfn(mem_map) != pgdat->node_start_pfn) -- mem_map -= offset; -+ mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET); - } - #endif - } diff --git a/6.12/target/linux/generic/pending-6.12/203-kallsyms_uncompressed.patch b/6.12/target/linux/generic/pending-6.12/203-kallsyms_uncompressed.patch new file mode 100644 index 00000000..fcb18817 --- /dev/null +++ b/6.12/target/linux/generic/pending-6.12/203-kallsyms_uncompressed.patch @@ -0,0 +1,165 @@ +From: Felix Fietkau +Subject: kernel: add a config option for keeping the kallsyms table uncompressed, saving ~9kb kernel size after lzma on ar71xx + +[john@phrozen.org: added to my upstream queue 30.12.2016] +lede-commit: e0e3509b5ce2ccf93d4d67ea907613f5f7ec2eed +Signed-off-by: Felix Fietkau +--- + init/Kconfig | 11 +++++++++++ + kernel/kallsyms.c | 8 ++++++++ + scripts/kallsyms.c | 12 ++++++++++++ + scripts/link-vmlinux.sh | 4 ++++ + 4 files changed, 35 insertions(+) + +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1525,6 +1525,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW + the unaligned access emulation. + see arch/parisc/kernel/unaligned.c for reference + ++config KALLSYMS_UNCOMPRESSED ++ bool "Keep kallsyms uncompressed" ++ depends on KALLSYMS ++ help ++ Normally kallsyms contains compressed symbols (using a token table), ++ reducing the uncompressed kernel image size. Keeping the symbol table ++ uncompressed significantly improves the size of this part in compressed ++ kernel images. ++ ++ Say N unless you need compressed kernel images to be small. ++ + config HAVE_PCSPKR_PLATFORM + bool + +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -69,6 +69,11 @@ static unsigned int kallsyms_expand_symb + * For every byte on the compressed symbol data, copy the table + * entry for that byte. + */ ++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED ++ memcpy(result, data + 1, len - 1); ++ result += len - 1; ++ len = 0; ++#endif + while (len) { + tptr = &kallsyms_token_table[kallsyms_token_index[*data]]; + data++; +@@ -101,6 +106,9 @@ tail: + */ + static char kallsyms_get_symbol_type(unsigned int off) + { ++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED ++ return kallsyms_names[off + 1]; ++#endif + /* + * Get just the first code, look it up in the token table, + * and return the first char from this token. +--- a/scripts/kallsyms.c ++++ b/scripts/kallsyms.c +@@ -62,6 +62,7 @@ static struct addr_range percpu_range = + static struct sym_entry **table; + static unsigned int table_size, table_cnt; + static int all_symbols; ++static int uncompressed; + static int absolute_percpu; + + static int token_profit[0x10000]; +@@ -412,12 +413,14 @@ static void write_src(void) + for (k = 0; k < table[i]->len; k++) + printf(", 0x%02x", table[i]->sym[k]); + +- /* +- * Now that we wrote out the compressed symbol name, restore the +- * original name and print it in the comment. +- */ +- expand_symbol(table[i]->sym, table[i]->len, buf); +- strcpy((char *)table[i]->sym, buf); ++ if (!uncompressed) { ++ /* ++ * Now that we wrote out the compressed symbol name, restore the ++ * original name and print it in the comment. ++ */ ++ expand_symbol(table[i]->sym, table[i]->len, buf); ++ strcpy((char *)table[i]->sym, buf); ++ } + printf("\t/* %s */\n", table[i]->sym); + } + printf("\n"); +@@ -429,20 +432,22 @@ static void write_src(void) + + free(markers); + +- output_label("kallsyms_token_table"); +- off = 0; +- for (i = 0; i < 256; i++) { +- best_idx[i] = off; +- expand_symbol(best_table[i], best_table_len[i], buf); +- printf("\t.asciz\t\"%s\"\n", buf); +- off += strlen(buf) + 1; ++ if (!uncompressed) { ++ output_label("kallsyms_token_table"); ++ off = 0; ++ for (i = 0; i < 256; i++) { ++ best_idx[i] = off; ++ expand_symbol(best_table[i], best_table_len[i], buf); ++ printf("\t.asciz\t\"%s\"\n", buf); ++ off += strlen(buf) + 1; ++ } ++ printf("\n"); ++ ++ output_label("kallsyms_token_index"); ++ for (i = 0; i < 256; i++) ++ printf("\t.short\t%d\n", best_idx[i]); ++ printf("\n"); + } +- printf("\n"); +- +- output_label("kallsyms_token_index"); +- for (i = 0; i < 256; i++) +- printf("\t.short\t%d\n", best_idx[i]); +- printf("\n"); + + output_label("kallsyms_offsets"); + +@@ -532,6 +537,9 @@ static unsigned char *find_token(unsigne + { + int i; + ++ if (uncompressed) ++ return NULL; ++ + for (i = 0; i < len - 1; i++) { + if (str[i] == token[0] && str[i+1] == token[1]) + return &str[i]; +@@ -604,6 +612,9 @@ static void optimize_result(void) + { + int i, best; + ++ if (uncompressed) ++ return; ++ + /* using the '\0' symbol last allows compress_symbols to use standard + * fast string functions */ + for (i = 255; i >= 0; i--) { +@@ -763,6 +774,7 @@ int main(int argc, char **argv) + static const struct option long_options[] = { + {"all-symbols", no_argument, &all_symbols, 1}, + {"absolute-percpu", no_argument, &absolute_percpu, 1}, ++ {"uncompressed", no_argument, &uncompressed, 1}, + {}, + }; + +--- a/scripts/link-vmlinux.sh ++++ b/scripts/link-vmlinux.sh +@@ -144,6 +144,10 @@ kallsyms() + kallsymopt="${kallsymopt} --absolute-percpu" + fi + ++ if is_enabled CONFIG_KALLSYMS_UNCOMPRESSED; then ++ kallsymopt="${kallsymopt} --uncompressed" ++ fi ++ + info KSYMS "${2}.S" + scripts/kallsyms ${kallsymopt} "${1}" > "${2}.S" + diff --git a/6.12/target/linux/generic/pending-6.12/452-block-add-support-for-notifications.patch b/6.12/target/linux/generic/pending-6.12/452-block-add-support-for-notifications.patch index 3100e159..9bf2367c 100644 --- a/6.12/target/linux/generic/pending-6.12/452-block-add-support-for-notifications.patch +++ b/6.12/target/linux/generic/pending-6.12/452-block-add-support-for-notifications.patch @@ -156,7 +156,7 @@ Signed-off-by: Daniel Golle +device_initcall(blk_notifications_init); --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h -@@ -1689,4 +1689,15 @@ static inline bool bdev_can_atomic_write +@@ -1690,4 +1690,15 @@ static inline bool bdev_can_atomic_write #define DEFINE_IO_COMP_BATCH(name) struct io_comp_batch name = { } diff --git a/6.12/target/linux/generic/pending-6.12/630-packet_socket_type.patch b/6.12/target/linux/generic/pending-6.12/630-packet_socket_type.patch index 9360eaaa..fff421bd 100644 --- a/6.12/target/linux/generic/pending-6.12/630-packet_socket_type.patch +++ b/6.12/target/linux/generic/pending-6.12/630-packet_socket_type.patch @@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau #define PACKET_FANOUT_LB 1 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c -@@ -1925,6 +1925,7 @@ static int packet_rcv_spkt(struct sk_buf +@@ -1911,6 +1911,7 @@ static int packet_rcv_spkt(struct sk_buf { struct sock *sk; struct sockaddr_pkt *spkt; @@ -38,7 +38,7 @@ Signed-off-by: Felix Fietkau /* * When we registered the protocol we saved the socket in the data -@@ -1932,6 +1933,7 @@ static int packet_rcv_spkt(struct sk_buf +@@ -1918,6 +1919,7 @@ static int packet_rcv_spkt(struct sk_buf */ sk = pt->af_packet_priv; @@ -46,7 +46,7 @@ Signed-off-by: Felix Fietkau /* * Yank back the headers [hope the device set this -@@ -1944,7 +1946,7 @@ static int packet_rcv_spkt(struct sk_buf +@@ -1930,7 +1932,7 @@ static int packet_rcv_spkt(struct sk_buf * so that this procedure is noop. */ @@ -55,7 +55,7 @@ Signed-off-by: Felix Fietkau goto out; if (!net_eq(dev_net(dev), sock_net(sk))) -@@ -2189,12 +2191,12 @@ static int packet_rcv(struct sk_buff *sk +@@ -2175,12 +2177,12 @@ static int packet_rcv(struct sk_buff *sk int skb_len = skb->len; unsigned int snaplen, res; @@ -71,7 +71,7 @@ Signed-off-by: Felix Fietkau if (!net_eq(dev_net(dev), sock_net(sk))) goto drop; -@@ -2318,12 +2320,12 @@ static int tpacket_rcv(struct sk_buff *s +@@ -2304,12 +2306,12 @@ static int tpacket_rcv(struct sk_buff *s BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32); BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48); @@ -87,7 +87,7 @@ Signed-off-by: Felix Fietkau if (!net_eq(dev_net(dev), sock_net(sk))) goto drop; -@@ -3444,6 +3446,7 @@ static int packet_create(struct net *net +@@ -3430,6 +3432,7 @@ static int packet_create(struct net *net mutex_init(&po->pg_vec_lock); po->rollover = NULL; po->prot_hook.func = packet_rcv; @@ -95,7 +95,7 @@ Signed-off-by: Felix Fietkau if (sock->type == SOCK_PACKET) po->prot_hook.func = packet_rcv_spkt; -@@ -4111,6 +4114,16 @@ packet_setsockopt(struct socket *sock, i +@@ -4097,6 +4100,16 @@ packet_setsockopt(struct socket *sock, i packet_sock_flag_set(po, PACKET_SOCK_QDISC_BYPASS, val); return 0; } @@ -112,7 +112,7 @@ Signed-off-by: Felix Fietkau default: return -ENOPROTOOPT; } -@@ -4173,6 +4186,13 @@ static int packet_getsockopt(struct sock +@@ -4159,6 +4172,13 @@ static int packet_getsockopt(struct sock case PACKET_COPY_THRESH: val = READ_ONCE(pkt_sk(sk)->copy_thresh); break; diff --git a/6.12/target/linux/generic/pending-6.12/681-net-remove-NETIF_F_GSO_FRAGLIST-from-NETIF_F_GSO_SOF.patch b/6.12/target/linux/generic/pending-6.12/681-net-remove-NETIF_F_GSO_FRAGLIST-from-NETIF_F_GSO_SOF.patch index 2e6d46d3..ad30c5af 100644 --- a/6.12/target/linux/generic/pending-6.12/681-net-remove-NETIF_F_GSO_FRAGLIST-from-NETIF_F_GSO_SOF.patch +++ b/6.12/target/linux/generic/pending-6.12/681-net-remove-NETIF_F_GSO_FRAGLIST-from-NETIF_F_GSO_SOF.patch @@ -96,7 +96,7 @@ Signed-off-by: Felix Fietkau } --- a/net/core/sock.c +++ b/net/core/sock.c -@@ -2525,7 +2525,7 @@ void sk_setup_caps(struct sock *sk, stru +@@ -2528,7 +2528,7 @@ void sk_setup_caps(struct sock *sk, stru if (sk_is_tcp(sk)) sk->sk_route_caps |= NETIF_F_GSO; if (sk->sk_route_caps & NETIF_F_GSO) @@ -107,7 +107,7 @@ Signed-off-by: Felix Fietkau if (sk_can_gso(sk)) { --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h -@@ -2012,7 +2012,7 @@ void ieee80211_color_collision_detection +@@ -2010,7 +2010,7 @@ void ieee80211_color_collision_detection /* interface handling */ #define MAC80211_SUPPORTED_FEATURES_TX (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \ NETIF_F_HW_CSUM | NETIF_F_SG | \ diff --git a/6.12/target/linux/generic/pending-6.12/701-netfilter-nf_tables-ignore-EOPNOTSUPP-on-flowtable-d.patch b/6.12/target/linux/generic/pending-6.12/701-netfilter-nf_tables-ignore-EOPNOTSUPP-on-flowtable-d.patch index 1ccf9cef..a6d07f54 100644 --- a/6.12/target/linux/generic/pending-6.12/701-netfilter-nf_tables-ignore-EOPNOTSUPP-on-flowtable-d.patch +++ b/6.12/target/linux/generic/pending-6.12/701-netfilter-nf_tables-ignore-EOPNOTSUPP-on-flowtable-d.patch @@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c -@@ -8607,7 +8607,7 @@ static int nft_register_flowtable_net_ho +@@ -8615,7 +8615,7 @@ static int nft_register_flowtable_net_ho err = flowtable->data.type->setup(&flowtable->data, hook->ops.dev, FLOW_BLOCK_BIND); diff --git a/6.12/target/linux/generic/pending-6.12/720-01-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch b/6.12/target/linux/generic/pending-6.12/720-01-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch index 2b77b6e0..24885e36 100644 --- a/6.12/target/linux/generic/pending-6.12/720-01-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch +++ b/6.12/target/linux/generic/pending-6.12/720-01-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch @@ -10,12 +10,12 @@ the PHY. Reported-by: Yevhen Kolomeiko Signed-off-by: Daniel Golle --- - drivers/net/phy/realtek.c | 6 ++++++ + drivers/net/phy/realtek/realtek_main.c | 6 ++++++ 1 file changed, 6 insertions(+) ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -1375,6 +1375,7 @@ static struct phy_driver realtek_drvs[] +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1430,6 +1430,7 @@ static struct phy_driver realtek_drvs[] }, { .name = "RTL8226 2.5Gbps PHY", .match_phy_device = rtl8226_match_phy_device, @@ -23,15 +23,15 @@ Signed-off-by: Daniel Golle .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .read_status = rtl822x_read_status, -@@ -1387,6 +1388,7 @@ static struct phy_driver realtek_drvs[] +@@ -1440,6 +1441,7 @@ static struct phy_driver realtek_drvs[] }, { - PHY_ID_MATCH_EXACT(0x001cc840), + .match_phy_device = rtl8221b_match_phy_device, .name = "RTL8226B_RTL8221B 2.5Gbps PHY", + .soft_reset = genphy_soft_reset, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .config_init = rtl822xb_config_init, -@@ -1401,6 +1403,7 @@ static struct phy_driver realtek_drvs[] +@@ -1452,6 +1454,7 @@ static struct phy_driver realtek_drvs[] }, { PHY_ID_MATCH_EXACT(0x001cc838), .name = "RTL8226-CG 2.5Gbps PHY", @@ -39,7 +39,7 @@ Signed-off-by: Daniel Golle .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .read_status = rtl822x_read_status, -@@ -1411,6 +1414,7 @@ static struct phy_driver realtek_drvs[] +@@ -1462,6 +1465,7 @@ static struct phy_driver realtek_drvs[] }, { PHY_ID_MATCH_EXACT(0x001cc848), .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", @@ -47,35 +47,35 @@ Signed-off-by: Daniel Golle .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .config_init = rtl822xb_config_init, -@@ -1423,6 +1427,7 @@ static struct phy_driver realtek_drvs[] +@@ -1474,6 +1478,7 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", + .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, - .config_init = rtl822xb_config_init, -@@ -1435,6 +1440,7 @@ static struct phy_driver realtek_drvs[] +@@ -1487,6 +1492,7 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", + .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, .config_init = rtl822xb_config_init, .get_rate_matching = rtl822xb_get_rate_matching, - .get_features = rtl822x_c45_get_features, -@@ -1445,6 +1451,7 @@ static struct phy_driver realtek_drvs[] +@@ -1498,6 +1504,7 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", + .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, - .config_init = rtl822xb_config_init, -@@ -1457,6 +1464,7 @@ static struct phy_driver realtek_drvs[] +@@ -1511,6 +1518,7 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", + .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, .config_init = rtl822xb_config_init, .get_rate_matching = rtl822xb_get_rate_matching, - .get_features = rtl822x_c45_get_features, diff --git a/6.12/target/linux/generic/pending-6.12/720-02-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch b/6.12/target/linux/generic/pending-6.12/720-02-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch index cbef74d3..edc03b55 100644 --- a/6.12/target/linux/generic/pending-6.12/720-02-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch +++ b/6.12/target/linux/generic/pending-6.12/720-02-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch @@ -15,12 +15,12 @@ Reported-by: Yevhen Kolomeiko Tested-by: Yevhen Kolomeiko Signed-off-by: Daniel Golle --- - drivers/net/phy/realtek.c | 27 +++++++++++++++++++++++++-- + drivers/net/phy/realtek/realtek_main.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -814,8 +814,8 @@ static int rtl822x_write_mmd(struct phy_ +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -834,8 +834,8 @@ static int rtl822x_probe(struct phy_devi static int rtl822xb_config_init(struct phy_device *phydev) { bool has_2500, has_sgmii; @@ -30,7 +30,7 @@ Signed-off-by: Daniel Golle has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->host_interfaces) || -@@ -865,7 +865,29 @@ static int rtl822xb_config_init(struct p +@@ -885,7 +885,29 @@ static int rtl822xb_config_init(struct p if (ret < 0) return ret; diff --git a/6.12/target/linux/generic/pending-6.12/720-03-net-phy-realtek-make-sure-paged-read-is-protected-by.patch b/6.12/target/linux/generic/pending-6.12/720-03-net-phy-realtek-make-sure-paged-read-is-protected-by.patch index 216fa918..d5f80d1c 100644 --- a/6.12/target/linux/generic/pending-6.12/720-03-net-phy-realtek-make-sure-paged-read-is-protected-by.patch +++ b/6.12/target/linux/generic/pending-6.12/720-03-net-phy-realtek-make-sure-paged-read-is-protected-by.patch @@ -13,12 +13,12 @@ rtl821x_write_page instead of 3 individually locked MDIO bus operations. Signed-off-by: Daniel Golle --- - drivers/net/phy/realtek.c | 8 +++++--- + drivers/net/phy/realtek/realtek_main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -1092,9 +1092,11 @@ static bool rtlgen_supports_2_5gbps(stru +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1111,9 +1111,11 @@ static bool rtlgen_supports_2_5gbps(stru { int val; diff --git a/6.12/target/linux/generic/pending-6.12/720-04-net-phy-realtek-introduce-rtl822x_probe.patch b/6.12/target/linux/generic/pending-6.12/720-04-net-phy-realtek-introduce-rtl822x_probe.patch deleted file mode 100644 index 08c13f34..00000000 --- a/6.12/target/linux/generic/pending-6.12/720-04-net-phy-realtek-introduce-rtl822x_probe.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 9155098547fb1172d4fa536f3f6bc9d42f59d08c Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Sat, 22 Apr 2023 03:26:01 +0100 -Subject: [PATCH] net: phy: realtek: setup ALDPS on RTL822x - -Setup Link Down Power Saving Mode according the DTS property -just like for RTL821x 1GE PHYs. - -Signed-off-by: Daniel Golle ---- - drivers/net/phy/realtek.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -80,6 +80,10 @@ - - #define RTL822X_VND2_GANLPAR 0xa414 - -+#define RTL8221B_PHYCR1 0xa430 -+#define RTL8221B_PHYCR1_ALDPS_EN BIT(2) -+#define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN BIT(12) -+ - #define RTL8366RB_POWER_SAVE 0x15 - #define RTL8366RB_POWER_SAVE_ON BIT(12) - -@@ -1152,6 +1156,25 @@ static int rtl8251b_c45_match_phy_device - return rtlgen_is_c45_match(phydev, RTL_8251B, true); - } - -+static int rtl822x_probe(struct phy_device *phydev) -+{ -+ struct device *dev = &phydev->mdio.dev; -+ int val; -+ -+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1); -+ if (val < 0) -+ return val; -+ -+ if (of_property_read_bool(dev->of_node, "realtek,aldps-enable")) -+ val |= RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN; -+ else -+ val &= ~(RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN); -+ -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1, val); -+ -+ return 0; -+} -+ - static int rtlgen_resume(struct phy_device *phydev) - { - int ret = genphy_resume(phydev); -@@ -1427,6 +1450,7 @@ static struct phy_driver realtek_drvs[] - }, { - PHY_ID_MATCH_EXACT(0x001cc838), - .name = "RTL8226-CG 2.5Gbps PHY", -+ .probe = rtl822x_probe, - .soft_reset = genphy_soft_reset, - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, -@@ -1438,6 +1462,7 @@ static struct phy_driver realtek_drvs[] - }, { - PHY_ID_MATCH_EXACT(0x001cc848), - .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", -+ .probe = rtl822x_probe, - .soft_reset = genphy_soft_reset, - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, -@@ -1451,6 +1476,7 @@ static struct phy_driver realtek_drvs[] - }, { - .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, - .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", -+ .probe = rtl822x_probe, - .soft_reset = genphy_soft_reset, - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, -@@ -1464,6 +1490,7 @@ static struct phy_driver realtek_drvs[] - }, { - .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, - .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", -+ .probe = rtl822x_probe, - .soft_reset = genphy_soft_reset, - .config_init = rtl822xb_config_init, - .get_rate_matching = rtl822xb_get_rate_matching, -@@ -1475,6 +1502,7 @@ static struct phy_driver realtek_drvs[] - }, { - .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, - .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", -+ .probe = rtl822x_probe, - .soft_reset = genphy_soft_reset, - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, -@@ -1488,6 +1516,7 @@ static struct phy_driver realtek_drvs[] - }, { - .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, - .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", -+ .probe = rtl822x_probe, - .soft_reset = genphy_soft_reset, - .config_init = rtl822xb_config_init, - .get_rate_matching = rtl822xb_get_rate_matching, diff --git a/6.12/target/linux/generic/pending-6.12/720-04-net-phy-realtek-setup-aldps.patch b/6.12/target/linux/generic/pending-6.12/720-04-net-phy-realtek-setup-aldps.patch new file mode 100644 index 00000000..23b3ca89 --- /dev/null +++ b/6.12/target/linux/generic/pending-6.12/720-04-net-phy-realtek-setup-aldps.patch @@ -0,0 +1,42 @@ +From 9155098547fb1172d4fa536f3f6bc9d42f59d08c Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 22 Apr 2023 03:26:01 +0100 +Subject: [PATCH] net: phy: realtek: setup ALDPS on RTL822x + +Setup Link Down Power Saving Mode according the DTS property +just like for RTL821x 1GE PHYs. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek/realtek_main.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -82,6 +82,10 @@ + + #define RTL822X_VND2_GANLPAR 0xa414 + ++#define RTL8221B_PHYCR1 0xa430 ++#define RTL8221B_PHYCR1_ALDPS_EN BIT(2) ++#define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN BIT(12) ++ + #define RTL8366RB_POWER_SAVE 0x15 + #define RTL8366RB_POWER_SAVE_ON BIT(12) + +@@ -889,6 +893,15 @@ static int rtl822xb_config_init(struct p + if (ret < 0) + return ret; + ++ if (of_property_read_bool(phydev->mdio.dev.of_node, "realtek,aldps-enable")) ++ ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1, ++ RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN); ++ else ++ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1, ++ RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN); ++ if (ret < 0) ++ return ret; ++ + /* Disable SGMII AN */ + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2); + if (ret < 0) diff --git a/6.12/target/linux/generic/pending-6.12/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch b/6.12/target/linux/generic/pending-6.12/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch index 6938552d..d7fbf3a2 100644 --- a/6.12/target/linux/generic/pending-6.12/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch +++ b/6.12/target/linux/generic/pending-6.12/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch @@ -12,9 +12,9 @@ over the implemented MMDs. Signed-off-by: Daniel Golle [forward-port by @namiltd] Signed-off-by: Mieczyslaw Nalewaj ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -1120,10 +1120,32 @@ static int rtl8226_match_phy_device(stru +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1166,10 +1166,32 @@ static int rtl8226_match_phy_device(stru static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, bool is_c45) { @@ -49,4 +49,4 @@ Signed-off-by: Mieczyslaw Nalewaj + } } - static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) + static int rtl8221b_match_phy_device(struct phy_device *phydev) diff --git a/6.12/target/linux/generic/pending-6.12/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch b/6.12/target/linux/generic/pending-6.12/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch index a796b8f0..45ca5413 100644 --- a/6.12/target/linux/generic/pending-6.12/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch +++ b/6.12/target/linux/generic/pending-6.12/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch @@ -7,12 +7,12 @@ This commit introduces interrupt support for RTL8221B. Signed-off-by: Jianhui Zhao --- - drivers/net/phy/realtek.c | 47 +++++++++++++++++++++++++++++++++++++++ + drivers/net/phy/realtek/realtek_main.c | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -1332,6 +1332,51 @@ static irqreturn_t rtl9000a_handle_inter +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1377,6 +1377,51 @@ static irqreturn_t rtl9000a_handle_inter return IRQ_HANDLED; } @@ -64,39 +64,39 @@ Signed-off-by: Jianhui Zhao static struct phy_driver realtek_drvs[] = { { PHY_ID_MATCH_EXACT(0x00008201), -@@ -1498,6 +1543,8 @@ static struct phy_driver realtek_drvs[] +@@ -1537,6 +1582,8 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", + .config_intr = rtl8221b_config_intr, + .handle_interrupt = rtl8221b_handle_interrupt, - .probe = rtl822x_probe, .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, .get_features = rtl822x_get_features, -@@ -1512,6 +1559,8 @@ static struct phy_driver realtek_drvs[] +@@ -1551,6 +1598,8 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", + .config_intr = rtl8221b_config_intr, + .handle_interrupt = rtl8221b_handle_interrupt, - .probe = rtl822x_probe, .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, .config_init = rtl822xb_config_init, -@@ -1524,6 +1573,8 @@ static struct phy_driver realtek_drvs[] +@@ -1563,6 +1612,8 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", + .config_intr = rtl8221b_config_intr, + .handle_interrupt = rtl8221b_handle_interrupt, - .probe = rtl822x_probe, .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, .get_features = rtl822x_get_features, -@@ -1538,6 +1589,8 @@ static struct phy_driver realtek_drvs[] +@@ -1577,6 +1628,8 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", + .config_intr = rtl8221b_config_intr, + .handle_interrupt = rtl8221b_handle_interrupt, - .probe = rtl822x_probe, .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, .config_init = rtl822xb_config_init, diff --git a/6.12/target/linux/generic/pending-6.12/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch b/6.12/target/linux/generic/pending-6.12/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch new file mode 100644 index 00000000..555e5905 --- /dev/null +++ b/6.12/target/linux/generic/pending-6.12/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch @@ -0,0 +1,27 @@ +From 1addfb042a9d27788a0fb2c2935045b56fd8560e Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 23 Jan 2025 03:25:29 +0000 +Subject: [PATCH] net: phy: realtek: mark existing MMDs as present + +When using Clause-45 mode to access RealTek RTL8221B 2.5G PHYs some +versions of the PHY fail to report the MMDs present on the PHY. +Mark MMDs PMAPMD, PCS and AN which are always existing according to +the datasheet as present to fix that. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek/realtek_main.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1043,6 +1043,9 @@ static int rtl822x_c45_get_features(stru + linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, + phydev->supported); + ++ phydev->c45_ids.mmds_present |= MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | ++ MDIO_DEVS_AN; ++ + return genphy_c45_pma_read_abilities(phydev); + } + diff --git a/6.12/target/linux/generic/pending-6.12/720-08-net-phy-realtek-work-around-broken-serdes.patch b/6.12/target/linux/generic/pending-6.12/720-08-net-phy-realtek-work-around-broken-serdes.patch new file mode 100644 index 00000000..e356a0a6 --- /dev/null +++ b/6.12/target/linux/generic/pending-6.12/720-08-net-phy-realtek-work-around-broken-serdes.patch @@ -0,0 +1,58 @@ +From: Daniel Golle +Date: Thu, 30 Jan 2025 05:33:12 +0000 +Subject: [PATCH] net: phy: realtek: work around broken SerDes + +For still unknown reasons the SerDes init sequence may sometimes +time out because a self-clearing bit never clears, indicating the +PHY has entered an unrecoverable error state. + +Work-around the issue by triggering a hardware reset and retry the +setup sequence while warning the user that this has happened. +This is really more of a work-around than a fix, and should be +replaced by a better actual fix in future (hopefully). + +Signed-off-by: Daniel Golle +--- +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -923,6 +923,22 @@ static int rtl822xb_config_init(struct p + return 0; + } + ++static int rtl822xb_config_init_war(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = rtl822xb_config_init(phydev); ++ ++ if (ret == -ETIMEDOUT) { ++ phydev_warn(phydev, "SerDes setup timed out, retrying\n"); ++ phy_device_reset(phydev, 1); ++ phy_device_reset(phydev, 0); ++ ret = rtl822xb_config_init(phydev); ++ } ++ ++ return ret; ++} ++ + static int rtl822xb_get_rate_matching(struct phy_device *phydev, + phy_interface_t iface) + { +@@ -1605,7 +1621,7 @@ static struct phy_driver realtek_drvs[] + .handle_interrupt = rtl8221b_handle_interrupt, + .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, +- .config_init = rtl822xb_config_init, ++ .config_init = rtl822xb_config_init_war, + .get_rate_matching = rtl822xb_get_rate_matching, + .get_features = rtl822x_c45_get_features, + .config_aneg = rtl822x_c45_config_aneg, +@@ -1635,7 +1651,7 @@ static struct phy_driver realtek_drvs[] + .handle_interrupt = rtl8221b_handle_interrupt, + .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, +- .config_init = rtl822xb_config_init, ++ .config_init = rtl822xb_config_init_war, + .get_rate_matching = rtl822xb_get_rate_matching, + .get_features = rtl822x_c45_get_features, + .config_aneg = rtl822x_c45_config_aneg, diff --git a/6.12/target/linux/generic/pending-6.12/720-09-net-phy-realtek-disable-MDIO-broadcast.patch b/6.12/target/linux/generic/pending-6.12/720-09-net-phy-realtek-disable-MDIO-broadcast.patch new file mode 100644 index 00000000..b2d26a87 --- /dev/null +++ b/6.12/target/linux/generic/pending-6.12/720-09-net-phy-realtek-disable-MDIO-broadcast.patch @@ -0,0 +1,27 @@ +From: Daniel Golle +Date: Thu, 30 Jan 2025 05:38:31 +0000 +Subject: [PATCH] net: phy: realtek: disable MDIO broadcast + +RealTek's PHYs by default also listen on MDIO address 0 which is defined +as broadcast address. This can lead to problems if there is an actual PHY +(such as MT7981 built-in PHY) present at this address, as accessing that +PHY may then confuse the RealTek PHY. + +Disabled listening on the MDIO broadcast address to avoid such problems. + +Signed-off-by: Daniel Golle +--- +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -849,6 +849,11 @@ static int rtl822xb_config_init(struct p + phydev->host_interfaces) || + phydev->interface == PHY_INTERFACE_MODE_SGMII; + ++ /* disable listening on MDIO broadcast address (0) */ ++ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, 0xa430, BIT(13)); ++ if (ret < 0) ++ return ret; ++ + /* fill in possible interfaces */ + __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces, + has_2500); diff --git a/6.12/target/linux/generic/pending-6.12/738-01-net-ethernet-mtk_eth_soc-reduce-rx-ring-size-for-older.patch b/6.12/target/linux/generic/pending-6.12/738-01-net-ethernet-mtk_eth_soc-reduce-rx-ring-size-for-older.patch new file mode 100644 index 00000000..7b88e3e6 --- /dev/null +++ b/6.12/target/linux/generic/pending-6.12/738-01-net-ethernet-mtk_eth_soc-reduce-rx-ring-size-for-older.patch @@ -0,0 +1,104 @@ +From: Felix Fietkau +Subject: [PATCH net-next 3/4] net: ethernet: mtk_eth_soc: reduce rx ring size for older chipsets +Date: Tue, 15 Oct 2024 13:09:37 +0200 + +Commit c57e55819443 ("net: ethernet: mtk_eth_soc: handle dma buffer +size soc specific") resolved some tx timeout issues by bumping FQ and +tx ring sizes from 512 to 2048 entries (the value used in the MediaTek +SDK), however it also changed the rx ring size for all chipsets in the +same way. + +Based on a few tests, it seems that a symmetric rx/tx ring size of 2048 +really only makes sense on MT7988, which is capable of 10G ethernet links. + +Older chipsets are typically deployed in systems that are more memory +constrained and don't actually need the larger rings to handle received +packets. + +In order to reduce wasted memory set the ring size based on the SoC to +the following values: +- 2048 on MT7988 +- 1024 on MT7986 +- 512 (previous value) on everything else, except: +- 256 on RT5350 (the oldest supported chipset) + +Fixes: c57e55819443 ("net: ethernet: mtk_eth_soc: handle dma buffer size soc specific") +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -5387,7 +5387,7 @@ static const struct mtk_soc_data mt2701_ + .desc_size = sizeof(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(512), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + }, +@@ -5415,7 +5415,7 @@ static const struct mtk_soc_data mt7621_ + .desc_size = sizeof(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(512), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + }, +@@ -5445,7 +5445,7 @@ static const struct mtk_soc_data mt7622_ + .desc_size = sizeof(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(512), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + }, +@@ -5474,7 +5474,7 @@ static const struct mtk_soc_data mt7623_ + .desc_size = sizeof(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(512), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + }, +@@ -5500,7 +5500,7 @@ static const struct mtk_soc_data mt7629_ + .desc_size = sizeof(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(512), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + }, +@@ -5532,7 +5532,7 @@ static const struct mtk_soc_data mt7981_ + .dma_l4_valid = RX_DMA_L4_VALID_V2, + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(512), + }, + }; + +@@ -5562,7 +5562,7 @@ static const struct mtk_soc_data mt7986_ + .dma_l4_valid = RX_DMA_L4_VALID_V2, + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(1K), + }, + }; + +@@ -5615,7 +5615,7 @@ static const struct mtk_soc_data rt5350_ + .dma_l4_valid = RX_DMA_L4_VALID_PDMA, + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(256), + }, + }; + diff --git a/6.12/target/linux/generic/pending-6.12/738-02-net-ethernet-mtk_eth_soc-do-not-enable-page-pool-sta.patch b/6.12/target/linux/generic/pending-6.12/738-02-net-ethernet-mtk_eth_soc-do-not-enable-page-pool-sta.patch new file mode 100644 index 00000000..190cea8f --- /dev/null +++ b/6.12/target/linux/generic/pending-6.12/738-02-net-ethernet-mtk_eth_soc-do-not-enable-page-pool-sta.patch @@ -0,0 +1,43 @@ +From: Danila Romanov +Date: Wed, 22 Jan 2025 06:48:45 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: do not enable page pool stats by + default + +There is no reason for it to be enabled by default. +Align mtk_eth_soc driver to mt76 driver. + +This option incurs additional CPU cost in allocation and recycle paths +and additional memory cost to store the statistics. + +Signed-off-by: Danila Romanov +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/Kconfig ++++ b/drivers/net/ethernet/mediatek/Kconfig +@@ -26,7 +26,6 @@ config NET_MEDIATEK_SOC + select PHYLINK + select DIMLIB + select PAGE_POOL +- select PAGE_POOL_STATS + select PCS_MTK_LYNXI + select REGMAP_MMIO + help +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4552,6 +4552,7 @@ static int mtk_get_sset_count(struct net + + static void mtk_ethtool_pp_stats(struct mtk_eth *eth, u64 *data) + { ++#ifdef CONFIG_PAGE_POOL_STATS + struct page_pool_stats stats = {}; + int i; + +@@ -4564,6 +4565,7 @@ static void mtk_ethtool_pp_stats(struct + page_pool_get_stats(ring->page_pool, &stats); + } + page_pool_ethtool_stats_get(data, &stats); ++#endif + } + + static void mtk_get_ethtool_stats(struct net_device *dev, diff --git a/6.12/target/linux/generic/pending-6.12/809-01-nvmem-core-generalize-mac-base-cells-handling.patch b/6.12/target/linux/generic/pending-6.12/809-01-nvmem-core-generalize-mac-base-cells-handling.patch new file mode 100644 index 00000000..139a925c --- /dev/null +++ b/6.12/target/linux/generic/pending-6.12/809-01-nvmem-core-generalize-mac-base-cells-handling.patch @@ -0,0 +1,248 @@ +From fd0e523037439520813db7c57df5bd37cdf40f7e Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Mon, 3 Feb 2025 00:10:18 +0100 +Subject: [PATCH 1/2] nvmem: core: generalize "mac-base" cells handling + +Generalize support of "mac-base" nvmem cells and provide a GPL symbol to +permit also other NVMEM layout driver to parse mac-base cells. + +It's VERY COMMON for some specially formatted NVMEM to expose a mac +address in ASCII format or HEX format hence prevent code duplication by +exposing a common helper. + +Such helper will change the nvmem_info_cell and apply the correct post +process function to correctly parse the mac address. + +Since the API requires OF and is only related to layout, move the +function in layouts.c to correctly handle non-OF NVMEM. + +Signed-off-by: Christian Marangi +--- + drivers/nvmem/core.c | 79 +-------------------------------- + drivers/nvmem/layouts.c | 80 ++++++++++++++++++++++++++++++++++ + include/linux/nvmem-provider.h | 4 ++ + 3 files changed, 86 insertions(+), 77 deletions(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -7,12 +7,9 @@ + */ + + #include +-#include +-#include + #include + #include + #include +-#include + #include + #include + #include +@@ -800,62 +797,6 @@ static int nvmem_validate_keepouts(struc + return 0; + } + +-static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset, +- void *buf, size_t bytes) +-{ +- if (WARN_ON(bytes != ETH_ALEN)) +- return -EINVAL; +- +- if (index) +- eth_addr_add(buf, index); +- +- return 0; +-} +- +-static int nvmem_mac_base_ascii_read(void *context, const char *id, int index, unsigned int offset, +- void *buf, size_t bytes) +-{ +- u8 mac[ETH_ALEN]; +- +- if (WARN_ON(bytes != 3 * ETH_ALEN - 1)) +- return -EINVAL; +- +- if (!mac_pton(buf, mac)) +- return -EINVAL; +- +- if (index) +- eth_addr_add(mac, index); +- +- ether_addr_copy(buf, mac); +- +- return 0; +-} +- +-static int nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset, +- void *buf, size_t bytes) +-{ +- u8 mac[ETH_ALEN], *hexstr; +- int i; +- +- if (WARN_ON(bytes != 2 * ETH_ALEN)) +- return -EINVAL; +- +- hexstr = (u8 *)buf; +- for (i = 0; i < ETH_ALEN; i++) { +- if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1])) +- return -EINVAL; +- +- mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]); +- } +- +- if (index) +- eth_addr_add(mac, index); +- +- ether_addr_copy(buf, mac); +- +- return 0; +-} +- + static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np) + { + struct device *dev = &nvmem->dev; +@@ -895,24 +836,8 @@ static int nvmem_add_cells_from_dt(struc + if (nvmem->fixup_dt_cell_info) + nvmem->fixup_dt_cell_info(nvmem, &info); + +- if (of_device_is_compatible(np, "fixed-layout")) { +- if (of_device_is_compatible(child, "mac-base")) { +- if (info.bytes == ETH_ALEN) { +- info.raw_len = info.bytes; +- info.bytes = ETH_ALEN; +- info.read_post_process = nvmem_mac_base_raw_read; +- } else if (info.bytes == 2 * ETH_ALEN) { +- info.raw_len = info.bytes; +- info.bytes = ETH_ALEN; +- info.read_post_process = nvmem_mac_base_hex_read; +- } else if (info.bytes == 3 * ETH_ALEN - 1) { +- info.raw_len = info.bytes; +- info.bytes = ETH_ALEN; +- info.read_post_process = nvmem_mac_base_ascii_read; +- } +- +- } +- } ++ if (of_device_is_compatible(np, "fixed-layout")) ++ nvmem_layout_parse_mac_base(&info); + + ret = nvmem_add_one_cell(nvmem, &info); + kfree(info.name); +--- a/drivers/nvmem/layouts.c ++++ b/drivers/nvmem/layouts.c +@@ -6,8 +6,11 @@ + * Author: Miquel Raynal + #include + #include ++#include ++#include + #include + #include + #include +@@ -21,6 +24,83 @@ + #define to_nvmem_layout_device(_dev) \ + container_of((_dev), struct nvmem_layout, dev) + ++static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset, ++ void *buf, size_t bytes) ++{ ++ if (WARN_ON(bytes != ETH_ALEN)) ++ return -EINVAL; ++ ++ if (index) ++ eth_addr_add(buf, index); ++ ++ return 0; ++} ++ ++static int nvmem_mac_base_ascii_read(void *context, const char *id, int index, unsigned int offset, ++ void *buf, size_t bytes) ++{ ++ u8 mac[ETH_ALEN]; ++ ++ if (WARN_ON(bytes != 3 * ETH_ALEN - 1)) ++ return -EINVAL; ++ ++ if (!mac_pton(buf, mac)) ++ return -EINVAL; ++ ++ if (index) ++ eth_addr_add(mac, index); ++ ++ ether_addr_copy(buf, mac); ++ ++ return 0; ++} ++ ++static int nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset, ++ void *buf, size_t bytes) ++{ ++ u8 mac[ETH_ALEN], *hexstr; ++ int i; ++ ++ if (WARN_ON(bytes != 2 * ETH_ALEN)) ++ return -EINVAL; ++ ++ hexstr = (u8 *)buf; ++ for (i = 0; i < ETH_ALEN; i++) { ++ if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1])) ++ return -EINVAL; ++ ++ mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]); ++ } ++ ++ if (index) ++ eth_addr_add(mac, index); ++ ++ ether_addr_copy(buf, mac); ++ ++ return 0; ++} ++ ++void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info) ++{ ++ if (!of_device_is_compatible(info->np, "mac-base")) ++ return; ++ ++ if (info->bytes == ETH_ALEN) { ++ info->raw_len = info->bytes; ++ info->bytes = ETH_ALEN; ++ info->read_post_process = nvmem_mac_base_raw_read; ++ } else if (info->bytes == 2 * ETH_ALEN) { ++ info->raw_len = info->bytes; ++ info->bytes = ETH_ALEN; ++ info->read_post_process = nvmem_mac_base_hex_read; ++ } else if (info->bytes == 3 * ETH_ALEN - 1) { ++ info->raw_len = info->bytes; ++ info->bytes = ETH_ALEN; ++ info->read_post_process = nvmem_mac_base_ascii_read; ++ } ++} ++EXPORT_SYMBOL_GPL(nvmem_layout_parse_mac_base); ++ + static int nvmem_layout_bus_match(struct device *dev, const struct device_driver *drv) + { + return of_driver_match_device(dev, drv); +--- a/include/linux/nvmem-provider.h ++++ b/include/linux/nvmem-provider.h +@@ -242,6 +242,8 @@ static inline void nvmem_layout_unregist + + #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) + ++void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info); ++ + /** + * of_nvmem_layout_get_container() - Get OF node of layout container + * +@@ -254,6 +256,8 @@ struct device_node *of_nvmem_layout_get_ + + #else /* CONFIG_NVMEM && CONFIG_OF */ + ++static inline void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info) {} ++ + static inline struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem) + { + return NULL; diff --git a/6.12/target/linux/generic/pending-6.12/809-02-nvmem-layouts-add-support-for-ascii-env-driver.patch b/6.12/target/linux/generic/pending-6.12/809-02-nvmem-layouts-add-support-for-ascii-env-driver.patch new file mode 100644 index 00000000..0906e0f7 --- /dev/null +++ b/6.12/target/linux/generic/pending-6.12/809-02-nvmem-layouts-add-support-for-ascii-env-driver.patch @@ -0,0 +1,204 @@ +From 38287e8ec5c0281377fc70f11f20bcd9986a05f5 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Mon, 3 Feb 2025 00:36:12 +0100 +Subject: [PATCH 2/2] nvmem: layouts: add support for ascii-env driver + +Add support for simple ASCII envirorment driver for NVMEM layouts. + +It's very common for devices to store simple text file format in +partition for environment varibles. The most common pattern is variable +name, a delimiter and variable value all separated by a new line +character (\n). + +This driver adds support for exporting such data and expose NVMEM cells +so they can be referenced by other drivers. This driver also supports +parsing mac-base NVMEM cells to parse ASCII or HEX mac address. + +Signed-off-by: Christian Marangi +--- + drivers/nvmem/layouts/Kconfig | 13 +++ + drivers/nvmem/layouts/Makefile | 1 + + drivers/nvmem/layouts/ascii-env.c | 140 ++++++++++++++++++++++++++++++ + 3 files changed, 154 insertions(+) + create mode 100644 drivers/nvmem/layouts/ascii-env.c + +--- a/drivers/nvmem/layouts/Kconfig ++++ b/drivers/nvmem/layouts/Kconfig +@@ -37,6 +37,19 @@ config NVMEM_LAYOUT_U_BOOT_ENV + + If unsure, say N. + ++config NVMEM_LAYOUT_ASCII_ENV ++ tristate "ASCII environment variables layout" ++ help ++ It's very common for devices to store simple text file format in ++ partition for environment varibles. The most common pattern is variable ++ name, a delimiter and variable value all separated by a new line ++ character (\n). ++ This driver adds support for exporting such data and expose NVMEM cells ++ so they can be referenced by other drivers. This driver also supports ++ parsing mac-base NVMEM cells to parse ASCII or HEX mac address. ++ ++ If unsure, say N. ++ + endmenu + + endif +--- a/drivers/nvmem/layouts/Makefile ++++ b/drivers/nvmem/layouts/Makefile +@@ -6,3 +6,4 @@ + obj-$(CONFIG_NVMEM_LAYOUT_SL28_VPD) += sl28vpd.o + obj-$(CONFIG_NVMEM_LAYOUT_ONIE_TLV) += onie-tlv.o + obj-$(CONFIG_NVMEM_LAYOUT_U_BOOT_ENV) += u-boot-env.o ++obj-$(CONFIG_NVMEM_LAYOUT_ASCII_ENV) += ascii-env.o +--- /dev/null ++++ b/drivers/nvmem/layouts/ascii-env.c +@@ -0,0 +1,148 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2024 Christian Marangi ++ * ++ * This borrow some parse logic from u-boot-env. ++ */ ++#include ++#include ++#include ++#include ++ ++struct ascii_env_match_data { ++ const char delim; ++}; ++ ++/* ++ * Parse a buffer as an ASCII text with name delimiter value and each pattern separated ++ * with a new line char '\n' ++ * Example: (delimiter '=') ++ * name=value\nname2=value2\n ++ * 2 Cell: ++ * - name: value ++ * - name2: value2 ++ */ ++static int ascii_env_parse_cells(struct device *dev, struct nvmem_device *nvmem, uint8_t *buf, ++ size_t data_len, const char delim) ++{ ++ char *var, *value, *eq, *lf; ++ char *data = buf; ++ ++ /* ++ * Warning the inner loop take care of replacing '\n' ++ * with '\0', hence we can use strlen on value. ++ */ ++ for (var = data; var < data + data_len && *var; ++ var = value + strlen(value) + 1) { ++ struct nvmem_cell_info info = {}; ++ struct device_node *child; ++ const char *label; ++ ++ eq = strchr(var, delim); ++ if (!eq) ++ break; ++ *eq = '\0'; ++ value = eq + 1; ++ ++ /* Replace '\n' with '\0' to use strlen for value */ ++ lf = strchr(value, '\n'); ++ if (!lf) ++ break; ++ *lf = '\0'; ++ ++ info.name = devm_kstrdup(dev, var, GFP_KERNEL); ++ if (!info.name) ++ return -ENOMEM; ++ info.offset = value - data; ++ info.bytes = strlen(value); ++ info.np = of_get_child_by_name(dev->of_node, info.name); ++ for_each_child_of_node(dev->of_node, child) { ++ if (!of_property_read_string(child, "label", &label) && ++ !strncmp(info.name, label, info.bytes)) ++ info.np = child; ++ else if (of_node_name_eq(child, info.name)) ++ info.np = child; ++ } ++ ++ nvmem_layout_parse_mac_base(&info); ++ ++ nvmem_add_one_cell(nvmem, &info); ++ } ++ ++ return 0; ++} ++ ++static int ascii_env_add_cells(struct nvmem_layout *layout) ++{ ++ struct nvmem_device *nvmem = layout->nvmem; ++ const struct ascii_env_match_data *data; ++ struct device *dev = &layout->dev; ++ size_t dev_size; ++ uint8_t *buf; ++ int bytes; ++ int ret; ++ ++ /* Get the delimiter for name value pattern */ ++ data = device_get_match_data(dev); ++ ++ dev_size = nvmem_dev_size(nvmem); ++ ++ buf = kzalloc(dev_size, GFP_KERNEL); ++ if (!buf) { ++ ret = -ENOMEM; ++ goto err_out; ++ } ++ ++ bytes = nvmem_device_read(nvmem, 0, dev_size, buf); ++ if (bytes < 0) { ++ ret = bytes; ++ goto err_kfree; ++ } else if (bytes != dev_size) { ++ ret = -EIO; ++ goto err_kfree; ++ } ++ ++ buf[dev_size - 1] = '\0'; ++ ret = ascii_env_parse_cells(dev, nvmem, buf, dev_size, data->delim); ++ ++err_kfree: ++ kfree(buf); ++err_out: ++ return ret; ++} ++ ++static int ascii_env_probe(struct nvmem_layout *layout) ++{ ++ layout->add_cells = ascii_env_add_cells; ++ ++ return nvmem_layout_register(layout); ++} ++ ++static void ascii_env_remove(struct nvmem_layout *layout) ++{ ++ nvmem_layout_unregister(layout); ++} ++ ++static const struct ascii_env_match_data ascii_env_eq = { ++ .delim = '=', ++}; ++ ++static const struct of_device_id ascii_env_of_match_table[] = { ++ { .compatible = "ascii-eq-delim-env", .data = &ascii_env_eq, }, ++ {}, ++}; ++ ++static struct nvmem_layout_driver ascii_env_layout = { ++ .driver = { ++ .name = "ascii-env-layout", ++ .of_match_table = ascii_env_of_match_table, ++ }, ++ .probe = ascii_env_probe, ++ .remove = ascii_env_remove, ++}; ++module_nvmem_layout_driver(ascii_env_layout); ++ ++MODULE_AUTHOR("Christian Marangi "); ++MODULE_LICENSE("GPL"); ++MODULE_DEVICE_TABLE(of, ascii_env_of_match_table); ++MODULE_DESCRIPTION("NVMEM layout driver for ASCII environment variables"); diff --git a/6.12/target/linux/generic/pending-6.12/891-dt-bindings-leds-Add-LED1202-LED-Controller.patch b/6.12/target/linux/generic/pending-6.12/891-dt-bindings-leds-Add-LED1202-LED-Controller.patch new file mode 100644 index 00000000..16425608 --- /dev/null +++ b/6.12/target/linux/generic/pending-6.12/891-dt-bindings-leds-Add-LED1202-LED-Controller.patch @@ -0,0 +1,181 @@ +From: Vicentiu Galanopulo +To: Pavel Machek , Lee Jones , + Rob Herring , + Krzysztof Kozlowski , + Conor Dooley , + Jonathan Corbet , + Vicentiu Galanopulo , + linux-leds@vger.kernel.org, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org +Cc: Krzysztof Kozlowski +Subject: [PATCH v11 2/3] dt-bindings: leds: Add LED1202 LED Controller +Date: Wed, 18 Dec 2024 18:33:58 +0000 [thread overview] +Message-ID: <20241218183401.41687-3-vicentiu.galanopulo@remote-tech.co.uk> (raw) +In-Reply-To: <20241218183401.41687-1-vicentiu.galanopulo@remote-tech.co.uk> + +The LED1202 is a 12-channel low quiescent current LED driver with: + * Supply range from 2.6 V to 5 V + * 20 mA current capability per channel + * 1.8 V compatible I2C control interface + * 8-bit analog dimming individual control + * 12-bit local PWM resolution + * 8 programmable patterns + +If the led node is present in the controller then the channel is +set to active. + +Signed-off-by: Vicentiu Galanopulo +Reviewed-by: Krzysztof Kozlowski +--- + v1: https://lore.kernel.org/lkml/ZnCnnQfwuRueCIQ0@admins-Air/T/ + v2: https://lore.kernel.org/all/ZniNdGgKyUMV-hjq@admins-Air/T/ + v3: https://lore.kernel.org/all/ZniNdGgKyUMV-hjq@admins-Air/T/ + + Changes in v4: + - remove label property, use devm_led_classdev_register_ext instead + Changes in v3: + - remove active property + Changes in v2: + - renamed label to remove color from it + - add color property for each node + - add function and function-enumerator property for each node + + .../devicetree/bindings/leds/st,led1202.yaml | 132 ++++++++++++++++++ + 1 file changed, 132 insertions(+) + create mode 100644 Documentation/devicetree/bindings/leds/st,led1202.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/leds/st,led1202.yaml +@@ -0,0 +1,132 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/leds/st,led1202.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: ST LED1202 LED controllers ++ ++maintainers: ++ - Vicentiu Galanopulo ++ ++description: | ++ The LED1202 is a 12-channel low quiescent current LED controller ++ programmable via I2C; The output current can be adjusted separately ++ for each channel by 8-bit analog and 12-bit digital dimming control. ++ Datasheet available at ++ https://www.st.com/en/power-management/led1202.html ++ ++properties: ++ compatible: ++ const: st,led1202 ++ ++ reg: ++ maxItems: 1 ++ ++ "#address-cells": ++ const: 1 ++ ++ "#size-cells": ++ const: 0 ++ ++patternProperties: ++ "^led@[0-9a-f]$": ++ type: object ++ $ref: common.yaml# ++ unevaluatedProperties: false ++ ++ properties: ++ reg: ++ minimum: 0 ++ maximum: 11 ++ ++ required: ++ - reg ++ ++required: ++ - compatible ++ - reg ++ - "#address-cells" ++ - "#size-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ led-controller@58 { ++ compatible = "st,led1202"; ++ reg = <0x58>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ led@0 { ++ reg = <0x0>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <1>; ++ }; ++ ++ led@1 { ++ reg = <0x1>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <2>; ++ }; ++ ++ led@2 { ++ reg = <0x2>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <3>; ++ }; ++ ++ led@3 { ++ reg = <0x3>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <4>; ++ }; ++ ++ led@4 { ++ reg = <0x4>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <5>; ++ }; ++ ++ led@5 { ++ reg = <0x5>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <6>; ++ }; ++ ++ led@6 { ++ reg = <0x6>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <7>; ++ }; ++ ++ led@7 { ++ reg = <0x7>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <8>; ++ }; ++ ++ led@8 { ++ reg = <0x8>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <9>; ++ }; ++ }; ++ }; ++... diff --git a/6.12/target/linux/generic/pending-6.12/892-leds-Add-LED1202-I2C-driver.patch b/6.12/target/linux/generic/pending-6.12/892-leds-Add-LED1202-I2C-driver.patch new file mode 100644 index 00000000..089f0921 --- /dev/null +++ b/6.12/target/linux/generic/pending-6.12/892-leds-Add-LED1202-I2C-driver.patch @@ -0,0 +1,513 @@ +From: Vicentiu Galanopulo +To: Pavel Machek , Lee Jones , + Rob Herring , + Krzysztof Kozlowski , + Conor Dooley , + Jonathan Corbet , + Vicentiu Galanopulo , + linux-leds@vger.kernel.org, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org +Subject: [PATCH v11 3/3] leds: Add LED1202 I2C driver +Date: Wed, 18 Dec 2024 18:33:59 +0000 [thread overview] +Message-ID: <20241218183401.41687-4-vicentiu.galanopulo@remote-tech.co.uk> (raw) +In-Reply-To: <20241218183401.41687-1-vicentiu.galanopulo@remote-tech.co.uk> + +The output current can be adjusted separately for each channel by 8-bit +analog (current sink input) and 12-bit digital (PWM) dimming control. The +LED1202 implements 12 low-side current generators with independent dimming +control. +Internal volatile memory allows the user to store up to 8 different patterns, +each pattern is a particular output configuration in terms of PWM +duty-cycle (on 4096 steps). Analog dimming (on 256 steps) is per channel but +common to all patterns. Each device tree LED node will have a corresponding +entry in /sys/class/leds with the label name. The brightness property +corresponds to the per channel analog dimming, while the patterns[1-8] to the +PWM dimming control. + +Signed-off-by: Vicentiu Galanopulo +--- + Changes in v10: + - update description help in Kconfig + - move st1202_led and st1202_chip into one line, declaration and definition + Changes in v9: + - log errors directly in st1202_write_reg and st1202_read_reg + - use mutex guards instead of lock/unlock + - remove i2c_set_clientdata + Changes in v7: + - fix st1202_brightness_get() error: uninitialized symbol 'value' + Changes in v6: + - fix build error + Changes in v5: + - remove unused macros + - switch to using devm_led_classdev_register_ext (struct st1202_led update) + - add prescalar_to_milliseconds (convert [22..5660]ms to [0..255] reg value) + - remove register range check in dt_init (range protected by yaml) + - address all review comments in v4 + Changes in v4: + - Remove attributes/extended attributes implementation + - Use /sys/class/leds//hw_pattern (Pavel suggestion) + - Implement review findings of Christophe JAILLET + Changes in v3: + - Rename all ll1202 to st1202, including driver file name + - Convert all magic numbers to defines + - Refactor the show/store callbacks as per Lee's and Thomas's review + - Remove ll1202_get_channel and use dev_ext_attributes instead + - Log all error values for all the functions + - Use sysfs_emit for show callbacks + Changes in v2: + - Fix build error for device_attribute modes + + drivers/leds/Kconfig | 10 + + drivers/leds/Makefile | 1 + + drivers/leds/leds-st1202.c | 416 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 427 insertions(+) + create mode 100644 drivers/leds/leds-st1202.c + +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -931,6 +931,16 @@ config LEDS_LM36274 + Say Y to enable the LM36274 LED driver for TI LMU devices. + This supports the LED device LM36274. + ++config LEDS_ST1202 ++ tristate "LED Support for STMicroelectronics LED1202 I2C chips" ++ depends on LEDS_CLASS ++ depends on I2C ++ depends on OF ++ select LEDS_TRIGGERS ++ help ++ Say Y to enable support for LEDs connected to LED1202 ++ LED driver chips accessed via the I2C bus. ++ + config LEDS_TPS6105X + tristate "LED support for TI TPS6105X" + depends on LEDS_CLASS +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -82,6 +82,7 @@ obj-$(CONFIG_LEDS_PWM) += leds-pwm.o + obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o + obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o + obj-$(CONFIG_LEDS_SUN50I_A100) += leds-sun50i-a100.o ++obj-$(CONFIG_LEDS_ST1202) += leds-st1202.o + obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o + obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o + obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o +--- /dev/null ++++ b/drivers/leds/leds-st1202.c +@@ -0,0 +1,416 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * LED driver for STMicroelectronics LED1202 chip ++ * ++ * Copyright (C) 2024 Remote-Tech Ltd. UK ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ST1202_CHAN_DISABLE_ALL 0x00 ++#define ST1202_CHAN_ENABLE_HIGH 0x03 ++#define ST1202_CHAN_ENABLE_LOW 0x02 ++#define ST1202_CONFIG_REG 0x04 ++/* PATS: Pattern sequence feature enable */ ++#define ST1202_CONFIG_REG_PATS BIT(7) ++/* PATSR: Pattern sequence runs (self-clear when sequence is finished) */ ++#define ST1202_CONFIG_REG_PATSR BIT(6) ++#define ST1202_CONFIG_REG_SHFT BIT(3) ++#define ST1202_DEV_ENABLE 0x01 ++#define ST1202_DEV_ENABLE_ON BIT(0) ++#define ST1202_DEV_ENABLE_RESET BIT(7) ++#define ST1202_DEVICE_ID 0x00 ++#define ST1202_ILED_REG0 0x09 ++#define ST1202_MAX_LEDS 12 ++#define ST1202_MAX_PATTERNS 8 ++#define ST1202_MILLIS_PATTERN_DUR_MAX 5660 ++#define ST1202_MILLIS_PATTERN_DUR_MIN 22 ++#define ST1202_PATTERN_DUR 0x16 ++#define ST1202_PATTERN_PWM 0x1E ++#define ST1202_PATTERN_REP 0x15 ++ ++struct st1202_led { ++ struct fwnode_handle *fwnode; ++ struct led_classdev led_cdev; ++ struct st1202_chip *chip; ++ bool is_active; ++ int led_num; ++}; ++ ++struct st1202_chip { ++ struct i2c_client *client; ++ struct mutex lock; ++ struct st1202_led leds[ST1202_MAX_LEDS]; ++}; ++ ++static struct st1202_led *cdev_to_st1202_led(struct led_classdev *cdev) ++{ ++ return container_of(cdev, struct st1202_led, led_cdev); ++} ++ ++static int st1202_read_reg(struct st1202_chip *chip, int reg, uint8_t *val) ++{ ++ struct device *dev = &chip->client->dev; ++ int ret; ++ ++ ret = i2c_smbus_read_byte_data(chip->client, reg); ++ if (ret < 0) { ++ dev_err(dev, "Failed to read register [0x%x]: %d\n", reg, ret); ++ return ret; ++ } ++ ++ *val = (uint8_t)ret; ++ return 0; ++} ++ ++static int st1202_write_reg(struct st1202_chip *chip, int reg, uint8_t val) ++{ ++ struct device *dev = &chip->client->dev; ++ int ret; ++ ++ ret = i2c_smbus_write_byte_data(chip->client, reg, val); ++ if (ret != 0) ++ dev_err(dev, "Failed to write %d to register [0x%x]: %d\n", val, reg, ret); ++ ++ return ret; ++} ++ ++static uint8_t st1202_prescalar_to_miliseconds(unsigned int value) ++{ ++ return value / ST1202_MILLIS_PATTERN_DUR_MIN - 1; ++} ++ ++static int st1202_pwm_pattern_write(struct st1202_chip *chip, int led_num, ++ int pattern, unsigned int value) ++{ ++ u8 value_l, value_h; ++ int ret; ++ ++ value_l = (u8)value; ++ value_h = (u8)(value >> 8); ++ ++ /* ++ * Datasheet: Register address low = 1Eh + 2*(xh) + 18h*(yh), ++ * where x is the channel number (led number) in hexadecimal (x = 00h .. 0Bh) ++ * and y is the pattern number in hexadecimal (y = 00h .. 07h) ++ */ ++ ret = st1202_write_reg(chip, (ST1202_PATTERN_PWM + (led_num * 2) + 0x18 * pattern), ++ value_l); ++ if (ret != 0) ++ return ret; ++ ++ /* ++ * Datasheet: Register address high = 1Eh + 01h + 2(xh) +18h*(yh), ++ * where x is the channel number in hexadecimal (x = 00h .. 0Bh) ++ * and y is the pattern number in hexadecimal (y = 00h .. 07h) ++ */ ++ ret = st1202_write_reg(chip, (ST1202_PATTERN_PWM + 0x1 + (led_num * 2) + 0x18 * pattern), ++ value_h); ++ if (ret != 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int st1202_duration_pattern_write(struct st1202_chip *chip, int pattern, ++ unsigned int value) ++{ ++ return st1202_write_reg(chip, (ST1202_PATTERN_DUR + pattern), ++ st1202_prescalar_to_miliseconds(value)); ++} ++ ++static void st1202_brightness_set(struct led_classdev *led_cdev, ++ enum led_brightness value) ++{ ++ struct st1202_led *led = cdev_to_st1202_led(led_cdev); ++ struct st1202_chip *chip = led->chip; ++ ++ guard(mutex)(&chip->lock); ++ ++ st1202_write_reg(chip, ST1202_ILED_REG0 + led->led_num, value); ++} ++ ++static enum led_brightness st1202_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct st1202_led *led = cdev_to_st1202_led(led_cdev); ++ struct st1202_chip *chip = led->chip; ++ u8 value = 0; ++ ++ guard(mutex)(&chip->lock); ++ ++ st1202_read_reg(chip, ST1202_ILED_REG0 + led->led_num, &value); ++ ++ return value; ++} ++ ++static int st1202_channel_set(struct st1202_chip *chip, int led_num, bool active) ++{ ++ u8 chan_low, chan_high; ++ int ret; ++ ++ guard(mutex)(&chip->lock); ++ ++ if (led_num <= 7) { ++ ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_LOW, &chan_low); ++ if (ret < 0) ++ return ret; ++ ++ chan_low = active ? chan_low | BIT(led_num) : chan_low & ~BIT(led_num); ++ ++ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, chan_low); ++ if (ret < 0) ++ return ret; ++ ++ } else { ++ ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_HIGH, &chan_high); ++ if (ret < 0) ++ return ret; ++ ++ chan_high = active ? chan_high | (BIT(led_num) >> 8) : ++ chan_high & ~(BIT(led_num) >> 8); ++ ++ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_HIGH, chan_high); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int st1202_led_set(struct led_classdev *ldev, enum led_brightness value) ++{ ++ struct st1202_led *led = cdev_to_st1202_led(ldev); ++ struct st1202_chip *chip = led->chip; ++ ++ return st1202_channel_set(chip, led->led_num, value == LED_OFF ? false : true); ++} ++ ++static int st1202_led_pattern_clear(struct led_classdev *ldev) ++{ ++ struct st1202_led *led = cdev_to_st1202_led(ldev); ++ struct st1202_chip *chip = led->chip; ++ int ret; ++ ++ guard(mutex)(&chip->lock); ++ ++ for (int patt = 0; patt < ST1202_MAX_PATTERNS; patt++) { ++ ret = st1202_pwm_pattern_write(chip, led->led_num, patt, LED_OFF); ++ if (ret != 0) ++ return ret; ++ ++ ret = st1202_duration_pattern_write(chip, patt, ST1202_MILLIS_PATTERN_DUR_MIN); ++ if (ret != 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int st1202_led_pattern_set(struct led_classdev *ldev, ++ struct led_pattern *pattern, ++ u32 len, int repeat) ++{ ++ struct st1202_led *led = cdev_to_st1202_led(ldev); ++ struct st1202_chip *chip = led->chip; ++ int ret; ++ ++ if (len > ST1202_MAX_PATTERNS) ++ return -EINVAL; ++ ++ guard(mutex)(&chip->lock); ++ ++ for (int patt = 0; patt < len; patt++) { ++ if (pattern[patt].delta_t < ST1202_MILLIS_PATTERN_DUR_MIN || ++ pattern[patt].delta_t > ST1202_MILLIS_PATTERN_DUR_MAX) ++ return -EINVAL; ++ ++ ret = st1202_pwm_pattern_write(chip, led->led_num, patt, pattern[patt].brightness); ++ if (ret != 0) ++ return ret; ++ ++ ret = st1202_duration_pattern_write(chip, patt, pattern[patt].delta_t); ++ if (ret != 0) ++ return ret; ++ } ++ ++ ret = st1202_write_reg(chip, ST1202_PATTERN_REP, repeat); ++ if (ret != 0) ++ return ret; ++ ++ ret = st1202_write_reg(chip, ST1202_CONFIG_REG, (ST1202_CONFIG_REG_PATSR | ++ ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_SHFT)); ++ if (ret != 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int st1202_dt_init(struct st1202_chip *chip) ++{ ++ struct device *dev = &chip->client->dev; ++ struct st1202_led *led; ++ int err, reg; ++ ++ for_each_available_child_of_node_scoped(dev_of_node(dev), child) { ++ struct led_init_data init_data = {}; ++ ++ err = of_property_read_u32(child, "reg", ®); ++ if (err) ++ return dev_err_probe(dev, err, "Invalid register\n"); ++ ++ led = &chip->leds[reg]; ++ led->is_active = true; ++ led->fwnode = of_fwnode_handle(child); ++ ++ led->led_cdev.max_brightness = U8_MAX; ++ led->led_cdev.brightness_set_blocking = st1202_led_set; ++ led->led_cdev.pattern_set = st1202_led_pattern_set; ++ led->led_cdev.pattern_clear = st1202_led_pattern_clear; ++ led->led_cdev.default_trigger = "pattern"; ++ ++ init_data.fwnode = led->fwnode; ++ init_data.devicename = "st1202"; ++ init_data.default_label = ":"; ++ ++ err = devm_led_classdev_register_ext(dev, &led->led_cdev, &init_data); ++ if (err < 0) ++ return dev_err_probe(dev, err, "Failed to register LED class device\n"); ++ ++ led->led_cdev.brightness_set = st1202_brightness_set; ++ led->led_cdev.brightness_get = st1202_brightness_get; ++ } ++ ++ return 0; ++} ++ ++static int st1202_setup(struct st1202_chip *chip) ++{ ++ int ret; ++ ++ guard(mutex)(&chip->lock); ++ ++ /* ++ * Once the supply voltage is applied, the LED1202 executes some internal checks, ++ * afterwords it stops the oscillator and puts the internal LDO in quiescent mode. ++ * To start the device, EN bit must be set inside the “Device Enable” register at ++ * address 01h. As soon as EN is set, the LED1202 loads the adjustment parameters ++ * from the internal non-volatile memory and performs an auto-calibration procedure ++ * in order to increase the output current precision. ++ * Such initialization lasts about 6.5 ms. ++ */ ++ ++ /* Reset the chip during setup */ ++ ret = st1202_write_reg(chip, ST1202_DEV_ENABLE, ST1202_DEV_ENABLE_RESET); ++ if (ret < 0) ++ return ret; ++ ++ /* Enable phase-shift delay feature */ ++ ret = st1202_write_reg(chip, ST1202_CONFIG_REG, ST1202_CONFIG_REG_SHFT); ++ if (ret < 0) ++ return ret; ++ ++ /* Enable the device */ ++ ret = st1202_write_reg(chip, ST1202_DEV_ENABLE, ST1202_DEV_ENABLE_ON); ++ if (ret < 0) ++ return ret; ++ ++ /* Duration of initialization */ ++ usleep_range(6500, 10000); ++ ++ /* Deactivate all LEDS (channels) and activate only the ones found in Device Tree */ ++ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, ST1202_CHAN_DISABLE_ALL); ++ if (ret < 0) ++ return ret; ++ ++ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_HIGH, ST1202_CHAN_DISABLE_ALL); ++ if (ret < 0) ++ return ret; ++ ++ ret = st1202_write_reg(chip, ST1202_CONFIG_REG, ++ ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_PATSR); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int st1202_probe(struct i2c_client *client) ++{ ++ struct st1202_chip *chip; ++ struct st1202_led *led; ++ int ret; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) ++ return dev_err_probe(&client->dev, -EIO, "SMBUS Byte Data not Supported\n"); ++ ++ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); ++ if (!chip) ++ return -ENOMEM; ++ ++ devm_mutex_init(&client->dev, &chip->lock); ++ chip->client = client; ++ ++ ret = st1202_dt_init(chip); ++ if (ret < 0) ++ return ret; ++ ++ ret = st1202_setup(chip); ++ if (ret < 0) ++ return ret; ++ ++ for (int i = 0; i < ST1202_MAX_LEDS; i++) { ++ led = &chip->leds[i]; ++ led->chip = chip; ++ led->led_num = i; ++ ++ if (!led->is_active) ++ continue; ++ ++ ret = st1202_channel_set(led->chip, led->led_num, true); ++ if (ret < 0) ++ return dev_err_probe(&client->dev, ret, ++ "Failed to activate LED channel\n"); ++ ++ ret = st1202_led_pattern_clear(&led->led_cdev); ++ if (ret < 0) ++ return dev_err_probe(&client->dev, ret, ++ "Failed to clear LED pattern\n"); ++ } ++ ++ return 0; ++} ++ ++static const struct i2c_device_id st1202_id[] = { ++ { "st1202-i2c" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(i2c, st1202_id); ++ ++static const struct of_device_id st1202_dt_ids[] = { ++ { .compatible = "st,led1202" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, st1202_dt_ids); ++ ++static struct i2c_driver st1202_driver = { ++ .driver = { ++ .name = "leds-st1202", ++ .of_match_table = of_match_ptr(st1202_dt_ids), ++ }, ++ .probe = st1202_probe, ++ .id_table = st1202_id, ++}; ++module_i2c_driver(st1202_driver); ++ ++MODULE_AUTHOR("Remote Tech LTD"); ++MODULE_DESCRIPTION("STMicroelectronics LED1202 : 12-channel constant current LED driver"); ++MODULE_LICENSE("GPL"); diff --git a/6.12/target/linux/generic/pending-6.12/893-leds_st1202-Fix-NULL-pointer-access-error.patch b/6.12/target/linux/generic/pending-6.12/893-leds_st1202-Fix-NULL-pointer-access-error.patch new file mode 100644 index 00000000..d763c5df --- /dev/null +++ b/6.12/target/linux/generic/pending-6.12/893-leds_st1202-Fix-NULL-pointer-access-error.patch @@ -0,0 +1,70 @@ +From e3da313ebcace17f1227566fe1b0d0c3883061f9 Mon Sep 17 00:00:00 2001 +From: Manuel Fombuena +Date: Fri, 17 Jan 2025 12:31:49 +0000 +Subject: [PATCH 1/5] leds: leds-st1202: fix NULL pointer access on race + condition + +st1202_dt_init() calls devm_led_classdev_register_ext() before the +internal data structures are properly setup, so the leds become visible +to user space while being partially initialized, leading to a window +where trying to access them causes a NULL pointer access. + +This change moves devm_led_classdev_register_ext() to the last thing to +happen during initialization to eliminate it. + +Signed-off-by: Manuel Fombuena +--- + drivers/leds/leds-st1202.c | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +--- a/drivers/leds/leds-st1202.c ++++ b/drivers/leds/leds-st1202.c +@@ -261,8 +261,6 @@ static int st1202_dt_init(struct st1202_ + int err, reg; + + for_each_available_child_of_node_scoped(dev_of_node(dev), child) { +- struct led_init_data init_data = {}; +- + err = of_property_read_u32(child, "reg", ®); + if (err) + return dev_err_probe(dev, err, "Invalid register\n"); +@@ -276,15 +274,6 @@ static int st1202_dt_init(struct st1202_ + led->led_cdev.pattern_set = st1202_led_pattern_set; + led->led_cdev.pattern_clear = st1202_led_pattern_clear; + led->led_cdev.default_trigger = "pattern"; +- +- init_data.fwnode = led->fwnode; +- init_data.devicename = "st1202"; +- init_data.default_label = ":"; +- +- err = devm_led_classdev_register_ext(dev, &led->led_cdev, &init_data); +- if (err < 0) +- return dev_err_probe(dev, err, "Failed to register LED class device\n"); +- + led->led_cdev.brightness_set = st1202_brightness_set; + led->led_cdev.brightness_get = st1202_brightness_get; + } +@@ -368,6 +357,7 @@ static int st1202_probe(struct i2c_clien + return ret; + + for (int i = 0; i < ST1202_MAX_LEDS; i++) { ++ struct led_init_data init_data = {}; + led = &chip->leds[i]; + led->chip = chip; + led->led_num = i; +@@ -384,6 +374,15 @@ static int st1202_probe(struct i2c_clien + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to clear LED pattern\n"); ++ ++ init_data.fwnode = led->fwnode; ++ init_data.devicename = "st1202"; ++ init_data.default_label = ":"; ++ ++ ret = devm_led_classdev_register_ext(&client->dev, &led->led_cdev, &init_data); ++ if (ret < 0) ++ return dev_err_probe(&client->dev, ret, ++ "Failed to register LED class device\n"); + } + + return 0;