Compare commits

..

31 Commits

Author SHA1 Message Date
Tom Elliott
43e7edf786 Should try to ensure we do MPA things when image type is MPA 2025-12-21 07:51:23 -06:00
Tom Elliott
8893d32bfb Sort the drives, but let lsblk be the commanding order of the drives 2025-10-14 04:52:24 -05:00
Tom Elliott
7a8264cf25 Should allow ability to define kernelarg == largesize="anything" to force largest disk to be primary disk. Otherwise will take the first ordered disk as the primary drive 2025-09-19 14:47:10 -05:00
Tom Elliott
3f44c60ec2 Should fix name ordering 2025-09-19 08:03:24 -05:00
Tom Elliott
dda9e28bc8 Should hopefully help with #100 again, but be a little less repeating in logic 2025-07-31 07:49:48 -05:00
Tom Elliott
2e501640e7 Should address introduced bug and maintain functionality found from #100. 2025-07-31 07:01:33 -05:00
Tom Elliott
ad837a6bd9 Shoudl reset to most recent before today kernel configs 2025-07-31 06:36:07 -05:00
Tom Elliott
28cfe9eb4f Revert kernel configs accidentally updated 2025-07-31 06:35:00 -05:00
Tom Elliott
710c27c4ed Should fix fdrive lookups 2025-07-31 06:32:40 -05:00
Tom Elliott
b3e34926b3 Stop escaping forward slashes 2025-07-15 05:11:21 -05:00
Tom Elliott
89b9608371 Should fix typoed double semicolon 2025-07-14 08:32:48 -05:00
rluzuriaga
c69a804e3a
chore(configs): update buildroot to 2025.02.4 2025-07-01 22:35:27 -07:00
rluzuriaga
61ed22b001 chore(configs): update kernel to 6.12.35 2025-07-01 21:13:55 -07:00
rluzuriaga
274999bcec feat(configs): add the configs for r8125, r8126, and r8168
- Enabled for x64 & arm64
- Disabled for x86
- Disabled the r8169 config if the r8125, r8126, and r8168 configs are enabled
2025-07-01 21:13:55 -07:00
rluzuriaga
4f434321ae feat(kernel): add Realtek network drivers for r8125, r8126, and r8168
This fixes the issues present in these forum posts:
https://forums.fogproject.org/topic/17900/asus-nuc14mnk-fos-kernel-no-netwerk-drivers
https://forums.fogproject.org/post/156789
2025-07-01 21:13:55 -07:00
rluzuriaga
cfa3187c79 chore(deps): add package needed for the new kernel package function 2025-07-01 21:13:55 -07:00
rluzuriaga
1c99536c1e feat(build): implement a way to add a custom kernel package/driver 2025-07-01 21:13:55 -07:00
rluzuriaga
e5345d2800 style(deps): fix linting errors/warnings using ShellCheck 2025-07-01 21:13:55 -07:00
rluzuriaga
2643db35bc style(build): fix linting errors/warnings using ShellCheck 2025-07-01 21:13:55 -07:00
Tom Elliott
0ceb4edc3e More refinement and hopeful dig in to debug for #100 and future proofing 2025-07-01 06:58:48 -05:00
Tom Elliott
a6e712395e Attempt to add UUID and make sure all search elements besides disk name are matched case insensitive for #100 2025-07-01 06:35:01 -05:00
Tom Elliott
887ec3abff Should fix the source of partition-funcs.sh 2025-07-01 06:20:02 -05:00
Tom Elliott
d50ae1de7b Refactored getHardDisk function 2025-07-01 06:18:28 -05:00
Tom Elliott
24d86d310e Should try to fail out if the fdrive param does not exist. 2025-07-01 05:59:38 -05:00
Tom Elliott
84036c68e6 Hopeful adjustment/fix for #105 2025-06-30 07:16:10 -05:00
rluzuriaga
f87f58758b Update dependencies 2025-04-29 11:22:41 -07:00
rluzuriaga
d316ba2f97 Update testdisk to from 7.1 to 7.2 2025-04-29 11:22:41 -07:00
rluzuriaga
2fe1159027 Update chntpw patch to remove GCC compile errors due to old C lang code 2025-04-29 11:22:41 -07:00
rluzuriaga
23f9f4fe60 Update filesystem patch to allow for compiler warning instead of errors. 2025-04-29 11:22:41 -07:00
rluzuriaga
b05c8e5e6a Update Buildroot to 2025.02 2025-04-29 11:22:41 -07:00
rluzuriaga
f3532b55c4 Update kernel to 6.12.25 2025-04-29 11:22:41 -07:00
97 changed files with 112294 additions and 576 deletions

View File

@ -1476,67 +1476,162 @@ getPartitions() {
[[ -z $disk ]] && handleError "No disk found (${FUNCNAME[0]})\n Args Passed: $*"
parts=$(lsblk -I 3,8,9,179,202,253,259 -lpno KNAME,TYPE $disk | awk '{if ($2 ~ /part/ || $2 ~ /md/) print $1}' | sort -V | uniq)
}
normalize() {
local input="$*"
# If no arguments, read from stdin
if [[ -z "$input" ]]; then
input=$(cat)
fi
echo $(trim "$input" | xargs | tr '[:upper:]' '[:lower:]')
}
resolve_path() {
local input="$*"
# If no arguments, read from stdin
if [[ -z "$input" ]]; then
input=$(cat)
fi
echo $(readlink -f "$input" 2>/dev/null || echo "$input")
}
# Gets the hard drive on the host
# Note: This function makes a best guess
getHardDisk() {
hd=""
disks=""
local devs=$(lsblk -dpno KNAME -I 3,8,9,179,202,253,259 | uniq | sort -V)
# Get valid devices (filter out 0B disks) once, keeping lsblk enumeration order
local devs
devs=$(lsblk -dpno KNAME,SIZE -I 3,8,9,179,202,253,259 | awk '$2 != "0B" && !seen[$1]++ { print $1 }')
if [[ -n $fdrive ]]; then
for spec in $(echo $fdrive | tr "," "\n"); do
local found_match=0
for spec in ${fdrive//,/ }; do
local spec_resolved spec_norm spec_normalized matched
spec_resolved=$(resolve_path "$spec")
spec_normalized=$(normalize "$spec")
matched=0
for dev in $devs; do
if [[ "x$spec" = "x$dev" ||
"x$spec" = "x$(trim $(blockdev --getsize64 $dev))" ||
"x$spec" = "x$(trim $(lsblk -pdno SERIAL $dev))" ||
"x$spec" = "x$(trim $(lsblk -pdno WWN $dev))" ]]; then
disks=$(echo "$disks $dev")
escaped_dev=$(echo $dev | sed -e 's/[]"\/$&*.^|[]/\\&/g')
devs=$(echo ${devs} | sed "s/[[:space:]]*${escaped_dev}[[:space:]]*/ /")
local size uuid serial wwn
size=$(blockdev --getsize64 "$dev" | normalize)
uuid=$(blkid -s UUID -o value "$dev" 2>/dev/null | normalize)
# Grab SERIAL and WWN safely (handles blanks and spacing)
local kv serial_raw wwn_raw
kv="$(lsblk -pdPno SERIAL,WWN "$dev" 2>/dev/null)" || kv=""
serial_raw="$(sed -n 's/.*SERIAL="\([^"]*\)".*/\1/p' <<<"$kv")"
wwn_raw="$(sed -n 's/.*WWN="\([^"]*\)".*/\1/p' <<<"$kv")"
serial="$(normalize "$serial_raw")"
wwn="$(normalize "$wwn_raw")"
[[ -n $isdebug ]] && {
echo "Comparing spec='$spec' (resolved: '$spec_resolved') with dev=$dev"
echo " size=$size serial=$serial wwn=$wwn uuid=$uuid"
}
if [[ "x$spec_resolved" == "x$dev" || \
"x$spec_normalized" == "x$size" || \
"x$spec_normalized" == "x$wwn" || \
"x$spec_normalized" == "x$serial" || \
"x$spec_normalized" == "x$uuid" ]]; then
[[ -n $isdebug ]] && echo "Matched spec '$spec' to device '$dev' (size=$size, serial=$serial, wwn=$wwn, uuid=$uuid)"
matched=1
found_match=1
disks="$disks $dev"
# remove matched dev from the pool
devs="$(echo " $devs " | sed "s# $dev # #g; s/^ *//; s/ *$//")"
break
else
p1="$(trim $(blockdev --getsize64 $dev))"
p2="$(trim $(lsblk -pdno SERIAL $dev))"
p3="$(trim $(lsblk -pdno WWN $dev))"
fi
done
[[ $matched -eq 0 ]] && echo "WARNING: Drive spec '$spec' does not match any available device." >&2
done
disks=$( echo "${disks} ${devs}" | xargs)
elif [[ -r ${imagePath}/d1.size && -r ${imagePath}/d2.size ]]; then
disks=$(echo ${devs})
disk_count=$(echo "$disks" | wc -w)
disk_array=()
size_information=$(cat ${imagePath}/*.size 2>/dev/null)
for disk_number in $(seq 1 $disk_count); do
disk=$(echo $disks | cut -d' ' -f $disk_number)
if [[ -n "${size_information}" ]]; then
disk_size=$(blockdev --getsize64 $disk)
image_matching_size=$(echo ${size_information} | grep -o "[0-9][0-9]*:${disk_size}" | head -1 | cut -d':' -f1)
if [[ -n $image_matching_size && $image_matching_size -gt 0 && $image_matching_size -le 32 ]]; then
disk_number=$image_matching_size
else
closest_sized_image=$(echo -e "${size_information}\nx:${disk_size}" | sort -t':' -k2 -n | grep -B1 "${disk_size}" | head -1 | cut -d':' -f1 )
if [[ -n $closest_sized_image && $closest_sized_image -gt 0 && $closest_sized_image -le 32 ]]; then
disk_number=$closest_sized_image
[[ $found_match -eq 0 ]] && handleError "Fatal: No valid drives found for 'Host Primary Disk'='$fdrive'."
disks=$(echo "$disks $devs" | xargs) # add unmatched devices for completeness
elif [[ "x$imgType" == "xmpa" ]]; then
# Multi-disk image: keep enumeration order
disks="$devs"
if [[ "x$type" == "xdown" ]]; then
# Expected disk sizes from image (d1.size, d2.size, ...)
local sizefiles expected_sizes=()
sizefiles=$(ls -1 "${imagePath}"/d*.size 2>/dev/null | sort -V)
if [[ -n "$sizefiles" ]]; then
local f exp
for f in $sizefiles; do
# file format: d1: 123456789
exp="$(awk -F: '{gsub(/[[:space:]]/,"",$2); print $2}' "$f")"
[[ -n "$exp" ]] && expected_sizes+=("$exp")
done
# Actual disks (keep lsblk order)
local actual_disks=()
for d in $devs; do actual_disks+=("$d"); done
# Build mapping in d1,d2,... order
local mapped=() used=" "
local i match candidates
for i in "${!expected_sizes[@]}"; do
exp="${expected_sizes[$i]}"
match=""
candidates=0
# Exact match pass
for d in "${actual_disks[@]}"; do
[[ "$used" == *" $d "* ]] && continue
if [[ "$(blockdev --getsize64 "$d" 2>/dev/null)" == "$exp" ]]; then
match="$d"
candidates=$((candidates+1))
fi
done
if [[ $candidates -eq 1 ]]; then
mapped+=("$match")
used+=" $match "
continue
fi
# Ambiguous or missing -> warn and fall back
echo "WARNING: Could not uniquely match disk for expected size $exp (found $candidates exact matches). Falling back to enumeration order." >&2
mapped=()
break
done
if [[ ${#mapped[@]} -gt 0 ]]; then
disks="${mapped[*]}"
hd="${mapped[0]}"
return 0
fi
size_information=$(echo ${size_information} | sed "s/[[:space:]]*[0-9][0-9]*:${disk_size}[[:space:]]*//")
fi
echo "${disk_array[@]}" | grep -q "$disk"
if [[ $? -eq 0 ]]; then
handleError "Fatal Error: Disk size information would lead to overwrite the already cloned disk $disk. ($0)"
fi
disk_array[$disk_number]=$disk
done
disks=${disk_array[@]}
fi
else
disks=$(echo ${devs})
if [[ -n $largesize ]]; then
# Auto-select largest available drive
hd=$(
for d in $devs; do
echo "$(blockdev --getsize64 "$d") $d"
done | sort -k1,1nr -k2,2 | head -1 | cut -d' ' -f2
)
else
for d in $devs; do
hd="$d"
break
done
fi
[[ -z $hd ]] && handleError "Could not determine a suitable disk automatically."
disks="$hd"
fi
for hd in $disks; do
break
done
[[ -z $hd || -z $disks ]] && handleError "Cannot find hard disk(s) (${FUNCNAME[0]})\n Args Passed: $*"
# Set primary hard disk
hd=$(awk '{print $1}' <<< "$disks")
}
# Finds the hard drive info and set's up the type
findHDDInfo() {
dots "Looking for Hard Disk(s)"

View File

@ -1,15 +1,15 @@
Binary files chntpw-140201/chntpw.static and chntpw-140201_new/chntpw.static differ
diff -rupN chntpw-140201/Makefile chntpw-140201_new/Makefile
--- chntpw-140201/Makefile 2014-02-01 11:54:37.000000000 -0500
+++ chntpw-140201_new/Makefile 2014-03-06 21:17:44.603673531 -0500
@@ -7,13 +7,8 @@
diff --git a/Makefile b/Makefile
index 6b4531e..9be0b0e 100644
--- a/Makefile
+++ b/Makefile
@@ -7,13 +7,9 @@
#
#SSLPATH=/usr/local/ssl
-OSSLPATH=/usr
+OSSLPATH=../../.././output/target/usr
OSSLINC=$(OSSLPATH)/include
-
-CC=gcc
-
-# Force 32 bit
@ -17,13 +17,13 @@ diff -rupN chntpw-140201/Makefile chntpw-140201_new/Makefile
OSSLLIB=$(OSSLPATH)/lib
# 64 bit if default for compiler setup
@@ -26,37 +21,22 @@ OSSLLIB=$(OSSLPATH)/lib
@@ -26,36 +22,23 @@ OSSLLIB=$(OSSLPATH)/lib
LIBS=-L$(OSSLLIB)
-all: chntpw chntpw.static cpnt reged reged.static samusrgrp samusrgrp.static sampasswd sampasswd.static
-
+all: chntpw cpnt reged samusrgrp sampasswd
chntpw: chntpw.o ntreg.o edlib.o libsam.o
$(CC) $(CFLAGS) -o chntpw chntpw.o ntreg.o edlib.o libsam.o $(LIBS)
@ -52,10 +52,50 @@ diff -rupN chntpw-140201/Makefile chntpw-140201_new/Makefile
- $(CC) -static $(CFLAGS) -o sampasswd.static sampasswd.o ntreg.o libsam.o
-
-
-
#ts: ts.o ntreg.o
# $(CC) $(CFLAGS) -nostdlib -o ts ts.o ntreg.o $(LIBS)
diff --git a/chntpw-presplit.c b/chntpw-presplit.c
index 824fed5..a8203b9 100644
--- a/chntpw-presplit.c
+++ b/chntpw-presplit.c
@@ -582,7 +582,7 @@ int put_grp_members_sid(int grp, struct sid_array *sarray)
Binary files chntpw-140201/reged.static and chntpw-140201_new/reged.static differ
Binary files chntpw-140201/sampasswd.static and chntpw-140201_new/sampasswd.static differ
Binary files chntpw-140201/samusrgrp.static and chntpw-140201_new/samusrgrp.static differ
if (gverbose) printf("put_grp_members_sid: ajusted: mofs = %x, mlen = %x (%d)\n", mofs + 0x34 ,mlen,mlen);
- if (gverbose) hexdump(&c->data, 0, c->len, 1);
+ if (gverbose) hexdump((char *)&c->data, 0, c->len, 1);
/* Get total size of new SID data */
@@ -610,7 +610,7 @@ int put_grp_members_sid(int grp, struct sid_array *sarray)
cd->members_len = sidlen; /* Update member count in C struct */
cd->grp_members = i;
- if (gverbose) hexdump(&c->data, 0, c->len, 1);
+ if (gverbose) hexdump((char *)&c->data, 0, c->len, 1);
if (!put_buf2val(hive[H_SAM], c, 0, g, 0, TPF_VK_EXACT)) {
fprintf(stderr,"put_grp_members_sid: could not write back group info in value %s\n",g);
diff --git a/libsam.c b/libsam.c
index 2c06c11..0932db7 100644
--- a/libsam.c
+++ b/libsam.c
@@ -511,7 +511,7 @@ int sam_put_grp_members_sid(struct hive *hdesc, int grp, struct sid_array *sarra
if (gverbose) printf("put_grp_members_sid: ajusted: mofs = %x, mlen = %x (%d)\n", mofs + 0x34 ,mlen,mlen);
- if (gverbose) hexdump(&c->data, 0, c->len, 1);
+ if (gverbose) hexdump((char *)&c->data, 0, c->len, 1);
/* Get total size of new SID data */
@@ -539,7 +539,7 @@ int sam_put_grp_members_sid(struct hive *hdesc, int grp, struct sid_array *sarra
cd->members_len = sidlen; /* Update member count in C struct */
cd->grp_members = i;
- if (gverbose) hexdump(&c->data, 0, c->len, 1);
+ if (gverbose) hexdump((char *)&c->data, 0, c->len, 1);
if (!put_buf2val(hdesc, c, 0, g, 0, TPF_VK_EXACT)) {
fprintf(stderr,"put_grp_members_sid: could not write back group info in value %s\n",g);

View File

@ -3,7 +3,7 @@
# testdisk
#
#############################################################
TESTDISK_VERSION:=7.1
TESTDISK_VERSION:=7.2
TESTDISK_SOURCE:=testdisk-$(TESTDISK_VERSION).tar.bz2
TESTDISK_SITE:=http://www.cgsecurity.org
TESTDISK_INSTALL_STAGING=YES

View File

@ -0,0 +1,5 @@
source "drivers/net/ethernet/realtek/r8125/Kconfig"
source "drivers/net/ethernet/realtek/r8126/Kconfig"
source "drivers/net/ethernet/realtek/r8168/Kconfig"

View File

@ -0,0 +1,4 @@
obj-$(CONFIG_R8125) += r8125/
obj-$(CONFIG_R8126) += r8126/
obj-$(CONFIG_R8168) += r8168/

View File

@ -0,0 +1 @@
savedcmd_drivers/net/ethernet/realtek/r8125/built-in.a := rm -f drivers/net/ethernet/realtek/r8125/built-in.a; printf "drivers/net/ethernet/realtek/r8125/%s " r8125_n.o rtl_eeprom.o rtltool.o r8125_fiber.o | xargs ar cDPrST drivers/net/ethernet/realtek/r8125/built-in.a

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
config R8125
tristate "Realtek 2.5G Ethernet driver (r8125)"
depends on PCI && MII
help
This is the official Realtek 2.5G Ethernet driver.

View File

@ -0,0 +1,76 @@
obj-$(CONFIG_R8125) += r8125.o
r8125-objs += r8125_n.o rtl_eeprom.o rtltool.o r8125_fiber.o
EXTRA_CFLAGS += -DCONFIG_SOC_LAN
EXTRA_CFLAGS += -DENABLE_FIBER_SUPPORT
EXTRA_CFLAGS += -DCONFIG_ASPM
EXTRA_CFLAGS += -DENABLE_S5WOL
EXTRA_CFLAGS += -DENABLE_TX_NO_CLOSE
EXTRA_CFLAGS += -DENABLE_GIGA_LITE
# EXTRA_CFLAGS += -DCONFIG_R8125_NAPI # Need to check if needed
# EXTRA_CFLAGS += -DCONFIG_R8125_VLAN # Need to check if needed
#
# Other options that can be enabled if needed.
#
# ENABLE_REALWOW_SUPPORT:
# r8125-objs += r8125_realwow.o
# EXTRA_CFLAGS += -DENABLE_REALWOW_SUPPORT
#
# ENABLE_DASH_SUPPORT:
# r8125-objs += r8125_dash.o
# EXTRA_CFLAGS += -DENABLE_DASH_SUPPORT
#
# ENABLE_DASH_PRINTER_SUPPORT:
# r8125-objs += r8125_dash.o
# EXTRA_CFLAGS += -DENABLE_DASH_SUPPORT -DENABLE_DASH_PRINTER_SUPPORT
#
# CONFIG_DOWN_SPEED_100:
# EXTRA_CFLAGS += -DCONFIG_DOWN_SPEED_100
#
# ENABLE_S5_KEEP_CURR_MAC:
# EXTRA_CFLAGS += -DENABLE_S5_KEEP_CURR_MAC
#
# ENABLE_EEE:
# EXTRA_CFLAGS += -DENABLE_EEE
#
# ENABLE_S0_MAGIC_PACKET:
# EXTRA_CFLAGS += -DENABLE_S0_MAGIC_PACKET
#
# ENABLE_MULTIPLE_TX_QUEUE:
# EXTRA_CFLAGS += -DENABLE_MULTIPLE_TX_QUEUE
#
# ENABLE_PTP_SUPPORT:
# r8125-objs += r8125_ptp.o
# EXTRA_CFLAGS += -DENABLE_PTP_SUPPORT
#
# ENABLE_PTP_MASTER_MODE:
# EXTRA_CFLAGS += -DENABLE_PTP_MASTER_MODE
#
# ENABLE_RSS_SUPPORT:
# r8125-objs += r8125_rss.o
# EXTRA_CFLAGS += -DENABLE_RSS_SUPPORT
#
# ENABLE_LIB_SUPPORT:
# r8125-objs += r8125_lib.o
# EXTRA_CFLAGS += -DENABLE_LIB_SUPPORT
#
# ENABLE_USE_FIRMWARE_FILE:
# r8125-objs += r8125_firmware.o
# EXTRA_CFLAGS += -DENABLE_USE_FIRMWARE_FILE
#
# DISABLE_WOL_SUPPORT:
# EXTRA_CFLAGS += -DDISABLE_WOL_SUPPORT
#
# DISABLE_MULTI_MSIX_VECTOR:
# EXTRA_CFLAGS += -DDISABLE_MULTI_MSIX_VECTOR
#
# ENABLE_DOUBLE_VLAN:
# EXTRA_CFLAGS += -DENABLE_DOUBLE_VLAN
#
# ENABLE_PAGE_REUSE:
# EXTRA_CFLAGS += -DENABLE_PAGE_REUSE
#
# ENABLE_RX_PACKET_FRAGMENT:
# EXTRA_CFLAGS += -DENABLE_RX_PACKET_FRAGMENT

View File

@ -0,0 +1,11 @@
!<thin>
// 52 `
r8125_n.o/
rtl_eeprom.o/
rtltool.o/
r8125_fiber.o/
/0 0 0 0 644 455568 `
/11 0 0 0 644 10016 `
/25 0 0 0 644 6712 `
/36 0 0 0 644 10992 `

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,196 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8125 is the Linux device driver released for Realtek 2.5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2025 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_R8125_DASH_H
#define _LINUX_R8125_DASH_H
#include <linux/if.h>
#define SIOCDEVPRIVATE_RTLDASH SIOCDEVPRIVATE+2
enum rtl_dash_cmd {
RTL_DASH_ARP_NS_OFFLOAD = 0,
RTL_DASH_SET_OOB_IPMAC,
RTL_DASH_NOTIFY_OOB,
RTL_DASH_SEND_BUFFER_DATA_TO_DASH_FW,
RTL_DASH_CHECK_SEND_BUFFER_TO_DASH_FW_COMPLETE,
RTL_DASH_GET_RCV_FROM_FW_BUFFER_DATA,
RTL_DASH_OOB_REQ,
RTL_DASH_OOB_ACK,
RTL_DASH_DETACH_OOB_REQ,
RTL_DASH_DETACH_OOB_ACK,
RTL_FW_SET_IPV4 = 0x10,
RTL_FW_GET_IPV4,
RTL_FW_SET_IPV6,
RTL_FW_GET_IPV6,
RTL_FW_SET_EXT_SNMP,
RTL_FW_GET_EXT_SNMP,
RTL_FW_SET_WAKEUP_PATTERN,
RTL_FW_GET_WAKEUP_PATTERN,
RTL_FW_DEL_WAKEUP_PATTERN,
RTLT_DASH_COMMAND_INVALID,
};
struct rtl_dash_ip_mac {
struct sockaddr ifru_addr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
};
struct rtl_dash_ioctl_struct {
__u32 cmd;
__u32 offset;
__u32 len;
union {
__u32 data;
void *data_buffer;
};
};
typedef struct _OSOOBHdr {
__le32 len;
u8 type;
u8 flag;
u8 hostReqV;
u8 res;
}
OSOOBHdr, *POSOOBHdr;
typedef struct _RX_DASH_BUFFER_TYPE_2 {
OSOOBHdr oobhdr;
u8 RxDataBuffer[0];
}
RX_DASH_BUFFER_TYPE_2, *PRX_DASH_BUFFER_TYPE_2;
#define ALIGN_8 (0x7)
#define ALIGN_16 (0xf)
#define ALIGN_32 (0x1f)
#define ALIGN_64 (0x3f)
#define ALIGN_256 (0xff)
#define ALIGN_4096 (0xfff)
#define OCP_REG_FIRMWARE_MAJOR_VERSION (0x120)
#define HW_DASH_SUPPORT_DASH(_M) ((_M)->HwSuppDashVer > 0)
#define HW_DASH_SUPPORT_TYPE_1(_M) ((_M)->HwSuppDashVer == 1)
#define HW_DASH_SUPPORT_TYPE_2(_M) ((_M)->HwSuppDashVer == 2)
#define HW_DASH_SUPPORT_TYPE_3(_M) ((_M)->HwSuppDashVer == 3)
#define HW_DASH_SUPPORT_TYPE_4(_M) ((_M)->HwSuppDashVer == 4)
#define HW_DASH_SUPPORT_CMAC(_M) (HW_DASH_SUPPORT_TYPE_2(_M) || HW_DASH_SUPPORT_TYPE_3(_M))
#define HW_DASH_SUPPORT_IPC2(_M) (HW_DASH_SUPPORT_TYPE_4(_M))
#define HW_DASH_SUPPORT_GET_FIRMWARE_VERSION(_M) (HW_DASH_SUPPORT_TYPE_2(_M) || \
HW_DASH_SUPPORT_TYPE_3(_M) || \
HW_DASH_SUPPORT_TYPE_4(_M))
#define RECV_FROM_FW_BUF_SIZE (1520)
#define SEND_TO_FW_BUF_SIZE (1520)
#define TXS_CC3_0 (BIT_0|BIT_1|BIT_2|BIT_3)
#define TXS_EXC BIT_4
#define TXS_LNKF BIT_5
#define TXS_OWC BIT_6
#define TXS_TES BIT_7
#define TXS_UNF BIT_9
#define TXS_LGSEN BIT_11
#define TXS_LS BIT_12
#define TXS_FS BIT_13
#define TXS_EOR BIT_14
#define TXS_OWN BIT_15
#define TPPool_HRDY 0x20
#define RXS_OWN BIT_15
#define RXS_EOR BIT_14
#define RXS_FS BIT_13
#define RXS_LS BIT_12
#define ISRIMR_DASH_INTR_EN BIT_12
#define NO_BASE_ADDRESS 0x00000000
/* IB2SOC registers */
#define IPC2_SWISR_DRIVER_READY 0x05
#define IPC2_SWISR_DRIVER_EXIT 0x06
#define IPC2_SWISR_CLIENTTOOL_SYNC_HOSTNAME 0x20
#define IPC2_SWISR_DIS_DASH 0x55
#define IPC2_SWISR_EN_DASH 0x56
#define IPC2_IB2SOC_SET 0x10
#define IPC2_IB2SOC_DATA 0x14
#define IPC2_IB2SOC_CMD 0x18
#define IPC2_IB2SOC_IMR 0x1C
/* IPC2 registers */
#define IPC2_PCIE_BASE 0xC100
#define IPC2_TX_SET_REG IPC2_PCIE_BASE
#define IPC2_TX_STATUS_REG (IPC2_PCIE_BASE+0x04)
#define IPC2_RX_STATUS_REG (IPC2_PCIE_BASE+0x08)
#define IPC2_RX_CLEAR_REG (IPC2_PCIE_BASE+0x0C)
#define IPC2_DATA_BASE 0x32000
#define IPC2_BUFFER_LENGTH 0x1000
#define IPC2_DATA_MASTER IPC2_DATA_BASE //dash tx buffer base
#define IPC2_DATA_SLAVE (IPC2_DATA_BASE+IPC2_BUFFER_LENGTH) //dash rx buffer base
#define IPC2_TX_BUFFER IPC2_DATA_MASTER
#define IPC2_RX_BUFFER IPC2_DATA_SLAVE
#define IPC2_TX_SEND_BIT BIT_0
#define IPC2_TX_ACK_BIT BIT_8
#define IPC2_RX_ROK_BIT BIT_0
#define IPC2_RX_ACK_BIT BIT_8
/* IPC2 write/read MMIO register */
#define RTL_DASH_IPC2_W8(tp, reg, val8) RTL_W8(tp, reg, val8)
#define RTL_DASH_IPC2_W16(tp, reg, val16) RTL_W16(tp, reg, val16)
#define RTL_DASH_IPC2_W32(tp, reg, val32) RTL_W32(tp, reg, val32)
#define RTL_DASH_IPC2_R8(tp, reg) RTL_R8(tp, reg)
#define RTL_DASH_IPC2_R16(tp, reg) RTL_R16(tp, reg)
#define RTL_DASH_IPC2_R32(tp, reg) RTL_R32(tp, reg)
/* DASH OOB Header Type */
#define DASH_OOB_HDR_TYPE_REQ 0x91
#define DASH_OOB_HDR_TYPE_ACK 0x92
struct rtl8125_private;
int rtl8125_dash_ioctl(struct net_device *dev, struct ifreq *ifr);
bool rtl8125_check_dash_interrupt(struct rtl8125_private *tp);
void rtl8125_handle_dash_interrupt(struct net_device *dev);
void rtl8125_clear_ipc2_isr(struct rtl8125_private *tp);
void rtl8125_set_ipc2_soc_imr_bit(struct rtl8125_private *tp, u16 mask);
void rtl8125_clear_ipc2_soc_imr_bit(struct rtl8125_private *tp, u16 mask);
#endif /* _LINUX_R8125_DASH_H */

View File

@ -0,0 +1,464 @@
/*
################################################################################
#
# r8125 is the Linux device driver released for Realtek 2.5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2025 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include "r8125.h"
#include "r8125_fiber.h"
static void
rtl8125_fiber_set_mdc_gpio_c45(struct rtl8125_private *tp, bool pu)
{
if (pu)
rtl8125_set_mac_ocp_bit(tp, 0xDC52, BIT_7);
else
rtl8125_clear_mac_ocp_bit(tp, 0xDC52, BIT_7);
//RtPciCommittp);
}
static void
rtl8125_fiber_set_mdc(struct rtl8125_private *tp, bool pu)
{
rtl8125_fiber_set_mdc_gpio_c45(tp, pu);
}
static void
rtl8125_fiber_set_mdcDownUp(struct rtl8125_private *tp)
{
udelay(1);
rtl8125_fiber_set_mdc(tp, 0);
udelay(1);
rtl8125_fiber_set_mdc(tp, 1);
}
static void
rtl8125_fiber_set_mdio_bit_gpio_c45(struct rtl8125_private *tp, bool pu)
{
if (pu)
rtl8125_set_mac_ocp_bit(tp, 0xDC52, BIT_2);
else
rtl8125_clear_mac_ocp_bit(tp, 0xDC52, BIT_2);
//RtPciCommittp);
rtl8125_fiber_set_mdcDownUp(tp);
}
static void
rtl8125_fiber_set_mdio_bit(struct rtl8125_private *tp, bool pu)
{
rtl8125_fiber_set_mdio_bit_gpio_c45(tp, pu);
}
static u16
rtl8125_fiber_get_mdio_bit_gpio_c45(struct rtl8125_private *tp)
{
rtl8125_fiber_set_mdcDownUp(tp);
return !!(rtl8125_mac_ocp_read(tp, 0xDC58) & BIT(2));
}
static u16
rtl8125_fiber_get_mdio_bit(struct rtl8125_private *tp)
{
return rtl8125_fiber_get_mdio_bit_gpio_c45(tp);
}
static void
rtl8125_fiber_shift_bit_in(struct rtl8125_private *tp, u32 val, int count)
{
int i;
for (i = (count - 1); i >= 0; i--)
rtl8125_fiber_set_mdio_bit(tp, !!(val & BIT(i)));
}
static u16
rtl8125_fiber_shift_bit_out(struct rtl8125_private *tp)
{
u16 data = 0;
int i;
for (i = 15; i >= 0; i--)
data += (rtl8125_fiber_get_mdio_bit(tp) << i);
return data;
}
static void
rtl8125_fiber_dir_gpio_c45(struct rtl8125_private *tp, bool output_mode)
{
if (output_mode)
rtl8125_set_mac_ocp_bit(tp, 0xDC4C, BIT_2);
else
rtl8125_clear_mac_ocp_bit(tp, 0xDC4C, BIT_2);
}
static void
rtl8125_fiber_dir(struct rtl8125_private *tp, bool output_mode)
{
rtl8125_fiber_dir_gpio_c45(tp, output_mode);
}
//fiber
#define R8125_FIBER_C22 (0)
#define R8125_FIBER_C45 (1)
// sfp opcodes
#define R8125_FIBER_ST (1)
#define R8125_FIBER_OP_W (1)
#define R8125_FIBER_OP_R (2)
#define R8125_FIBER_TA (2)
// sfp C45 opcodes
#define R8125_FIBER_MDIO_C45 (BIT(15))
#define R8125_FIBER_C45_ST (R8125_FIBER_MDIO_C45 | 0)
#define R8125_FIBER_C45_OP_ADDR (R8125_FIBER_MDIO_C45 | 0)
#define R8125_FIBER_C45_OP_W (R8125_FIBER_MDIO_C45 | 1)
#define R8125_FIBER_C45_OP_R (R8125_FIBER_MDIO_C45 | 3)
static void
rtl8125_fiber_cmd(struct rtl8125_private *tp, u32 cmd, u8 phy_addr,
u32 reg)
{
/* change to output mode */
rtl8125_fiber_dir(tp, 1);
/* preamble 32bit of 1 */
rtl8125_fiber_shift_bit_in(tp, UINT_MAX, 32);
/* start bit */
if (cmd & R8125_FIBER_MDIO_C45)
rtl8125_fiber_shift_bit_in(tp, R8125_FIBER_C45_ST, 2);
else
rtl8125_fiber_shift_bit_in(tp, R8125_FIBER_ST, 2);
/* opcode */
rtl8125_fiber_shift_bit_in(tp, cmd, 2);
/* phy address */
rtl8125_fiber_shift_bit_in(tp, phy_addr, 5);
/* phy reg */
rtl8125_fiber_shift_bit_in(tp, reg, 5);
}
static u8
rtl8125_fiber_cmdAddr(struct rtl8125_private *tp, u8 phy_addr, u32 reg)
{
u8 dev_addr = (reg >> 16) & 0x1F;
u16 addr = (u16)reg;
rtl8125_fiber_cmd(tp, R8125_FIBER_C45_OP_ADDR, phy_addr, dev_addr);
/* turn-around(TA) */
rtl8125_fiber_shift_bit_in(tp, R8125_FIBER_TA, 2);
rtl8125_fiber_shift_bit_in(tp, addr, 16);
rtl8125_fiber_dir(tp, 0);
rtl8125_fiber_get_mdio_bit(tp);
return dev_addr;
}
static void
rtl8125_fiber_reset_gpio_c45(struct rtl8125_private *tp)
{
rtl8125_set_mac_ocp_bit(tp, 0xDC4C, (BIT_7 | BIT_2));
/* init sfp interface */
rtl8125_clear_mac_ocp_bit(tp, 0xDC52, BIT_7);
rtl8125_set_mac_ocp_bit(tp, 0xDC52, BIT_2);
}
static void
rtl8125_fiber_write_common(struct rtl8125_private *tp, u16 val)
{
/* turn-around(TA) */
rtl8125_fiber_shift_bit_in(tp, R8125_FIBER_TA, 2);
/* write phy data */
rtl8125_fiber_shift_bit_in(tp, val, 16);
/* change to input mode */
rtl8125_fiber_dir(tp, 0);
rtl8125_fiber_get_mdio_bit(tp);
}
static void
rtl8125_fiber_mdio_write_gpio_c45(
struct rtl8125_private *tp,
u32 reg,
u16 val,
u8 phy_addr)
{
/* opcode write */
reg = rtl8125_fiber_cmdAddr(tp, phy_addr, reg);
rtl8125_fiber_cmd(tp, R8125_FIBER_C45_OP_W, phy_addr, reg);
rtl8125_fiber_write_common(tp, val);
}
static u16
rtl8125_fiber_read_common(struct rtl8125_private *tp)
{
u16 data = 0;
/* change to input mode */
rtl8125_fiber_dir(tp, 0);
/* TA 0 */
rtl8125_fiber_get_mdio_bit(tp);
/* read phy data */
data = rtl8125_fiber_shift_bit_out(tp);
rtl8125_fiber_get_mdio_bit(tp);
return data;
}
static u16
rtl8125_fiber_mdio_read_gpio_c45(
struct rtl8125_private *tp,
u32 reg,
u8 phy_addr)
{
reg = rtl8125_fiber_cmdAddr(tp, phy_addr, reg);
rtl8125_fiber_cmd(tp, R8125_FIBER_C45_OP_R, phy_addr, reg);
return rtl8125_fiber_read_common(tp);
}
void
rtl8125_fiber_mdio_write(
struct rtl8125_private *tp,
u32 reg,
u16 val)
{
switch(tp->HwFiberStat) {
case FIBER_STAT_CONNECT_GPO_C45:
return rtl8125_fiber_mdio_write_gpio_c45(tp, reg, val, 0);
default:
return;
}
}
u16
rtl8125_fiber_mdio_read(
struct rtl8125_private *tp,
u32 reg)
{
switch(tp->HwFiberStat) {
case FIBER_STAT_CONNECT_GPO_C45:
return rtl8125_fiber_mdio_read_gpio_c45(tp, reg, 0);
default:
return 0xffff;
}
}
static void
rtl8125_fiber_clear_and_set_phy_bit(struct rtl8125_private *tp, u32 addr, u16 clearmask, u16 setmask)
{
u16 PhyRegValue;
PhyRegValue = rtl8125_fiber_mdio_read(tp, addr);
PhyRegValue &= ~clearmask;
PhyRegValue |= setmask;
rtl8125_fiber_mdio_write(tp, addr, PhyRegValue);
}
static void
rtl8125_fiber_clear_phy_bit(struct rtl8125_private *tp, u32 addr, u16 mask)
{
rtl8125_fiber_clear_and_set_phy_bit(tp, addr, mask, 0);
}
static void
rtl8125_fiber_set_phy_bit(struct rtl8125_private *tp, u32 addr, u16 mask)
{
rtl8125_fiber_clear_and_set_phy_bit(tp, addr, 0, mask);
}
#define R8125_MAKE_C45_ADDR(_mmd, _addr) (_mmd << 16 | _addr)
static void
rtl8125_fiber_phy_reset_8221d(struct rtl8125_private *tp)
{
u16 PhyRegValue;
u32 Timeout;
rtl8125_fiber_set_phy_bit(tp, R8125_MAKE_C45_ADDR(0x01, 0x00), BIT_15);
Timeout = 0;
do {
udelay(1000);
PhyRegValue = rtl8125_fiber_mdio_read(tp, R8125_MAKE_C45_ADDR(0x01, 0x00));
Timeout++;
} while ((PhyRegValue & BIT_15) && (Timeout < 20));
}
static void
rtl8125_fiber_phy_reset(struct rtl8125_private *tp)
{
switch (tp->HwFiberModeVer) {
case FIBER_MODE_RTL8125D_RTL8221D:
rtl8125_fiber_phy_reset_8221d(tp);
break;
}
}
static void
rtl8125_fiber_set_rtl8221d_phy_mode(struct rtl8125_private *tp, u16 mode)
{
mode &= 0x3f;
rtl8125_fiber_clear_phy_bit(tp, R8125_MAKE_C45_ADDR(30, 0x75F3), BIT_0);
rtl8125_fiber_clear_and_set_phy_bit(tp,
R8125_MAKE_C45_ADDR(30, 0x697A),
0x003F,
mode);
}
static void
rtl8125_fiber_set_phy_mode(struct rtl8125_private *tp, u16 mode)
{
switch (tp->HwFiberModeVer) {
case FIBER_MODE_RTL8125D_RTL8221D:
rtl8125_fiber_set_rtl8221d_phy_mode(tp, mode);
break;
default:
break;
}
}
static void
rtl8125_hw_rtl8221d_phy_config(struct rtl8125_private *tp)
{
rtl8125_fiber_reset_gpio_c45(tp);
rtl8125_fiber_set_phy_mode(tp, (tp->speed == SPEED_2500) ? 0x02 : 0x04);
rtl8125_fiber_clear_phy_bit(tp, R8125_MAKE_C45_ADDR(0x07, 0x3C), (BIT_2 | BIT_1));
rtl8125_fiber_clear_phy_bit(tp, R8125_MAKE_C45_ADDR(0x07, 0x3E), (BIT_1 | BIT_0));
rtl8125_fiber_phy_reset(tp);
}
void
rtl8125_hw_fiber_phy_config(struct rtl8125_private *tp)
{
switch (tp->HwFiberModeVer) {
case FIBER_MODE_RTL8125D_RTL8221D:
rtl8125_hw_rtl8221d_phy_config(tp);
break;
default:
break;
}
}
#define RTL8221D_PHY_ID_1 0x001C
#define RTL8221D_PHY_ID_2 0xC849
static u32
rtl8125_fiber_get_connect_status_8221d(struct rtl8125_private *tp)
{
int i;
int const checkcnt = 4;
rtl8125_fiber_reset_gpio_c45(tp);
for (i = 0; i < checkcnt; i++) {
if (RTL8221D_PHY_ID_1 != rtl8125_fiber_mdio_read_gpio_c45(tp, R8125_MAKE_C45_ADDR(0x01, 0x02), 0) ||
RTL8221D_PHY_ID_2 != rtl8125_fiber_mdio_read_gpio_c45(tp, R8125_MAKE_C45_ADDR(0x01, 0x03), 0))
return FIBER_STAT_DISCONNECT;
}
return FIBER_STAT_CONNECT_GPO_C45;
}
static u32
rtl8125_fiber_get_connect_status(struct rtl8125_private *tp)
{
switch (tp->HwFiberModeVer) {
case FIBER_MODE_RTL8125D_RTL8221D:
return rtl8125_fiber_get_connect_status_8221d(tp);
default:
return FIBER_STAT_NOT_CHECKED;
}
}
void
rtl8125_check_fiber_mode_support(struct rtl8125_private *tp)
{
switch(tp->mcfg) {
case CFG_METHOD_10:
case CFG_METHOD_11: {
u8 tmp = (u8)rtl8125_mac_ocp_read(tp, 0xD006);
if (tmp == 0x03)
tp->HwFiberModeVer = FIBER_MODE_RTL8125D_RTL8221D;
}
break;
}
if (HW_FIBER_MODE_ENABLED(tp))
tp->HwFiberStat = rtl8125_fiber_get_connect_status(tp);
}
unsigned int
rtl8125_fiber_link_ok(struct net_device *dev)
{
struct rtl8125_private *tp = netdev_priv(dev);
u16 status;
switch (tp->HwFiberStat) {
case FIBER_STAT_CONNECT_GPO_C45:
status = rtl8125_fiber_mdio_read(tp, R8125_MAKE_C45_ADDR(30, 0x758D));
if (status != USHRT_MAX && status & BIT_1)
return 1;
else
return 0;
break;
default:
return 0;
}
}

View File

@ -0,0 +1,63 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8125 is the Linux device driver released for Realtek 2.5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2025 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_R8125_FIBER_H
#define _LINUX_R8125_FIBER_H
enum {
FIBER_MODE_NIC_ONLY = 0,
FIBER_MODE_RTL8125D_RTL8221D,
FIBER_MODE_MAX
};
enum {
FIBER_STAT_NOT_CHECKED = 0,
FIBER_STAT_DISCONNECT,
FIBER_STAT_CONNECT_GPO_C45,
FIBER_STAT_MAX
};
#define HW_FIBER_MODE_ENABLED(_M) ((_M)->HwFiberModeVer > 0)
#define HW_FIBER_STATUS_CONNECTED(_M) (((_M)->HwFiberStat == FIBER_STAT_CONNECT_GPO_C45))
#define HW_FIBER_STATUS_DISCONNECTED(_M) ((_M)->HwFiberStat == FIBER_STAT_DISCONNECT)
struct rtl8125_private;
void rtl8125_hw_fiber_phy_config(struct rtl8125_private *tp);
void rtl8125_check_fiber_mode_support(struct rtl8125_private *tp);
void rtl8125_fiber_mdio_write( struct rtl8125_private *tp, u32 reg, u16 val);
u16 rtl8125_fiber_mdio_read(struct rtl8125_private *tp, u32 reg);
unsigned int rtl8125_fiber_link_ok(struct net_device *dev);
#endif /* _LINUX_R8125_FIBER_H */

View File

@ -0,0 +1,264 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
################################################################################
#
# r8125 is the Linux device driver released for Realtek 2.5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2025 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/version.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include "r8125_firmware.h"
enum rtl_fw_opcode {
PHY_READ = 0x0,
PHY_DATA_OR = 0x1,
PHY_DATA_AND = 0x2,
PHY_BJMPN = 0x3,
PHY_MDIO_CHG = 0x4,
PHY_CLEAR_READCOUNT = 0x7,
PHY_WRITE = 0x8,
PHY_READCOUNT_EQ_SKIP = 0x9,
PHY_COMP_EQ_SKIPN = 0xa,
PHY_COMP_NEQ_SKIPN = 0xb,
PHY_WRITE_PREVIOUS = 0xc,
PHY_SKIPN = 0xd,
PHY_DELAY_MS = 0xe,
};
struct fw_info {
u32 magic;
char version[RTL8125_VER_SIZE];
__le32 fw_start;
__le32 fw_len;
u8 chksum;
} __packed;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,16,0)
#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
#endif
#define FW_OPCODE_SIZE sizeof_field(struct rtl8125_fw_phy_action, code[0])
static bool rtl8125_fw_format_ok(struct rtl8125_fw *rtl_fw)
{
const struct firmware *fw = rtl_fw->fw;
struct fw_info *fw_info = (struct fw_info *)fw->data;
struct rtl8125_fw_phy_action *pa = &rtl_fw->phy_action;
if (fw->size < FW_OPCODE_SIZE)
return false;
if (!fw_info->magic) {
size_t i, size, start;
u8 checksum = 0;
if (fw->size < sizeof(*fw_info))
return false;
for (i = 0; i < fw->size; i++)
checksum += fw->data[i];
if (checksum != 0)
return false;
start = le32_to_cpu(fw_info->fw_start);
if (start > fw->size)
return false;
size = le32_to_cpu(fw_info->fw_len);
if (size > (fw->size - start) / FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, fw_info->version, RTL8125_VER_SIZE);
pa->code = (__le32 *)(fw->data + start);
pa->size = size;
} else {
if (fw->size % FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, rtl_fw->fw_name, RTL8125_VER_SIZE);
pa->code = (__le32 *)fw->data;
pa->size = fw->size / FW_OPCODE_SIZE;
}
return true;
}
static bool rtl8125_fw_data_ok(struct rtl8125_fw *rtl_fw)
{
struct rtl8125_fw_phy_action *pa = &rtl_fw->phy_action;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 val = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
switch (action >> 28) {
case PHY_READ:
case PHY_DATA_OR:
case PHY_DATA_AND:
case PHY_CLEAR_READCOUNT:
case PHY_WRITE:
case PHY_WRITE_PREVIOUS:
case PHY_DELAY_MS:
break;
case PHY_MDIO_CHG:
if (val > 1)
goto out;
break;
case PHY_BJMPN:
if (regno > index)
goto out;
break;
case PHY_READCOUNT_EQ_SKIP:
if (index + 2 >= pa->size)
goto out;
break;
case PHY_COMP_EQ_SKIPN:
case PHY_COMP_NEQ_SKIPN:
case PHY_SKIPN:
if (index + 1 + regno >= pa->size)
goto out;
break;
default:
dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
return false;
}
}
return true;
out:
dev_err(rtl_fw->dev, "Out of range of firmware\n");
return false;
}
void rtl8125_fw_write_firmware(struct rtl8125_private *tp, struct rtl8125_fw *rtl_fw)
{
struct rtl8125_fw_phy_action *pa = &rtl_fw->phy_action;
rtl8125_fw_write_t fw_write = rtl_fw->phy_write;
rtl8125_fw_read_t fw_read = rtl_fw->phy_read;
int predata = 0, count = 0;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 data = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
enum rtl_fw_opcode opcode = action >> 28;
if (!action)
break;
switch (opcode) {
case PHY_READ:
predata = fw_read(tp, regno);
count++;
break;
case PHY_DATA_OR:
predata |= data;
break;
case PHY_DATA_AND:
predata &= data;
break;
case PHY_BJMPN:
index -= (regno + 1);
break;
case PHY_MDIO_CHG:
if (data) {
fw_write = rtl_fw->mac_mcu_write;
fw_read = rtl_fw->mac_mcu_read;
} else {
fw_write = rtl_fw->phy_write;
fw_read = rtl_fw->phy_read;
}
break;
case PHY_CLEAR_READCOUNT:
count = 0;
break;
case PHY_WRITE:
fw_write(tp, regno, data);
break;
case PHY_READCOUNT_EQ_SKIP:
if (count == data)
index++;
break;
case PHY_COMP_EQ_SKIPN:
if (predata == data)
index += regno;
break;
case PHY_COMP_NEQ_SKIPN:
if (predata != data)
index += regno;
break;
case PHY_WRITE_PREVIOUS:
fw_write(tp, regno, predata);
break;
case PHY_SKIPN:
index += regno;
break;
case PHY_DELAY_MS:
mdelay(1 * data);
break;
}
}
}
void rtl8125_fw_release_firmware(struct rtl8125_fw *rtl_fw)
{
release_firmware(rtl_fw->fw);
}
int rtl8125_fw_request_firmware(struct rtl8125_fw *rtl_fw)
{
int rc;
rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
if (rc < 0)
goto out;
if (!rtl8125_fw_format_ok(rtl_fw) || !rtl8125_fw_data_ok(rtl_fw)) {
release_firmware(rtl_fw->fw);
rc = -EINVAL;
goto out;
}
return 0;
out:
dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
rtl_fw->fw_name, rc);
return rc;
}

View File

@ -0,0 +1,68 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8125 is the Linux device driver released for Realtek 2.5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2025 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_rtl8125_FIRMWARE_H
#define _LINUX_rtl8125_FIRMWARE_H
#include <linux/device.h>
#include <linux/firmware.h>
struct rtl8125_private;
typedef void (*rtl8125_fw_write_t)(struct rtl8125_private *tp, u16 reg, u16 val);
typedef u32 (*rtl8125_fw_read_t)(struct rtl8125_private *tp, u16 reg);
#define RTL8125_VER_SIZE 32
struct rtl8125_fw {
rtl8125_fw_write_t phy_write;
rtl8125_fw_read_t phy_read;
rtl8125_fw_write_t mac_mcu_write;
rtl8125_fw_read_t mac_mcu_read;
const struct firmware *fw;
const char *fw_name;
struct device *dev;
char version[RTL8125_VER_SIZE];
struct rtl8125_fw_phy_action {
__le32 *code;
size_t size;
} phy_action;
};
int rtl8125_fw_request_firmware(struct rtl8125_fw *rtl_fw);
void rtl8125_fw_release_firmware(struct rtl8125_fw *rtl_fw);
void rtl8125_fw_write_firmware(struct rtl8125_private *tp, struct rtl8125_fw *rtl_fw);
#endif /* _LINUX_rtl8125_FIRMWARE_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,159 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8125 is the Linux device driver released for Realtek 2.5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2025 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_rtl8125_PTP_H
#define _LINUX_rtl8125_PTP_H
#include <linux/ktime.h>
#include <linux/timecounter.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/ptp_classify.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,11,0)
#define PTP_MSGTYPE_SYNC 0x0
#define PTP_MSGTYPE_DELAY_REQ 0x1
#define PTP_MSGTYPE_PDELAY_REQ 0x2
#define PTP_MSGTYPE_PDELAY_RESP 0x3
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,11,0) */
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0)
struct clock_identity {
u8 id[8];
} __packed;
struct port_identity {
struct clock_identity clock_identity;
__be16 port_number;
} __packed;
struct ptp_header {
u8 tsmt; /* transportSpecific | messageType */
u8 ver; /* reserved | versionPTP */
__be16 message_length;
u8 domain_number;
u8 reserved1;
u8 flag_field[2];
__be64 correction;
__be32 reserved2;
struct port_identity source_port_identity;
__be16 sequence_id;
u8 control;
u8 log_message_interval;
} __packed;
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) */
struct rtl8125_ptp_info {
s64 time_sec;
u32 time_ns;
u16 ts_info;
};
#ifndef _STRUCT_TIMESPEC
#define _STRUCT_TIMESPEC
struct timespec {
__kernel_old_time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
#endif
enum PTP_CMD_TYPE {
PTP_CMD_SET_LOCAL_TIME = 0,
PTP_CMD_DRIFT_LOCAL_TIME,
PTP_CMD_LATCHED_LOCAL_TIME,
};
#define PTP_CLKADJ_MODE_SET BIT_0
enum PTP_CLKADJ_MOD_TYPE {
NO_FUNCTION = 0,
CLKADJ_MODE_SET = 1,
RESERVED = 2,
DIRECT_READ = 4,
DIRECT_WRITE = 6,
INCREMENT_STEP = 8,
DECREMENT_STEP = 10,
RATE_READ = 12,
RATE_WRITE = 14,
};
enum PTP_INSR_TYPE {
EVENT_CAP_INTR = (1 << 0),
TRIG_GEN_INTR = (1 << 1),
RX_TS_INTR = (1 << 2),
TX_TX_INTR = (1 << 3),
};
enum PTP_TRX_TS_STA_REG {
TRX_TS_RD = (1 << 0),
TRXTS_SEL = (1 << 1),
RX_TS_PDLYRSP_RDY = (1 << 8),
RX_TS_PDLYREQ_RDY = (1 << 9),
RX_TS_DLYREQ_RDY = (1 << 10),
RX_TS_SYNC_RDY = (1 << 11),
TX_TS_PDLYRSP_RDY = (1 << 12),
TX_TS_PDLYREQ_RDY = (1 << 13),
TX_TS_DLYREQ_RDY = (1 << 14),
TX_TS_SYNC_RDY = (1 << 15),
};
#define RTL_FLAG_RX_HWTSTAMP_ENABLED BIT_0
struct rtl8125_private;
struct RxDescV3;
#if LINUX_VERSION_CODE < KERNEL_VERSION(6,11,0)
int rtl8125_get_ts_info(struct net_device *netdev,
struct ethtool_ts_info *info);
#else
int rtl8125_get_ts_info(struct net_device *netdev,
struct kernel_ethtool_ts_info *info);
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(6,11,0) */
void rtl8125_ptp_reset(struct rtl8125_private *tp);
void rtl8125_ptp_init(struct rtl8125_private *tp);
void rtl8125_ptp_suspend(struct rtl8125_private *tp);
void rtl8125_ptp_stop(struct rtl8125_private *tp);
int rtl8125_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
void rtl8125_rx_mac_ptp_pktstamp(struct rtl8125_private *tp, struct sk_buff *skb,
struct RxDescV3 *descv3);
void rtl8125_set_phy_local_time(struct rtl8125_private *tp);
void rtl8125_rx_phy_ptp_timestamp(struct rtl8125_private *tp, struct sk_buff *skb);
#endif /* _LINUX_rtl8125_PTP_H */

View File

@ -0,0 +1,118 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8125 is the Linux device driver released for Realtek 2.5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2025 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_R8125_REALWOW_H
#define _LINUX_R8125_REALWOW_H
#define SIOCDEVPRIVATE_RTLREALWOW SIOCDEVPRIVATE+3
#define MAX_RealWoW_KCP_SIZE (100)
#define MAX_RealWoW_Payload (64)
#define KA_TX_PACKET_SIZE (100)
#define KA_WAKEUP_PATTERN_SIZE (120)
//HwSuppKeepAliveOffloadVer
#define HW_SUPPORT_KCP_OFFLOAD(_M) ((_M)->HwSuppKCPOffloadVer > 0)
enum rtl_realwow_cmd {
RTL_REALWOW_SET_KCP_DISABLE=0,
RTL_REALWOW_SET_KCP_INFO,
RTL_REALWOW_SET_KCP_CONTENT,
RTL_REALWOW_SET_KCP_ACKPKTINFO,
RTL_REALWOW_SET_KCP_WPINFO,
RTL_REALWOW_SET_KCPDHCP_TIMEOUT,
RTLT_REALWOW_COMMAND_INVALID
};
struct rtl_realwow_ioctl_struct {
__u32 cmd;
__u32 offset;
__u32 len;
union {
__u32 data;
void *data_buffer;
};
};
typedef struct _MP_KCPInfo {
u8 DIPv4[4];
u8 MacID[6];
u16 UdpPort[2];
u8 PKTLEN[2];
u16 ackLostCnt;
u8 KCP_WakePattern[MAX_RealWoW_Payload];
u8 KCP_AckPacket[MAX_RealWoW_Payload];
u32 KCP_interval;
u8 KCP_WakePattern_Len;
u8 KCP_AckPacket_Len;
u8 KCP_TxPacket[2][KA_TX_PACKET_SIZE];
} MP_KCP_INFO, *PMP_KCP_INFO;
typedef struct _KCPInfo {
u32 nId; // = id
u8 DIPv4[4];
u8 MacID[6];
u16 UdpPort;
u16 PKTLEN;
} KCPInfo, *PKCPInfo;
typedef struct _KCPContent {
u32 id; // = id
u32 mSec; // = msec
u32 size; // =size
u8 bPacket[MAX_RealWoW_KCP_SIZE]; // put packet here
} KCPContent, *PKCPContent;
typedef struct _RealWoWAckPktInfo {
u16 ackLostCnt;
u16 patterntSize;
u8 pattern[MAX_RealWoW_Payload];
} RealWoWAckPktInfo,*PRealWoWAckPktInfo;
typedef struct _RealWoWWPInfo {
u16 patterntSize;
u8 pattern[MAX_RealWoW_Payload];
} RealWoWWPInfo,*PRealWoWWPInfo;
int rtl8125_realwow_ioctl(struct net_device *dev, struct ifreq *ifr);
void rtl8125_realwow_hw_init(struct net_device *dev);
void rtl8125_get_realwow_hw_version(struct net_device *dev);
void rtl8125_set_realwow_d3_para(struct net_device *dev);
#endif /* _LINUX_R8125_REALWOW_H */

View File

@ -0,0 +1,583 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
################################################################################
#
# r8125 is the Linux device driver released for Realtek 2.5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2025 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/version.h>
#include "r8125.h"
enum rtl8125_rss_register_content {
/* RSS */
RSS_CTRL_TCP_IPV4_SUPP = (1 << 0),
RSS_CTRL_IPV4_SUPP = (1 << 1),
RSS_CTRL_TCP_IPV6_SUPP = (1 << 2),
RSS_CTRL_IPV6_SUPP = (1 << 3),
RSS_CTRL_IPV6_EXT_SUPP = (1 << 4),
RSS_CTRL_TCP_IPV6_EXT_SUPP = (1 << 5),
RSS_HALF_SUPP = (1 << 7),
RSS_CTRL_UDP_IPV4_SUPP = (1 << 11),
RSS_CTRL_UDP_IPV6_SUPP = (1 << 12),
RSS_CTRL_UDP_IPV6_EXT_SUPP = (1 << 13),
RSS_QUAD_CPU_EN = (1 << 16),
RSS_HQ_Q_SUP_R = (1 << 31),
};
static int rtl8125_get_rss_hash_opts(struct rtl8125_private *tp,
struct ethtool_rxnfc *cmd)
{
cmd->data = 0;
/* Report default options for RSS */
switch (cmd->flow_type) {
case TCP_V4_FLOW:
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough;
case UDP_V4_FLOW:
if (tp->rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV4)
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough;
case IPV4_FLOW:
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
break;
case TCP_V6_FLOW:
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough;
case UDP_V6_FLOW:
if (tp->rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV6)
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough;
case IPV6_FLOW:
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
break;
default:
return -EINVAL;
}
return 0;
}
int rtl8125_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
u32 *rule_locs)
{
struct rtl8125_private *tp = netdev_priv(dev);
int ret = -EOPNOTSUPP;
if (!(dev->features & NETIF_F_RXHASH))
return ret;
switch (cmd->cmd) {
case ETHTOOL_GRXRINGS:
cmd->data = rtl8125_tot_rx_rings(tp);
ret = 0;
break;
case ETHTOOL_GRXFH:
ret = rtl8125_get_rss_hash_opts(tp, cmd);
break;
default:
break;
}
return ret;
}
u32 rtl8125_rss_indir_tbl_entries(struct rtl8125_private *tp)
{
return tp->HwSuppIndirTblEntries;
}
#define RSS_MASK_BITS_OFFSET (8)
#define RSS_CPU_NUM_OFFSET (16)
#define RTL8125_UDP_RSS_FLAGS (RTL_8125_RSS_FLAG_HASH_UDP_IPV4 | \
RTL_8125_RSS_FLAG_HASH_UDP_IPV6)
static int _rtl8125_set_rss_hash_opt(struct rtl8125_private *tp)
{
u32 rss_flags = tp->rss_flags;
u32 hash_mask_len;
u32 rss_ctrl;
rss_ctrl = ilog2(rtl8125_tot_rx_rings(tp));
rss_ctrl &= (BIT_0 | BIT_1 | BIT_2);
rss_ctrl <<= RSS_CPU_NUM_OFFSET;
/* Perform hash on these packet types */
rss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP
| RSS_CTRL_IPV4_SUPP
| RSS_CTRL_IPV6_SUPP
| RSS_CTRL_IPV6_EXT_SUPP
| RSS_CTRL_TCP_IPV6_SUPP
| RSS_CTRL_TCP_IPV6_EXT_SUPP;
if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV4)
rss_ctrl |= RSS_CTRL_UDP_IPV4_SUPP;
if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV6)
rss_ctrl |= RSS_CTRL_UDP_IPV6_SUPP |
RSS_CTRL_UDP_IPV6_EXT_SUPP;
hash_mask_len = ilog2(rtl8125_rss_indir_tbl_entries(tp));
hash_mask_len &= (BIT_0 | BIT_1 | BIT_2);
rss_ctrl |= hash_mask_len << RSS_MASK_BITS_OFFSET;
RTL_W32(tp, RSS_CTRL_8125, rss_ctrl);
return 0;
}
static int rtl8125_set_rss_hash_opt(struct rtl8125_private *tp,
struct ethtool_rxnfc *nfc)
{
u32 rss_flags = tp->rss_flags;
/*
* RSS does not support anything other than hashing
* to queues on src and dst IPs and ports
*/
if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3))
return -EINVAL;
switch (nfc->flow_type) {
case TCP_V4_FLOW:
case TCP_V6_FLOW:
if (!(nfc->data & RXH_IP_SRC) ||
!(nfc->data & RXH_IP_DST) ||
!(nfc->data & RXH_L4_B_0_1) ||
!(nfc->data & RXH_L4_B_2_3))
return -EINVAL;
break;
case UDP_V4_FLOW:
if (!(nfc->data & RXH_IP_SRC) ||
!(nfc->data & RXH_IP_DST))
return -EINVAL;
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
case 0:
rss_flags &= ~RTL_8125_RSS_FLAG_HASH_UDP_IPV4;
break;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
rss_flags |= RTL_8125_RSS_FLAG_HASH_UDP_IPV4;
break;
default:
return -EINVAL;
}
break;
case UDP_V6_FLOW:
if (!(nfc->data & RXH_IP_SRC) ||
!(nfc->data & RXH_IP_DST))
return -EINVAL;
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
case 0:
rss_flags &= ~RTL_8125_RSS_FLAG_HASH_UDP_IPV6;
break;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
rss_flags |= RTL_8125_RSS_FLAG_HASH_UDP_IPV6;
break;
default:
return -EINVAL;
}
break;
case SCTP_V4_FLOW:
case AH_ESP_V4_FLOW:
case AH_V4_FLOW:
case ESP_V4_FLOW:
case SCTP_V6_FLOW:
case AH_ESP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
case IP_USER_FLOW:
case ETHER_FLOW:
/* RSS is not supported for these protocols */
if (nfc->data) {
netif_err(tp, drv, tp->dev, "Command parameters not supported\n");
return -EINVAL;
}
return 0;
break;
default:
return -EINVAL;
}
/* if we changed something we need to update flags */
if (rss_flags != tp->rss_flags) {
u32 rss_ctrl = RTL_R32(tp, RSS_CTRL_8125);
if ((rss_flags & RTL8125_UDP_RSS_FLAGS) &&
!(tp->rss_flags & RTL8125_UDP_RSS_FLAGS))
netdev_warn(tp->dev,
"enabling UDP RSS: fragmented packets may "
"arrive out of order to the stack above\n");
tp->rss_flags = rss_flags;
/* Perform hash on these packet types */
rss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP
| RSS_CTRL_IPV4_SUPP
| RSS_CTRL_IPV6_SUPP
| RSS_CTRL_IPV6_EXT_SUPP
| RSS_CTRL_TCP_IPV6_SUPP
| RSS_CTRL_TCP_IPV6_EXT_SUPP;
rss_ctrl &= ~(RSS_CTRL_UDP_IPV4_SUPP |
RSS_CTRL_UDP_IPV6_SUPP |
RSS_CTRL_UDP_IPV6_EXT_SUPP);
if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV4)
rss_ctrl |= RSS_CTRL_UDP_IPV4_SUPP;
if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV6)
rss_ctrl |= RSS_CTRL_UDP_IPV6_SUPP |
RSS_CTRL_UDP_IPV6_EXT_SUPP;
RTL_W32(tp, RSS_CTRL_8125, rss_ctrl);
}
return 0;
}
int rtl8125_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
{
struct rtl8125_private *tp = netdev_priv(dev);
int ret = -EOPNOTSUPP;
if (!(dev->features & NETIF_F_RXHASH))
return ret;
switch (cmd->cmd) {
case ETHTOOL_SRXFH:
ret = rtl8125_set_rss_hash_opt(tp, cmd);
break;
default:
break;
}
return ret;
}
static u32 _rtl8125_get_rxfh_key_size(struct rtl8125_private *tp)
{
return sizeof(tp->rss_key);
}
u32 rtl8125_get_rxfh_key_size(struct net_device *dev)
{
struct rtl8125_private *tp = netdev_priv(dev);
if (!(dev->features & NETIF_F_RXHASH))
return 0;
return _rtl8125_get_rxfh_key_size(tp);
}
u32 rtl8125_rss_indir_size(struct net_device *dev)
{
struct rtl8125_private *tp = netdev_priv(dev);
if (!(dev->features & NETIF_F_RXHASH))
return 0;
return rtl8125_rss_indir_tbl_entries(tp);
}
static void rtl8125_get_reta(struct rtl8125_private *tp, u32 *indir)
{
int i, reta_size = rtl8125_rss_indir_tbl_entries(tp);
for (i = 0; i < reta_size; i++)
indir[i] = tp->rss_indir_tbl[i];
}
static u32 rtl8125_rss_key_reg(struct rtl8125_private *tp)
{
return RSS_KEY_8125;
}
static u32 rtl8125_rss_indir_tbl_reg(struct rtl8125_private *tp)
{
return RSS_INDIRECTION_TBL_8125_V2;
}
static void rtl8125_store_reta(struct rtl8125_private *tp)
{
u16 indir_tbl_reg = rtl8125_rss_indir_tbl_reg(tp);
u32 i, reta_entries = rtl8125_rss_indir_tbl_entries(tp);
u32 reta = 0;
u8 *indir_tbl = tp->rss_indir_tbl;
/* Write redirection table to HW */
for (i = 0; i < reta_entries; i++) {
reta |= indir_tbl[i] << (i & 0x3) * 8;
if ((i & 3) == 3) {
RTL_W32(tp, indir_tbl_reg, reta);
indir_tbl_reg += 4;
reta = 0;
}
}
}
static void rtl8125_store_rss_key(struct rtl8125_private *tp)
{
const u16 rss_key_reg = rtl8125_rss_key_reg(tp);
u32 i, rss_key_size = _rtl8125_get_rxfh_key_size(tp);
u32 *rss_key = (u32*)tp->rss_key;
/* Write redirection table to HW */
for (i = 0; i < rss_key_size; i+=4)
RTL_W32(tp, rss_key_reg + i, *rss_key++);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0)
int rtl8125_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh)
{
struct rtl8125_private *tp = netdev_priv(dev);
if (!(dev->features & NETIF_F_RXHASH))
return -EOPNOTSUPP;
rxfh->hfunc = ETH_RSS_HASH_TOP;
if (rxfh->indir)
rtl8125_get_reta(tp, rxfh->indir);
if (rxfh->key)
memcpy(rxfh->key, tp->rss_key, RTL8125_RSS_KEY_SIZE);
return 0;
}
int rtl8125_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack)
{
struct rtl8125_private *tp = netdev_priv(dev);
int i;
u32 reta_entries = rtl8125_rss_indir_tbl_entries(tp);
/* We require at least one supported parameter to be changed and no
* change in any of the unsupported parameters
*/
if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
/* Fill out the redirection table */
if (rxfh->indir) {
int max_queues = tp->num_rx_rings;
/* Verify user input. */
for (i = 0; i < reta_entries; i++)
if (rxfh->indir[i] >= max_queues)
return -EINVAL;
for (i = 0; i < reta_entries; i++)
tp->rss_indir_tbl[i] = rxfh->indir[i];
}
/* Fill out the rss hash key */
if (rxfh->key)
memcpy(tp->rss_key, rxfh->key, RTL8125_RSS_KEY_SIZE);
rtl8125_store_reta(tp);
rtl8125_store_rss_key(tp);
return 0;
}
#else
int rtl8125_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
u8 *hfunc)
{
struct rtl8125_private *tp = netdev_priv(dev);
if (!(dev->features & NETIF_F_RXHASH))
return -EOPNOTSUPP;
if (hfunc)
*hfunc = ETH_RSS_HASH_TOP;
if (indir)
rtl8125_get_reta(tp, indir);
if (key)
memcpy(key, tp->rss_key, RTL8125_RSS_KEY_SIZE);
return 0;
}
int rtl8125_set_rxfh(struct net_device *dev, const u32 *indir,
const u8 *key, const u8 hfunc)
{
struct rtl8125_private *tp = netdev_priv(dev);
int i;
u32 reta_entries = rtl8125_rss_indir_tbl_entries(tp);
/* We require at least one supported parameter to be changed and no
* change in any of the unsupported parameters
*/
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
/* Fill out the redirection table */
if (indir) {
int max_queues = tp->num_rx_rings;
/* Verify user input. */
for (i = 0; i < reta_entries; i++)
if (indir[i] >= max_queues)
return -EINVAL;
for (i = 0; i < reta_entries; i++)
tp->rss_indir_tbl[i] = indir[i];
}
/* Fill out the rss hash key */
if (key)
memcpy(tp->rss_key, key, RTL8125_RSS_KEY_SIZE);
rtl8125_store_reta(tp);
rtl8125_store_rss_key(tp);
return 0;
}
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0) */
static u32 rtl8125_get_rx_desc_hash(struct rtl8125_private *tp,
struct RxDesc *desc)
{
switch (tp->InitRxDescType) {
case RX_DESC_RING_TYPE_3:
return le32_to_cpu(((struct RxDescV3 *)desc)->RxDescNormalDDWord2.RSSResult);
case RX_DESC_RING_TYPE_4:
return le32_to_cpu(((struct RxDescV4 *)desc)->RxDescNormalDDWord1.RSSResult);
default:
return 0;
}
}
#define RXS_8125B_RSS_UDP BIT(9)
#define RXS_8125_RSS_IPV4 BIT(10)
#define RXS_8125_RSS_IPV6 BIT(12)
#define RXS_8125_RSS_TCP BIT(13)
#define RTL8125_RXS_RSS_L3_TYPE_MASK (RXS_8125_RSS_IPV4 | RXS_8125_RSS_IPV6)
#define RTL8125_RXS_RSS_L4_TYPE_MASK (RXS_8125_RSS_TCP | RXS_8125B_RSS_UDP)
#define RXS_8125B_RSS_UDP_V4 BIT(27)
#define RXS_8125_RSS_IPV4_V4 BIT(28)
#define RXS_8125_RSS_IPV6_V4 BIT(29)
#define RXS_8125_RSS_TCP_V4 BIT(30)
#define RTL8125_RXS_RSS_L3_TYPE_MASK_V4 (RXS_8125_RSS_IPV4_V4 | RXS_8125_RSS_IPV6_V4)
#define RTL8125_RXS_RSS_L4_TYPE_MASK_V4 (RXS_8125_RSS_TCP_V4 | RXS_8125B_RSS_UDP_V4)
static void rtl8125_rx_hash_v3(struct rtl8125_private *tp,
struct RxDescV3 *descv3,
struct sk_buff *skb)
{
u16 rss_header_info;
if (!(tp->dev->features & NETIF_F_RXHASH))
return;
rss_header_info = le16_to_cpu(descv3->RxDescNormalDDWord2.HeaderInfo);
if (!(rss_header_info & RTL8125_RXS_RSS_L3_TYPE_MASK))
return;
skb_set_hash(skb, rtl8125_get_rx_desc_hash(tp, (struct RxDesc *)descv3),
(RTL8125_RXS_RSS_L4_TYPE_MASK & rss_header_info) ?
PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
}
static void rtl8125_rx_hash_v4(struct rtl8125_private *tp,
struct RxDescV4 *descv4,
struct sk_buff *skb)
{
u32 rss_header_info;
if (!(tp->dev->features & NETIF_F_RXHASH))
return;
rss_header_info = le32_to_cpu(descv4->RxDescNormalDDWord1.RSSInfo);
if (!(rss_header_info & RTL8125_RXS_RSS_L3_TYPE_MASK_V4))
return;
skb_set_hash(skb, rtl8125_get_rx_desc_hash(tp, (struct RxDesc *)descv4),
(RTL8125_RXS_RSS_L4_TYPE_MASK_V4 & rss_header_info) ?
PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
}
void rtl8125_rx_hash(struct rtl8125_private *tp,
struct RxDesc *desc,
struct sk_buff *skb)
{
switch (tp->InitRxDescType) {
case RX_DESC_RING_TYPE_3:
rtl8125_rx_hash_v3(tp, (struct RxDescV3 *)desc, skb);
break;
case RX_DESC_RING_TYPE_4:
rtl8125_rx_hash_v4(tp, (struct RxDescV4 *)desc, skb);
break;
default:
return;
}
}
void rtl8125_disable_rss(struct rtl8125_private *tp)
{
RTL_W32(tp, RSS_CTRL_8125, 0x00);
}
void _rtl8125_config_rss(struct rtl8125_private *tp)
{
_rtl8125_set_rss_hash_opt(tp);
rtl8125_store_reta(tp);
rtl8125_store_rss_key(tp);
}
void rtl8125_config_rss(struct rtl8125_private *tp)
{
if (!tp->EnableRss) {
rtl8125_disable_rss(tp);
return;
}
_rtl8125_config_rss(tp);
}
void rtl8125_init_rss(struct rtl8125_private *tp)
{
int i;
for (i = 0; i < rtl8125_rss_indir_tbl_entries(tp); i++)
tp->rss_indir_tbl[i] = ethtool_rxfh_indir_default(i, tp->num_rx_rings);
netdev_rss_key_fill(tp->rss_key, RTL8125_RSS_KEY_SIZE);
}

View File

@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8125 is the Linux device driver released for Realtek 2.5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2025 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_rtl8125_RSS_H
#define _LINUX_rtl8125_RSS_H
#include <linux/netdevice.h>
#include <linux/types.h>
#define RTL8125_RSS_KEY_SIZE 40 /* size of RSS Hash Key in bytes */
#define RTL8125_MAX_INDIRECTION_TABLE_ENTRIES 128
enum rtl8125_rss_flag {
RTL_8125_RSS_FLAG_HASH_UDP_IPV4 = (1 << 0),
RTL_8125_RSS_FLAG_HASH_UDP_IPV6 = (1 << 1),
};
struct rtl8125_private;
struct RxDesc;
int rtl8125_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
u32 *rule_locs);
int rtl8125_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd);
u32 rtl8125_get_rxfh_key_size(struct net_device *netdev);
u32 rtl8125_rss_indir_size(struct net_device *netdev);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0)
int rtl8125_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh);
int rtl8125_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack);
#else
int rtl8125_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
u8 *hfunc);
int rtl8125_set_rxfh(struct net_device *netdev, const u32 *indir,
const u8 *key, const u8 hfunc);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0) */
void rtl8125_rx_hash(struct rtl8125_private *tp,
struct RxDesc *desc,
struct sk_buff *skb);
void _rtl8125_config_rss(struct rtl8125_private *tp);
void rtl8125_config_rss(struct rtl8125_private *tp);
void rtl8125_init_rss(struct rtl8125_private *tp);
u32 rtl8125_rss_indir_tbl_entries(struct rtl8125_private *tp);
void rtl8125_disable_rss(struct rtl8125_private *tp);
#endif /* _LINUX_rtl8125_RSS_H */

View File

@ -0,0 +1,284 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
################################################################################
#
# r8125 is the Linux device driver released for Realtek 2.5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2025 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <asm/io.h>
#include "r8125.h"
#include "rtl_eeprom.h"
//-------------------------------------------------------------------
//rtl8125_eeprom_type():
// tell the eeprom type
//return value:
// 0: the eeprom type is 93C46
// 1: the eeprom type is 93C56 or 93C66
//-------------------------------------------------------------------
void rtl8125_eeprom_type(struct rtl8125_private *tp)
{
u16 magic = 0;
if (tp->mcfg == CFG_METHOD_DEFAULT)
goto out_no_eeprom;
if(RTL_R8(tp, 0xD2)&0x04) {
//not support
//tp->eeprom_type = EEPROM_TWSI;
//tp->eeprom_len = 256;
goto out_no_eeprom;
} else if(RTL_R32(tp, RxConfig) & RxCfg_9356SEL) {
tp->eeprom_type = EEPROM_TYPE_93C56;
tp->eeprom_len = 256;
} else {
tp->eeprom_type = EEPROM_TYPE_93C46;
tp->eeprom_len = 128;
}
magic = rtl8125_eeprom_read_sc(tp, 0);
out_no_eeprom:
if ((magic != 0x8129) && (magic != 0x8128)) {
tp->eeprom_type = EEPROM_TYPE_NONE;
tp->eeprom_len = 0;
}
}
void rtl8125_eeprom_cleanup(struct rtl8125_private *tp)
{
u8 x;
x = RTL_R8(tp, Cfg9346);
x &= ~(Cfg9346_EEDI | Cfg9346_EECS);
RTL_W8(tp, Cfg9346, x);
rtl8125_raise_clock(tp, &x);
rtl8125_lower_clock(tp, &x);
}
static int rtl8125_eeprom_cmd_done(struct rtl8125_private *tp)
{
u8 x;
int i;
rtl8125_stand_by(tp);
for (i = 0; i < 50000; i++) {
x = RTL_R8(tp, Cfg9346);
if (x & Cfg9346_EEDO) {
udelay(RTL_CLOCK_RATE * 2 * 3);
return 0;
}
udelay(1);
}
return -1;
}
//-------------------------------------------------------------------
//rtl8125_eeprom_read_sc():
// read one word from eeprom
//-------------------------------------------------------------------
u16 rtl8125_eeprom_read_sc(struct rtl8125_private *tp, u16 reg)
{
int addr_sz = 6;
u8 x;
u16 data;
if(tp->eeprom_type == EEPROM_TYPE_NONE)
return -1;
if (tp->eeprom_type==EEPROM_TYPE_93C46)
addr_sz = 6;
else if (tp->eeprom_type==EEPROM_TYPE_93C56)
addr_sz = 8;
x = Cfg9346_EEM1 | Cfg9346_EECS;
RTL_W8(tp, Cfg9346, x);
rtl8125_shift_out_bits(tp, RTL_EEPROM_READ_OPCODE, 3);
rtl8125_shift_out_bits(tp, reg, addr_sz);
data = rtl8125_shift_in_bits(tp);
rtl8125_eeprom_cleanup(tp);
RTL_W8(tp, Cfg9346, 0);
return data;
}
//-------------------------------------------------------------------
//rtl8125_eeprom_write_sc():
// write one word to a specific address in the eeprom
//-------------------------------------------------------------------
void rtl8125_eeprom_write_sc(struct rtl8125_private *tp, u16 reg, u16 data)
{
u8 x;
int addr_sz = 6;
int w_dummy_addr = 4;
if(tp->eeprom_type == EEPROM_TYPE_NONE)
return;
if (tp->eeprom_type==EEPROM_TYPE_93C46) {
addr_sz = 6;
w_dummy_addr = 4;
} else if (tp->eeprom_type==EEPROM_TYPE_93C56) {
addr_sz = 8;
w_dummy_addr = 6;
}
x = Cfg9346_EEM1 | Cfg9346_EECS;
RTL_W8(tp, Cfg9346, x);
rtl8125_shift_out_bits(tp, RTL_EEPROM_EWEN_OPCODE, 5);
rtl8125_shift_out_bits(tp, reg, w_dummy_addr);
rtl8125_stand_by(tp);
rtl8125_shift_out_bits(tp, RTL_EEPROM_ERASE_OPCODE, 3);
rtl8125_shift_out_bits(tp, reg, addr_sz);
if (rtl8125_eeprom_cmd_done(tp) < 0)
return;
rtl8125_stand_by(tp);
rtl8125_shift_out_bits(tp, RTL_EEPROM_WRITE_OPCODE, 3);
rtl8125_shift_out_bits(tp, reg, addr_sz);
rtl8125_shift_out_bits(tp, data, 16);
if (rtl8125_eeprom_cmd_done(tp) < 0)
return;
rtl8125_stand_by(tp);
rtl8125_shift_out_bits(tp, RTL_EEPROM_EWDS_OPCODE, 5);
rtl8125_shift_out_bits(tp, reg, w_dummy_addr);
rtl8125_eeprom_cleanup(tp);
RTL_W8(tp, Cfg9346, 0);
}
void rtl8125_raise_clock(struct rtl8125_private *tp, u8 *x)
{
*x = *x | Cfg9346_EESK;
RTL_W8(tp, Cfg9346, *x);
udelay(RTL_CLOCK_RATE);
}
void rtl8125_lower_clock(struct rtl8125_private *tp, u8 *x)
{
*x = *x & ~Cfg9346_EESK;
RTL_W8(tp, Cfg9346, *x);
udelay(RTL_CLOCK_RATE);
}
void rtl8125_shift_out_bits(struct rtl8125_private *tp, int data, int count)
{
u8 x;
int mask;
mask = 0x01 << (count - 1);
x = RTL_R8(tp, Cfg9346);
x &= ~(Cfg9346_EEDI | Cfg9346_EEDO);
do {
if (data & mask)
x |= Cfg9346_EEDI;
else
x &= ~Cfg9346_EEDI;
RTL_W8(tp, Cfg9346, x);
udelay(RTL_CLOCK_RATE);
rtl8125_raise_clock(tp, &x);
rtl8125_lower_clock(tp, &x);
mask = mask >> 1;
} while(mask);
x &= ~Cfg9346_EEDI;
RTL_W8(tp, Cfg9346, x);
}
u16 rtl8125_shift_in_bits(struct rtl8125_private *tp)
{
u8 x;
u16 d, i;
x = RTL_R8(tp, Cfg9346);
x &= ~(Cfg9346_EEDI | Cfg9346_EEDO);
d = 0;
for (i = 0; i < 16; i++) {
d = d << 1;
rtl8125_raise_clock(tp, &x);
x = RTL_R8(tp, Cfg9346);
x &= ~Cfg9346_EEDI;
if (x & Cfg9346_EEDO)
d |= 1;
rtl8125_lower_clock(tp, &x);
}
return d;
}
void rtl8125_stand_by(struct rtl8125_private *tp)
{
u8 x;
x = RTL_R8(tp, Cfg9346);
x &= ~(Cfg9346_EECS | Cfg9346_EESK);
RTL_W8(tp, Cfg9346, x);
udelay(RTL_CLOCK_RATE);
x |= Cfg9346_EECS;
RTL_W8(tp, Cfg9346, x);
}
void rtl8125_set_eeprom_sel_low(struct rtl8125_private *tp)
{
RTL_W8(tp, Cfg9346, Cfg9346_EEM1);
RTL_W8(tp, Cfg9346, Cfg9346_EEM1 | Cfg9346_EESK);
udelay(20);
RTL_W8(tp, Cfg9346, Cfg9346_EEM1);
}

View File

@ -0,0 +1,53 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8125 is the Linux device driver released for Realtek 2.5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2025 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
//EEPROM opcodes
#define RTL_EEPROM_READ_OPCODE 06
#define RTL_EEPROM_WRITE_OPCODE 05
#define RTL_EEPROM_ERASE_OPCODE 07
#define RTL_EEPROM_EWEN_OPCODE 19
#define RTL_EEPROM_EWDS_OPCODE 16
#define RTL_CLOCK_RATE 3
void rtl8125_eeprom_type(struct rtl8125_private *tp);
void rtl8125_eeprom_cleanup(struct rtl8125_private *tp);
u16 rtl8125_eeprom_read_sc(struct rtl8125_private *tp, u16 reg);
void rtl8125_eeprom_write_sc(struct rtl8125_private *tp, u16 reg, u16 data);
void rtl8125_shift_out_bits(struct rtl8125_private *tp, int data, int count);
u16 rtl8125_shift_in_bits(struct rtl8125_private *tp);
void rtl8125_raise_clock(struct rtl8125_private *tp, u8 *x);
void rtl8125_lower_clock(struct rtl8125_private *tp, u8 *x);
void rtl8125_stand_by(struct rtl8125_private *tp);
void rtl8125_set_eeprom_sel_low(struct rtl8125_private *tp);

View File

@ -0,0 +1,312 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
################################################################################
#
# r8125 is the Linux device driver released for Realtek 2.5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2025 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/in.h>
#include <linux/ethtool.h>
#include <asm/uaccess.h>
#include "r8125.h"
#include "rtl_eeprom.h"
#include "rtltool.h"
int rtl8125_tool_ioctl(struct rtl8125_private *tp, struct ifreq *ifr)
{
struct rtltool_cmd my_cmd;
unsigned long flags;
int ret;
if (copy_from_user(&my_cmd, ifr->ifr_data, sizeof(my_cmd)))
return -EFAULT;
ret = 0;
switch (my_cmd.cmd) {
case RTLTOOL_READ_MAC:
if ((my_cmd.offset + my_cmd.len) > pci_resource_len(tp->pci_dev, 2)) {
ret = -EINVAL;
break;
}
if (my_cmd.len==1)
my_cmd.data = readb(tp->mmio_addr+my_cmd.offset);
else if (my_cmd.len==2)
my_cmd.data = readw(tp->mmio_addr+(my_cmd.offset&~1));
else if (my_cmd.len==4)
my_cmd.data = readl(tp->mmio_addr+(my_cmd.offset&~3));
else {
ret = -EOPNOTSUPP;
break;
}
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_MAC:
if ((my_cmd.offset + my_cmd.len) > pci_resource_len(tp->pci_dev, 2)) {
ret = -EINVAL;
break;
}
if (my_cmd.len==1)
writeb(my_cmd.data, tp->mmio_addr+my_cmd.offset);
else if (my_cmd.len==2)
writew(my_cmd.data, tp->mmio_addr+(my_cmd.offset&~1));
else if (my_cmd.len==4)
writel(my_cmd.data, tp->mmio_addr+(my_cmd.offset&~3));
else {
ret = -EOPNOTSUPP;
break;
}
break;
case RTLTOOL_READ_PHY:
r8125_spin_lock(&tp->phy_lock, flags);
my_cmd.data = rtl8125_mdio_prot_read(tp, my_cmd.offset);
r8125_spin_unlock(&tp->phy_lock, flags);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_PHY:
r8125_spin_lock(&tp->phy_lock, flags);
rtl8125_mdio_prot_write(tp, my_cmd.offset, my_cmd.data);
r8125_spin_unlock(&tp->phy_lock, flags);
break;
case RTLTOOL_READ_EPHY:
my_cmd.data = rtl8125_ephy_read(tp, my_cmd.offset);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_EPHY:
rtl8125_ephy_write(tp, my_cmd.offset, my_cmd.data);
break;
case RTLTOOL_READ_ERI:
my_cmd.data = 0;
if (my_cmd.len==1 || my_cmd.len==2 || my_cmd.len==4) {
my_cmd.data = rtl8125_eri_read(tp, my_cmd.offset, my_cmd.len, ERIAR_ExGMAC);
} else {
ret = -EOPNOTSUPP;
break;
}
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_ERI:
if (my_cmd.len==1 || my_cmd.len==2 || my_cmd.len==4) {
rtl8125_eri_write(tp, my_cmd.offset, my_cmd.len, my_cmd.data, ERIAR_ExGMAC);
} else {
ret = -EOPNOTSUPP;
break;
}
break;
case RTLTOOL_READ_PCI:
my_cmd.data = 0;
if (my_cmd.len==1)
pci_read_config_byte(tp->pci_dev, my_cmd.offset,
(u8 *)&my_cmd.data);
else if (my_cmd.len==2)
pci_read_config_word(tp->pci_dev, my_cmd.offset,
(u16 *)&my_cmd.data);
else if (my_cmd.len==4)
pci_read_config_dword(tp->pci_dev, my_cmd.offset,
&my_cmd.data);
else {
ret = -EOPNOTSUPP;
break;
}
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_PCI:
if (my_cmd.len==1)
pci_write_config_byte(tp->pci_dev, my_cmd.offset,
my_cmd.data);
else if (my_cmd.len==2)
pci_write_config_word(tp->pci_dev, my_cmd.offset,
my_cmd.data);
else if (my_cmd.len==4)
pci_write_config_dword(tp->pci_dev, my_cmd.offset,
my_cmd.data);
else {
ret = -EOPNOTSUPP;
break;
}
break;
case RTLTOOL_READ_EEPROM:
my_cmd.data = rtl8125_eeprom_read_sc(tp, my_cmd.offset);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_EEPROM:
rtl8125_eeprom_write_sc(tp, my_cmd.offset, my_cmd.data);
break;
case RTL_READ_OOB_MAC:
rtl8125_oob_mutex_lock(tp);
my_cmd.data = rtl8125_ocp_read(tp, my_cmd.offset, 4);
rtl8125_oob_mutex_unlock(tp);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTL_WRITE_OOB_MAC:
if (my_cmd.len == 0 || my_cmd.len > 4)
return -EOPNOTSUPP;
rtl8125_oob_mutex_lock(tp);
rtl8125_ocp_write(tp, my_cmd.offset, my_cmd.len, my_cmd.data);
rtl8125_oob_mutex_unlock(tp);
break;
case RTL_ENABLE_PCI_DIAG:
r8125_spin_lock(&tp->phy_lock, flags);
tp->rtk_enable_diag = 1;
r8125_spin_unlock(&tp->phy_lock, flags);
dprintk("enable rtk diag\n");
break;
case RTL_DISABLE_PCI_DIAG:
r8125_spin_lock(&tp->phy_lock, flags);
tp->rtk_enable_diag = 0;
r8125_spin_unlock(&tp->phy_lock, flags);
dprintk("disable rtk diag\n");
break;
case RTL_READ_MAC_OCP:
if (my_cmd.offset % 2)
return -EOPNOTSUPP;
my_cmd.data = rtl8125_mac_ocp_read(tp, my_cmd.offset);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTL_WRITE_MAC_OCP:
if ((my_cmd.offset % 2) || (my_cmd.len != 2))
return -EOPNOTSUPP;
rtl8125_mac_ocp_write(tp, my_cmd.offset, (u16)my_cmd.data);
break;
case RTL_DIRECT_READ_PHY_OCP:
r8125_spin_lock(&tp->phy_lock, flags);
my_cmd.data = rtl8125_mdio_prot_direct_read_phy_ocp(tp, my_cmd.offset);
r8125_spin_unlock(&tp->phy_lock, flags);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTL_DIRECT_WRITE_PHY_OCP:
r8125_spin_lock(&tp->phy_lock, flags);
rtl8125_mdio_prot_direct_write_phy_ocp(tp, my_cmd.offset, my_cmd.data);
r8125_spin_unlock(&tp->phy_lock, flags);
break;
#ifdef ENABLE_FIBER_SUPPORT
case RTL_READ_FIBER_PHY:
if (!HW_FIBER_STATUS_CONNECTED(tp)) {
ret = -EOPNOTSUPP;
break;
}
r8125_spin_lock(&tp->phy_lock, flags);
my_cmd.data = rtl8125_fiber_mdio_read(tp, my_cmd.offset);
r8125_spin_unlock(&tp->phy_lock, flags);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTL_WRITE_FIBER_PHY:
if (!HW_FIBER_STATUS_CONNECTED(tp)) {
ret = -EOPNOTSUPP;
break;
}
r8125_spin_lock(&tp->phy_lock, flags);
rtl8125_fiber_mdio_write(tp, my_cmd.offset, my_cmd.data);
r8125_spin_unlock(&tp->phy_lock, flags);
break;
#endif /* ENABLE_FIBER_SUPPORT */
default:
ret = -EOPNOTSUPP;
break;
}
return ret;
}

View File

@ -0,0 +1,89 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8125 is the Linux device driver released for Realtek 2.5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2025 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_RTLTOOL_H
#define _LINUX_RTLTOOL_H
#define SIOCRTLTOOL SIOCDEVPRIVATE+1
enum rtl_cmd {
RTLTOOL_READ_MAC=0,
RTLTOOL_WRITE_MAC,
RTLTOOL_READ_PHY,
RTLTOOL_WRITE_PHY,
RTLTOOL_READ_EPHY,
RTLTOOL_WRITE_EPHY,
RTLTOOL_READ_ERI,
RTLTOOL_WRITE_ERI,
RTLTOOL_READ_PCI,
RTLTOOL_WRITE_PCI,
RTLTOOL_READ_EEPROM,
RTLTOOL_WRITE_EEPROM,
RTL_READ_OOB_MAC,
RTL_WRITE_OOB_MAC,
RTL_ENABLE_PCI_DIAG,
RTL_DISABLE_PCI_DIAG,
RTL_READ_MAC_OCP,
RTL_WRITE_MAC_OCP,
RTL_DIRECT_READ_PHY_OCP,
RTL_DIRECT_WRITE_PHY_OCP,
RTL_READ_FIBER_PHY,
RTL_WRITE_FIBER_PHY,
RTLTOOL_INVALID
};
struct rtltool_cmd {
__u32 cmd;
__u32 offset;
__u32 len;
__u32 data;
};
enum mode_access {
MODE_NONE=0,
MODE_READ,
MODE_WRITE
};
#ifdef __KERNEL__
int rtl8125_tool_ioctl(struct rtl8125_private *tp, struct ifreq *ifr);
#endif
#endif /* _LINUX_RTLTOOL_H */

View File

@ -0,0 +1 @@
savedcmd_drivers/net/ethernet/realtek/r8126/built-in.a := rm -f drivers/net/ethernet/realtek/r8126/built-in.a; printf "drivers/net/ethernet/realtek/r8126/%s " r8126_n.o rtl_eeprom.o rtltool.o r8126_fiber.o | xargs ar cDPrST drivers/net/ethernet/realtek/r8126/built-in.a

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
config R8126
tristate "Realtek 5G Ethernet driver (r8126)"
depends on PCI && MII
help
This is the official Realtek 5G Ethernet driver.

View File

@ -0,0 +1,73 @@
obj-$(CONFIG_R8126) += r8126.o
r8126-objs += r8126_n.o rtl_eeprom.o rtltool.o r8126_fiber.o
EXTRA_CFLAGS += -DCONFIG_SOC_LAN
EXTRA_CFLAGS += -DENABLE_FIBER_SUPPORT
EXTRA_CFLAGS += -DCONFIG_ASPM
EXTRA_CFLAGS += -DENABLE_S5WOL
EXTRA_CFLAGS += -DENABLE_TX_NO_CLOSE
EXTRA_CFLAGS += -DENABLE_GIGA_LITE
# EXTRA_CFLAGS += -DCONFIG_R8126_NAPI # Need to check if needed
# EXTRA_CFLAGS += -DCONFIG_R8126_VLAN # Need to check if needed
#
# Other options that can be enabled if needed.
#
# ENABLE_REALWOW_SUPPORT:
# r8126-objs += r8126_realwow.o
# EXTRA_CFLAGS += -DENABLE_REALWOW_SUPPORT
#
# ENABLE_DASH_SUPPORT:
# r8126-objs += r8126_dash.o
# EXTRA_CFLAGS += -DENABLE_DASH_SUPPORT
#
# ENABLE_DASH_PRINTER_SUPPORT:
# r8126-objs += r8126_dash.o
# EXTRA_CFLAGS += -DENABLE_DASH_SUPPORT -DENABLE_DASH_PRINTER_SUPPORT
#
# CONFIG_DOWN_SPEED_100:
# EXTRA_CFLAGS += -DCONFIG_DOWN_SPEED_100
#
# ENABLE_S5_KEEP_CURR_MAC:
# EXTRA_CFLAGS += -DENABLE_S5_KEEP_CURR_MAC
#
# ENABLE_EEE:
# EXTRA_CFLAGS += -DENABLE_EEE
#
# ENABLE_S0_MAGIC_PACKET:
# EXTRA_CFLAGS += -DENABLE_S0_MAGIC_PACKET
#
# ENABLE_MULTIPLE_TX_QUEUE:
# EXTRA_CFLAGS += -DENABLE_MULTIPLE_TX_QUEUE
#
# ENABLE_PTP_SUPPORT:
# r8126-objs += r8126_ptp.o
# EXTRA_CFLAGS += -DENABLE_PTP_SUPPORT
#
# ENABLE_RSS_SUPPORT:
# r8126-objs += r8126_rss.o
# EXTRA_CFLAGS += -DENABLE_RSS_SUPPORT
#
# ENABLE_LIB_SUPPORT:
# r8126-objs += r8126_lib.o
# EXTRA_CFLAGS += -DENABLE_LIB_SUPPORT
#
# ENABLE_USE_FIRMWARE_FILE:
# r8126-objs += r8126_firmware.o
# EXTRA_CFLAGS += -DENABLE_USE_FIRMWARE_FILE
#
# DISABLE_WOL_SUPPORT:
# EXTRA_CFLAGS += -DDISABLE_WOL_SUPPORT
#
# DISABLE_MULTI_MSIX_VECTOR:
# EXTRA_CFLAGS += -DDISABLE_MULTI_MSIX_VECTOR
#
# ENABLE_DOUBLE_VLAN:
# EXTRA_CFLAGS += -DENABLE_DOUBLE_VLAN
#
# ENABLE_PAGE_REUSE:
# EXTRA_CFLAGS += -DENABLE_PAGE_REUSE
#
# ENABLE_RX_PACKET_FRAGMENT:
# EXTRA_CFLAGS += -DENABLE_RX_PACKET_FRAGMENT

View File

@ -0,0 +1,11 @@
!<thin>
// 52 `
r8126_n.o/
rtl_eeprom.o/
rtltool.o/
r8126_fiber.o/
/0 0 0 0 644 308368 `
/11 0 0 0 644 10088 `
/25 0 0 0 644 5872 `
/36 0 0 0 644 11032 `

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,261 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_R8126_DASH_H
#define _LINUX_R8126_DASH_H
#include <linux/if.h>
#define SIOCDEVPRIVATE_RTLDASH SIOCDEVPRIVATE+2
enum rtl_dash_cmd {
RTL_DASH_ARP_NS_OFFLOAD = 0,
RTL_DASH_SET_OOB_IPMAC,
RTL_DASH_NOTIFY_OOB,
RTL_DASH_SEND_BUFFER_DATA_TO_DASH_FW,
RTL_DASH_CHECK_SEND_BUFFER_TO_DASH_FW_COMPLETE,
RTL_DASH_GET_RCV_FROM_FW_BUFFER_DATA,
RTL_DASH_OOB_REQ,
RTL_DASH_OOB_ACK,
RTL_DASH_DETACH_OOB_REQ,
RTL_DASH_DETACH_OOB_ACK,
RTL_FW_SET_IPV4 = 0x10,
RTL_FW_GET_IPV4,
RTL_FW_SET_IPV6,
RTL_FW_GET_IPV6,
RTL_FW_SET_EXT_SNMP,
RTL_FW_GET_EXT_SNMP,
RTL_FW_SET_WAKEUP_PATTERN,
RTL_FW_GET_WAKEUP_PATTERN,
RTL_FW_DEL_WAKEUP_PATTERN,
RTLT_DASH_COMMAND_INVALID,
};
struct rtl_dash_ip_mac {
struct sockaddr ifru_addr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
};
struct rtl_dash_ioctl_struct {
__u32 cmd;
__u32 offset;
__u32 len;
union {
__u32 data;
void *data_buffer;
};
};
struct settings_ipv4 {
__u32 IPv4addr;
__u32 IPv4mask;
__u32 IPv4Gateway;
};
struct settings_ipv6 {
__u32 reserved;
__u32 prefixLen;
__u16 IPv6addr[8];
__u16 IPv6Gateway[8];
};
struct settings_ext_snmp {
__u16 index;
__u16 oid_get_len;
__u8 oid_for_get[24];
__u8 reserved0[26];
__u16 value_len;
__u8 value[256];
__u8 supported;
__u8 reserved1[27];
};
struct wakeup_pattern {
__u8 index;
__u8 valid;
__u8 start;
__u8 length;
__u8 name[36];
__u8 mask[16];
__u8 pattern[128];
__u32 reserved[2];
};
typedef struct _RX_DASH_FROM_FW_DESC {
u16 length;
u8 statusLowByte;
u8 statusHighByte;
u32 resv;
u64 BufferAddress;
}
RX_DASH_FROM_FW_DESC, *PRX_DASH_FROM_FW_DESC;
typedef struct _TX_DASH_SEND_FW_DESC {
u16 length;
u8 statusLowByte;
u8 statusHighByte;
u32 resv;
u64 BufferAddress;
}
TX_DASH_SEND_FW_DESC, *PTX_DASH_SEND_FW_DESC;
typedef struct _OSOOBHdr {
u32 len;
u8 type;
u8 flag;
u8 hostReqV;
u8 res;
}
OSOOBHdr, *POSOOBHdr;
typedef struct _RX_DASH_BUFFER_TYPE_2 {
OSOOBHdr oobhdr;
u8 RxDataBuffer[0];
}
RX_DASH_BUFFER_TYPE_2, *PRX_DASH_BUFFER_TYPE_2;
#define ALIGN_8 (0x7)
#define ALIGN_16 (0xf)
#define ALIGN_32 (0x1f)
#define ALIGN_64 (0x3f)
#define ALIGN_256 (0xff)
#define ALIGN_4096 (0xfff)
#define OCP_REG_CONFIG0 (0x10)
#define OCP_REG_CONFIG0_REV_F (0xB8)
#define OCP_REG_DASH_POLL (0x30)
#define OCP_REG_HOST_REQ (0x34)
#define OCP_REG_DASH_REQ (0x35)
#define OCP_REG_CR (0x36)
#define OCP_REG_DMEMSTA (0x38)
#define OCP_REG_GPHYAR (0x60)
#define OCP_REG_CONFIG0_DASHEN BIT_15
#define OCP_REG_CONFIG0_OOBRESET BIT_14
#define OCP_REG_CONFIG0_APRDY BIT_13
#define OCP_REG_CONFIG0_FIRMWARERDY BIT_12
#define OCP_REG_CONFIG0_DRIVERRDY BIT_11
#define OCP_REG_CONFIG0_OOB_WDT BIT_9
#define OCP_REG_CONFIG0_DRV_WAIT_OOB BIT_8
#define OCP_REG_CONFIG0_TLSEN BIT_7
#define HW_DASH_SUPPORT_DASH(_M) ((_M)->HwSuppDashVer > 0)
#define HW_DASH_SUPPORT_TYPE_1(_M) ((_M)->HwSuppDashVer == 1)
#define HW_DASH_SUPPORT_TYPE_2(_M) ((_M)->HwSuppDashVer == 2)
#define HW_DASH_SUPPORT_TYPE_3(_M) ((_M)->HwSuppDashVer == 3)
#define RECV_FROM_FW_BUF_SIZE (1520)
#define SEND_TO_FW_BUF_SIZE (1520)
#define RX_DASH_FROM_FW_OWN BIT_15
#define TX_DASH_SEND_FW_OWN BIT_15
#define TX_DASH_SEND_FW_OWN_HIGHBYTE BIT_7
#define TXS_CC3_0 (BIT_0|BIT_1|BIT_2|BIT_3)
#define TXS_EXC BIT_4
#define TXS_LNKF BIT_5
#define TXS_OWC BIT_6
#define TXS_TES BIT_7
#define TXS_UNF BIT_9
#define TXS_LGSEN BIT_11
#define TXS_LS BIT_12
#define TXS_FS BIT_13
#define TXS_EOR BIT_14
#define TXS_OWN BIT_15
#define TPPool_HRDY 0x20
#define HostReqReg (0xC0)
#define SystemMasterDescStartAddrLow (0xF0)
#define SystemMasterDescStartAddrHigh (0xF4)
#define SystemSlaveDescStartAddrLow (0xF8)
#define SystemSlaveDescStartAddrHigh (0xFC)
//DASH Request Type
#define WSMANREG 0x01
#define OSPUSHDATA 0x02
#define RXS_OWN BIT_15
#define RXS_EOR BIT_14
#define RXS_FS BIT_13
#define RXS_LS BIT_12
#define ISRIMR_DP_DASH_OK BIT_15
#define ISRIMR_DP_HOST_OK BIT_13
#define ISRIMR_DP_REQSYS_OK BIT_11
#define ISRIMR_DASH_INTR_EN BIT_12
#define ISRIMR_DASH_INTR_CMAC_RESET BIT_15
#define ISRIMR_DASH_TYPE2_ROK BIT_0
#define ISRIMR_DASH_TYPE2_RDU BIT_1
#define ISRIMR_DASH_TYPE2_TOK BIT_2
#define ISRIMR_DASH_TYPE2_TDU BIT_3
#define ISRIMR_DASH_TYPE2_TX_FIFO_FULL BIT_4
#define ISRIMR_DASH_TYPE2_TX_DISABLE_IDLE BIT_5
#define ISRIMR_DASH_TYPE2_RX_DISABLE_IDLE BIT_6
#define CMAC_OOB_STOP 0x25
#define CMAC_OOB_INIT 0x26
#define CMAC_OOB_RESET 0x2a
#define NO_BASE_ADDRESS 0x00000000
#define RTL8168FP_OOBMAC_BASE 0xBAF70000
#define RTL8168FP_CMAC_IOBASE 0xBAF20000
#define RTL8168FP_KVM_BASE 0xBAF80400
#define CMAC_SYNC_REG 0x20
#define CMAC_RXDESC_OFFSET 0x90 //RX: 0x90 - 0x98
#define CMAC_TXDESC_OFFSET 0x98 //TX: 0x98 - 0x9F
/* cmac write/read MMIO register */
#define RTL_CMAC_W8(tp, reg, val8) writeb ((val8), tp->cmac_ioaddr + (reg))
#define RTL_CMAC_W16(tp, reg, val16) writew ((val16), tp->cmac_ioaddr + (reg))
#define RTL_CMAC_W32(tp, reg, val32) writel ((val32), tp->cmac_ioaddr + (reg))
#define RTL_CMAC_R8(tp, reg) readb (tp->cmac_ioaddr + (reg))
#define RTL_CMAC_R16(tp, reg) readw (tp->cmac_ioaddr + (reg))
#define RTL_CMAC_R32(tp, reg) ((unsigned long) readl (tp->cmac_ioaddr + (reg)))
int rtl8126_dash_ioctl(struct net_device *dev, struct ifreq *ifr);
void HandleDashInterrupt(struct net_device *dev);
int AllocateDashShareMemory(struct net_device *dev);
void FreeAllocatedDashShareMemory(struct net_device *dev);
void DashHwInit(struct net_device *dev);
#endif /* _LINUX_R8126_DASH_H */

View File

@ -0,0 +1,466 @@
/*
################################################################################
#
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include "r8126.h"
#include "r8126_fiber.h"
static void
rtl8126_fiber_set_mdc_gpio_c45(struct rtl8126_private *tp, bool pu)
{
if (pu)
rtl8126_set_mac_ocp_bit(tp, 0xDC52, BIT_7);
else
rtl8126_clear_mac_ocp_bit(tp, 0xDC52, BIT_7);
//RtPciCommittp);
}
static void
rtl8126_fiber_set_mdc(struct rtl8126_private *tp, bool pu)
{
rtl8126_fiber_set_mdc_gpio_c45(tp, pu);
}
static void
rtl8126_fiber_set_mdcDownUp(struct rtl8126_private *tp)
{
udelay(1);
rtl8126_fiber_set_mdc(tp, 0);
udelay(1);
rtl8126_fiber_set_mdc(tp, 1);
}
static void
rtl8126_fiber_set_mdio_bit_gpio_c45(struct rtl8126_private *tp, bool pu)
{
if (pu)
rtl8126_set_mac_ocp_bit(tp, 0xDC52, BIT_2);
else
rtl8126_clear_mac_ocp_bit(tp, 0xDC52, BIT_2);
//RtPciCommittp);
rtl8126_fiber_set_mdcDownUp(tp);
}
static void
rtl8126_fiber_set_mdio_bit(struct rtl8126_private *tp, bool pu)
{
rtl8126_fiber_set_mdio_bit_gpio_c45(tp, pu);
}
static u16
rtl8126_fiber_get_mdio_bit_gpio_c45(struct rtl8126_private *tp)
{
rtl8126_fiber_set_mdcDownUp(tp);
return !!(rtl8126_mac_ocp_read(tp, 0xDC58) & BIT(2));
}
static u16
rtl8126_fiber_get_mdio_bit(struct rtl8126_private *tp)
{
return rtl8126_fiber_get_mdio_bit_gpio_c45(tp);
}
static void
rtl8126_fiber_shift_bit_in(struct rtl8126_private *tp, u32 val, int count)
{
int i;
for (i = (count - 1); i >= 0; i--)
rtl8126_fiber_set_mdio_bit(tp, !!(val & BIT(i)));
}
static u16
rtl8126_fiber_shift_bit_out(struct rtl8126_private *tp)
{
u16 data = 0;
int i;
for (i = 15; i >= 0; i--)
data += (rtl8126_fiber_get_mdio_bit(tp) << i);
return data;
}
static void
rtl8126_fiber_dir_gpio_c45(struct rtl8126_private *tp, bool output_mode)
{
if (output_mode)
rtl8126_set_mac_ocp_bit(tp, 0xDC4C, BIT_2);
else
rtl8126_clear_mac_ocp_bit(tp, 0xDC4C, BIT_2);
}
static void
rtl8126_fiber_dir(struct rtl8126_private *tp, bool output_mode)
{
rtl8126_fiber_dir_gpio_c45(tp, output_mode);
}
//fiber
#define R8126_FIBER_C22 (0)
#define R8126_FIBER_C45 (1)
// sfp opcodes
#define R8126_FIBER_ST (1)
#define R8126_FIBER_OP_W (1)
#define R8126_FIBER_OP_R (2)
#define R8126_FIBER_TA (2)
// sfp C45 opcodes
#define R8126_FIBER_MDIO_C45 (BIT(15))
#define R8126_FIBER_C45_ST (R8126_FIBER_MDIO_C45 | 0)
#define R8126_FIBER_C45_OP_ADDR (R8126_FIBER_MDIO_C45 | 0)
#define R8126_FIBER_C45_OP_W (R8126_FIBER_MDIO_C45 | 1)
#define R8126_FIBER_C45_OP_R (R8126_FIBER_MDIO_C45 | 3)
static void
rtl8126_fiber_cmd(struct rtl8126_private *tp, u32 cmd, u8 phy_addr,
u32 reg)
{
/* change to output mode */
rtl8126_fiber_dir(tp, 1);
/* preamble 32bit of 1 */
rtl8126_fiber_shift_bit_in(tp, UINT_MAX, 32);
/* start bit */
if (cmd & R8126_FIBER_MDIO_C45)
rtl8126_fiber_shift_bit_in(tp, R8126_FIBER_C45_ST, 2);
else
rtl8126_fiber_shift_bit_in(tp, R8126_FIBER_ST, 2);
/* opcode */
rtl8126_fiber_shift_bit_in(tp, cmd, 2);
/* phy address */
rtl8126_fiber_shift_bit_in(tp, phy_addr, 5);
/* phy reg */
rtl8126_fiber_shift_bit_in(tp, reg, 5);
}
static u8
rtl8126_fiber_cmdAddr(struct rtl8126_private *tp, u8 phy_addr, u32 reg)
{
u8 dev_addr = (reg >> 16) & 0x1F;
u16 addr = (u16)reg;
rtl8126_fiber_cmd(tp, R8126_FIBER_C45_OP_ADDR, phy_addr, dev_addr);
/* turn-around(TA) */
rtl8126_fiber_shift_bit_in(tp, R8126_FIBER_TA, 2);
rtl8126_fiber_shift_bit_in(tp, addr, 16);
rtl8126_fiber_dir(tp, 0);
rtl8126_fiber_get_mdio_bit(tp);
return dev_addr;
}
static void
rtl8126_fiber_reset_gpio_c45(struct rtl8126_private *tp)
{
rtl8126_set_mac_ocp_bit(tp, 0xDC4C, (BIT_7 | BIT_2));
/* init sfp interface */
rtl8126_clear_mac_ocp_bit(tp, 0xDC52, BIT_7);
rtl8126_set_mac_ocp_bit(tp, 0xDC52, BIT_2);
}
static void
rtl8126_fiber_write_common(struct rtl8126_private *tp, u16 val)
{
/* turn-around(TA) */
rtl8126_fiber_shift_bit_in(tp, R8126_FIBER_TA, 2);
/* write phy data */
rtl8126_fiber_shift_bit_in(tp, val, 16);
/* change to input mode */
rtl8126_fiber_dir(tp, 0);
rtl8126_fiber_get_mdio_bit(tp);
}
static void
rtl8126_fiber_mdio_write_gpio_c45(
struct rtl8126_private *tp,
u32 reg,
u16 val,
u8 phy_addr)
{
/* opcode write */
reg = rtl8126_fiber_cmdAddr(tp, phy_addr, reg);
rtl8126_fiber_cmd(tp, R8126_FIBER_C45_OP_W, phy_addr, reg);
rtl8126_fiber_write_common(tp, val);
}
static u16
rtl8126_fiber_read_common(struct rtl8126_private *tp)
{
u16 data = 0;
/* change to input mode */
rtl8126_fiber_dir(tp, 0);
/* TA 0 */
rtl8126_fiber_get_mdio_bit(tp);
/* read phy data */
data = rtl8126_fiber_shift_bit_out(tp);
rtl8126_fiber_get_mdio_bit(tp);
return data;
}
static u16
rtl8126_fiber_mdio_read_gpio_c45(
struct rtl8126_private *tp,
u32 reg,
u8 phy_addr)
{
reg = rtl8126_fiber_cmdAddr(tp, phy_addr, reg);
rtl8126_fiber_cmd(tp, R8126_FIBER_C45_OP_R, phy_addr, reg);
return rtl8126_fiber_read_common(tp);
}
void
rtl8126_fiber_mdio_write(
struct rtl8126_private *tp,
u32 reg,
u16 val)
{
switch(tp->HwFiberStat) {
case FIBER_STAT_CONNECT_GPO_C45:
return rtl8126_fiber_mdio_write_gpio_c45(tp, reg, val, 0);
default:
return;
}
}
u16
rtl8126_fiber_mdio_read(
struct rtl8126_private *tp,
u32 reg)
{
switch(tp->HwFiberStat) {
case FIBER_STAT_CONNECT_GPO_C45:
return rtl8126_fiber_mdio_read_gpio_c45(tp, reg, 0);
default:
return 0xffff;
}
}
static void
rtl8126_fiber_clear_and_set_phy_bit(struct rtl8126_private *tp, u32 addr, u16 clearmask, u16 setmask)
{
u16 PhyRegValue;
PhyRegValue = rtl8126_fiber_mdio_read(tp, addr);
PhyRegValue &= ~clearmask;
PhyRegValue |= setmask;
rtl8126_fiber_mdio_write(tp, addr, PhyRegValue);
}
static void
rtl8126_fiber_clear_phy_bit(struct rtl8126_private *tp, u32 addr, u16 mask)
{
rtl8126_fiber_clear_and_set_phy_bit(tp, addr, mask, 0);
}
static void
rtl8126_fiber_set_phy_bit(struct rtl8126_private *tp, u32 addr, u16 mask)
{
rtl8126_fiber_clear_and_set_phy_bit(tp, addr, 0, mask);
}
#define R8126_MAKE_C45_ADDR(_mmd, _addr) (_mmd << 16 | _addr)
static void
rtl8126_fiber_set_ra_8251b(struct rtl8126_private *tp)
{
struct pci_dev *pdev = tp->pci_dev;
u16 const svid = pdev->subsystem_vendor;
rtl8126_fiber_clear_and_set_phy_bit(tp,
R8126_MAKE_C45_ADDR(30, 0x6973),
0x00FF,
(svid == PCI_VENDOR_ID_DELL) ?
0x03 : 0x12);
rtl8126_fiber_clear_and_set_phy_bit(tp,
R8126_MAKE_C45_ADDR(30, 0x6974),
0x00FF,
0x0005);
rtl8126_fiber_clear_and_set_phy_bit(tp,
R8126_MAKE_C45_ADDR(30, 0x6975),
0x00FF,
0x0008);
}
static void
rtl8126_fiber_set_ra(struct rtl8126_private *tp)
{
switch (tp->HwFiberModeVer) {
case FIBER_MODE_RTL8126_RTL8251B:
rtl8126_fiber_set_ra_8251b(tp);
break;
}
}
static void
rtl8126_fiber_phy_reset_8251b(struct rtl8126_private *tp)
{
u16 PhyRegValue;
u32 Timeout;
rtl8126_fiber_set_phy_bit(tp, R8126_MAKE_C45_ADDR(0x01, 0x00), BIT_15);
Timeout = 0;
do {
udelay(1000);
PhyRegValue = rtl8126_fiber_mdio_read(tp, R8126_MAKE_C45_ADDR(0x01, 0x00));
Timeout++;
} while ((PhyRegValue & BIT_15) && (Timeout < 20));
}
static void
rtl8126_fiber_phy_reset(struct rtl8126_private *tp)
{
switch (tp->HwFiberModeVer) {
case FIBER_MODE_RTL8126_RTL8251B:
rtl8126_fiber_phy_reset_8251b(tp);
break;
}
}
static void
rtl8126_hw_rtl8251b_phy_config(struct rtl8126_private *tp)
{
rtl8126_fiber_reset_gpio_c45(tp);
rtl8126_fiber_set_ra(tp);
rtl8126_fiber_clear_phy_bit(tp, R8126_MAKE_C45_ADDR(0x07, 0x3C), (BIT_2 | BIT_1));
rtl8126_fiber_clear_phy_bit(tp, R8126_MAKE_C45_ADDR(0x07, 0x3E), (BIT_1 | BIT_0));
rtl8126_fiber_phy_reset(tp);
}
void
rtl8126_hw_fiber_phy_config(struct rtl8126_private *tp)
{
switch (tp->HwFiberModeVer) {
case FIBER_MODE_RTL8126_RTL8251B:
rtl8126_hw_rtl8251b_phy_config(tp);
break;
}
}
#define RTL8251B_PHY_ID_1 0x001C
#define RTL8251B_PHY_ID_2 0xC868
static u32
rtl8126_fiber_get_connect_status_8251b(struct rtl8126_private *tp)
{
int i;
int const checkcnt = 4;
rtl8126_fiber_reset_gpio_c45(tp);
for (i = 0; i < checkcnt; i++) {
if (RTL8251B_PHY_ID_1 != rtl8126_fiber_mdio_read_gpio_c45(tp, R8126_MAKE_C45_ADDR(0x01, 0x02), 0) ||
RTL8251B_PHY_ID_2 != rtl8126_fiber_mdio_read_gpio_c45(tp, R8126_MAKE_C45_ADDR(0x01, 0x03), 0))
return FIBER_STAT_DISCONNECT;
}
return FIBER_STAT_CONNECT_GPO_C45;
}
static u32
rtl8126_fiber_get_connect_status(struct rtl8126_private *tp)
{
switch (tp->HwFiberModeVer) {
case FIBER_MODE_RTL8126_RTL8251B:
return rtl8126_fiber_get_connect_status_8251b(tp);
default:
return FIBER_STAT_NOT_CHECKED;
}
}
void
rtl8126_check_fiber_mode_support(struct rtl8126_private *tp)
{
switch(tp->mcfg) {
case CFG_METHOD_3: {
u8 tmp = (u8)rtl8126_mac_ocp_read(tp, 0xD006);
if (tmp == 0x03)
tp->HwFiberModeVer = FIBER_MODE_RTL8126_RTL8251B;
}
break;
}
if (HW_FIBER_MODE_ENABLED(tp))
tp->HwFiberStat = rtl8126_fiber_get_connect_status(tp);
}
unsigned int
rtl8126_fiber_link_ok(struct net_device *dev)
{
struct rtl8126_private *tp = netdev_priv(dev);
u16 status;
switch (tp->HwFiberStat) {
case FIBER_STAT_CONNECT_GPO_C45:
status = rtl8126_fiber_mdio_read(tp, R8126_MAKE_C45_ADDR(30, 0x758D));
if (status != USHRT_MAX && status & BIT_1)
return 1;
else
return 0;
break;
default:
return 0;
}
}

View File

@ -0,0 +1,63 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_R8126_FIBER_H
#define _LINUX_R8126_FIBER_H
enum {
FIBER_MODE_NIC_ONLY = 0,
FIBER_MODE_RTL8126_RTL8251B,
FIBER_MODE_MAX
};
enum {
FIBER_STAT_NOT_CHECKED = 0,
FIBER_STAT_DISCONNECT,
FIBER_STAT_CONNECT_GPO_C45,
FIBER_STAT_MAX
};
#define HW_FIBER_MODE_ENABLED(_M) ((_M)->HwFiberModeVer > 0)
#define HW_FIBER_STATUS_CONNECTED(_M) (((_M)->HwFiberStat == FIBER_STAT_CONNECT_GPO_C45))
#define HW_FIBER_STATUS_DISCONNECTED(_M) ((_M)->HwFiberStat == FIBER_STAT_DISCONNECT)
struct rtl8126_private;
void rtl8126_hw_fiber_phy_config(struct rtl8126_private *tp);
void rtl8126_check_fiber_mode_support(struct rtl8126_private *tp);
void rtl8126_fiber_mdio_write( struct rtl8126_private *tp, u32 reg, u16 val);
u16 rtl8126_fiber_mdio_read(struct rtl8126_private *tp, u32 reg);
unsigned int rtl8126_fiber_link_ok(struct net_device *dev);
#endif /* _LINUX_R8126_FIBER_H */

View File

@ -0,0 +1,264 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
################################################################################
#
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/version.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include "r8126_firmware.h"
enum rtl_fw_opcode {
PHY_READ = 0x0,
PHY_DATA_OR = 0x1,
PHY_DATA_AND = 0x2,
PHY_BJMPN = 0x3,
PHY_MDIO_CHG = 0x4,
PHY_CLEAR_READCOUNT = 0x7,
PHY_WRITE = 0x8,
PHY_READCOUNT_EQ_SKIP = 0x9,
PHY_COMP_EQ_SKIPN = 0xa,
PHY_COMP_NEQ_SKIPN = 0xb,
PHY_WRITE_PREVIOUS = 0xc,
PHY_SKIPN = 0xd,
PHY_DELAY_MS = 0xe,
};
struct fw_info {
u32 magic;
char version[RTL8126_VER_SIZE];
__le32 fw_start;
__le32 fw_len;
u8 chksum;
} __packed;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,16,0)
#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
#endif
#define FW_OPCODE_SIZE sizeof_field(struct rtl8126_fw_phy_action, code[0])
static bool rtl8126_fw_format_ok(struct rtl8126_fw *rtl_fw)
{
const struct firmware *fw = rtl_fw->fw;
struct fw_info *fw_info = (struct fw_info *)fw->data;
struct rtl8126_fw_phy_action *pa = &rtl_fw->phy_action;
if (fw->size < FW_OPCODE_SIZE)
return false;
if (!fw_info->magic) {
size_t i, size, start;
u8 checksum = 0;
if (fw->size < sizeof(*fw_info))
return false;
for (i = 0; i < fw->size; i++)
checksum += fw->data[i];
if (checksum != 0)
return false;
start = le32_to_cpu(fw_info->fw_start);
if (start > fw->size)
return false;
size = le32_to_cpu(fw_info->fw_len);
if (size > (fw->size - start) / FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, fw_info->version, RTL8126_VER_SIZE);
pa->code = (__le32 *)(fw->data + start);
pa->size = size;
} else {
if (fw->size % FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, rtl_fw->fw_name, RTL8126_VER_SIZE);
pa->code = (__le32 *)fw->data;
pa->size = fw->size / FW_OPCODE_SIZE;
}
return true;
}
static bool rtl8126_fw_data_ok(struct rtl8126_fw *rtl_fw)
{
struct rtl8126_fw_phy_action *pa = &rtl_fw->phy_action;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 val = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
switch (action >> 28) {
case PHY_READ:
case PHY_DATA_OR:
case PHY_DATA_AND:
case PHY_CLEAR_READCOUNT:
case PHY_WRITE:
case PHY_WRITE_PREVIOUS:
case PHY_DELAY_MS:
break;
case PHY_MDIO_CHG:
if (val > 1)
goto out;
break;
case PHY_BJMPN:
if (regno > index)
goto out;
break;
case PHY_READCOUNT_EQ_SKIP:
if (index + 2 >= pa->size)
goto out;
break;
case PHY_COMP_EQ_SKIPN:
case PHY_COMP_NEQ_SKIPN:
case PHY_SKIPN:
if (index + 1 + regno >= pa->size)
goto out;
break;
default:
dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
return false;
}
}
return true;
out:
dev_err(rtl_fw->dev, "Out of range of firmware\n");
return false;
}
void rtl8126_fw_write_firmware(struct rtl8126_private *tp, struct rtl8126_fw *rtl_fw)
{
struct rtl8126_fw_phy_action *pa = &rtl_fw->phy_action;
rtl8126_fw_write_t fw_write = rtl_fw->phy_write;
rtl8126_fw_read_t fw_read = rtl_fw->phy_read;
int predata = 0, count = 0;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 data = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
enum rtl_fw_opcode opcode = action >> 28;
if (!action)
break;
switch (opcode) {
case PHY_READ:
predata = fw_read(tp, regno);
count++;
break;
case PHY_DATA_OR:
predata |= data;
break;
case PHY_DATA_AND:
predata &= data;
break;
case PHY_BJMPN:
index -= (regno + 1);
break;
case PHY_MDIO_CHG:
if (data) {
fw_write = rtl_fw->mac_mcu_write;
fw_read = rtl_fw->mac_mcu_read;
} else {
fw_write = rtl_fw->phy_write;
fw_read = rtl_fw->phy_read;
}
break;
case PHY_CLEAR_READCOUNT:
count = 0;
break;
case PHY_WRITE:
fw_write(tp, regno, data);
break;
case PHY_READCOUNT_EQ_SKIP:
if (count == data)
index++;
break;
case PHY_COMP_EQ_SKIPN:
if (predata == data)
index += regno;
break;
case PHY_COMP_NEQ_SKIPN:
if (predata != data)
index += regno;
break;
case PHY_WRITE_PREVIOUS:
fw_write(tp, regno, predata);
break;
case PHY_SKIPN:
index += regno;
break;
case PHY_DELAY_MS:
mdelay(data);
break;
}
}
}
void rtl8126_fw_release_firmware(struct rtl8126_fw *rtl_fw)
{
release_firmware(rtl_fw->fw);
}
int rtl8126_fw_request_firmware(struct rtl8126_fw *rtl_fw)
{
int rc;
rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
if (rc < 0)
goto out;
if (!rtl8126_fw_format_ok(rtl_fw) || !rtl8126_fw_data_ok(rtl_fw)) {
release_firmware(rtl_fw->fw);
rc = -EINVAL;
goto out;
}
return 0;
out:
dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
rtl_fw->fw_name, rc);
return rc;
}

View File

@ -0,0 +1,68 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_R8126_FIRMWARE_H
#define _LINUX_R8126_FIRMWARE_H
#include <linux/device.h>
#include <linux/firmware.h>
struct rtl8126_private;
typedef void (*rtl8126_fw_write_t)(struct rtl8126_private *tp, u16 reg, u16 val);
typedef u32 (*rtl8126_fw_read_t)(struct rtl8126_private *tp, u16 reg);
#define RTL8126_VER_SIZE 32
struct rtl8126_fw {
rtl8126_fw_write_t phy_write;
rtl8126_fw_read_t phy_read;
rtl8126_fw_write_t mac_mcu_write;
rtl8126_fw_read_t mac_mcu_read;
const struct firmware *fw;
const char *fw_name;
struct device *dev;
char version[RTL8126_VER_SIZE];
struct rtl8126_fw_phy_action {
__le32 *code;
size_t size;
} phy_action;
};
int rtl8126_fw_request_firmware(struct rtl8126_fw *rtl_fw);
void rtl8126_fw_release_firmware(struct rtl8126_fw *rtl_fw);
void rtl8126_fw_write_firmware(struct rtl8126_private *tp, struct rtl8126_fw *rtl_fw);
#endif /* _LINUX_R8126_FIRMWARE_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,944 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
################################################################################
#
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/mii.h>
#include <linux/in.h>
#include <linux/ethtool.h>
#include <linux/rtnetlink.h>
#include "r8126.h"
#include "r8126_ptp.h"
static void rtl8126_wait_clkadj_ready(struct rtl8126_private *tp)
{
int i;
for (i = 0; i < R8126_CHANNEL_WAIT_COUNT; i++)
if (!(rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CLK_CFG_8126) & CLKADJ_MODE_SET))
break;
}
static void rtl8126_set_clkadj_mode(struct rtl8126_private *tp, u16 cmd)
{
rtl8126_clear_and_set_eth_phy_ocp_bit(tp,
PTP_CLK_CFG_8126,
BIT_3 | BIT_2 | BIT_1,
CLKADJ_MODE_SET | cmd);
rtl8126_wait_clkadj_ready(tp);
}
static int _rtl8126_phc_gettime(struct rtl8126_private *tp, struct timespec64 *ts64)
{
unsigned long flags;
spin_lock_irqsave(&tp->phy_lock, flags);
//Direct Read
rtl8126_set_clkadj_mode(tp, DIRECT_READ);
/* nanoseconds */
//Ns[29:16] E414[13:0]
ts64->tv_nsec = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_NS_HI_8126) & 0x3fff;
ts64->tv_nsec <<= 16;
//Ns[15:0] E412[15:0]
ts64->tv_nsec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_NS_LO_8126);
/* seconds */
//S[47:32] E41A[15:0]
ts64->tv_sec = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_S_HI_8126);
ts64->tv_sec <<= 16;
//S[31:16] E418[15:0]
ts64->tv_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_S_MI_8126);
ts64->tv_sec <<= 16;
//S[15:0] E416[15:0]
ts64->tv_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_S_LO_8126);
spin_unlock_irqrestore(&tp->phy_lock, flags);
return 0;
}
static int _rtl8126_phc_settime(struct rtl8126_private *tp, const struct timespec64 *ts64)
{
unsigned long flags;
spin_lock_irqsave(&tp->phy_lock, flags);
/* nanoseconds */
//Ns[15:0] E412[15:0]
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_NS_LO_8126, ts64->tv_nsec);
//Ns[29:16] E414[13:0]
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_NS_HI_8126, (ts64->tv_nsec & 0x3fff0000) >> 16);
/* seconds */
//S[15:0] E416[15:0]
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_S_LO_8126, ts64->tv_sec);
//S[31:16] E418[15:0]
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_S_MI_8126, (ts64->tv_sec >> 16));
//S[47:32] E41A[15:0]
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_S_HI_8126, (ts64->tv_sec >> 32));
//Direct Write
rtl8126_set_clkadj_mode(tp, DIRECT_WRITE);
spin_unlock_irqrestore(&tp->phy_lock, flags);
return 0;
}
static int _rtl8126_phc_adjtime(struct rtl8126_private *tp, s64 delta)
{
unsigned long flags;
struct timespec64 d;
bool negative;
u64 tohw;
u32 nsec;
u64 sec;
if (delta < 0) {
negative = true;
tohw = -delta;
} else {
negative = false;
tohw = delta;
}
d = ns_to_timespec64(tohw);
nsec = d.tv_nsec;
sec = d.tv_sec;
nsec &= 0x3fffffff;
sec &= 0x0000ffffffffffff;
spin_lock_irqsave(&tp->phy_lock, flags);
/* nanoseconds */
//Ns[15:0] E412[15:0]
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_NS_LO_8126, nsec);
//Ns[29:16] E414[13:0]
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_NS_HI_8126, (nsec >> 16));
/* seconds */
//S[15:0] E416[15:0]
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_S_LO_8126, sec);
//S[31:16] E418[15:0]
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_S_MI_8126, (sec >> 16));
//S[47:32] E41A[15:0]
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_S_HI_8126, (sec >> 32));
if (negative)
rtl8126_set_clkadj_mode(tp, DECREMENT_STEP);
else
rtl8126_set_clkadj_mode(tp, INCREMENT_STEP);
spin_unlock_irqrestore(&tp->phy_lock, flags);
return 0;
}
static int rtl8126_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct rtl8126_private *tp = container_of(ptp, struct rtl8126_private, ptp_clock_info);
int ret;
//netif_info(tp, drv, tp->dev, "phc adjust time\n");
ret = _rtl8126_phc_adjtime(tp, delta);
return ret;
}
/*
* delta = delta * 10^6 ppm = delta * 10^9 ppb (in this equation ppm and ppb are not variable)
*
* in adjfreq ppb is a variable
* ppb = delta * 10^9
* delta = ppb / 10^9
* rate_value = |delta| * 2^32 = |ppb| / 10^9 * 2^32 = (|ppb| << 32) / 10^9
*/
static int _rtl8126_phc_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
{
struct rtl8126_private *tp = container_of(ptp, struct rtl8126_private, ptp_clock_info);
unsigned long flags;
u32 rate_value;
if (ppb < 0) {
rate_value = ((u64)-ppb << 32) / 1000000000;
rate_value = ~rate_value + 1;
} else
rate_value = ((u64)ppb << 32) / 1000000000;
spin_lock_irqsave(&tp->phy_lock, flags);
/* nanoseconds */
//Ns[15:0] E412[15:0]
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_NS_LO_8126, rate_value);
//Ns[22:16] E414[13:0]
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_NS_HI_8126, (rate_value & 0x003f0000) >> 16);
rtl8126_set_clkadj_mode(tp, RATE_WRITE);
spin_unlock_irqrestore(&tp->phy_lock, flags);
return 0;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,2,0)
static int rtl8126_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
s32 ppb = scaled_ppm_to_ppb(scaled_ppm);
if (ppb > ptp->max_adj || ppb < -ptp->max_adj)
return -EINVAL;
_rtl8126_phc_adjfreq(ptp, ppb);
return 0;
}
#else
static int rtl8126_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
{
//struct rtl8126_private *tp = container_of(ptp, struct rtl8126_private, ptp_clock_info);
//netif_info(tp, drv, tp->dev, "phc adjust freq\n");
if (delta > ptp->max_adj || delta < -ptp->max_adj)
return -EINVAL;
_rtl8126_phc_adjfreq(ptp, delta);
return 0;
}
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6,2,0) */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
static int rtl8126_phc_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts64,
struct ptp_system_timestamp *sts)
{
struct rtl8126_private *tp = container_of(ptp, struct rtl8126_private, ptp_clock_info);
int ret;
//netif_info(tp, drv, tp->dev, "phc get ts\n");
ptp_read_system_prets(sts);
ret = _rtl8126_phc_gettime(tp, ts64);
ptp_read_system_postts(sts);
return ret;
}
#else
static int rtl8126_phc_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts64)
{
struct rtl8126_private *tp = container_of(ptp, struct rtl8126_private, ptp_clock_info);
int ret;
//netif_info(tp, drv, tp->dev, "phc get ts\n");
ret = _rtl8126_phc_gettime(tp, ts64);
return ret;
}
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) */
static int rtl8126_phc_settime(struct ptp_clock_info *ptp,
const struct timespec64 *ts64)
{
struct rtl8126_private *tp = container_of(ptp, struct rtl8126_private, ptp_clock_info);
int ret;
//netif_info(tp, drv, tp->dev, "phc set ts\n");
ret = _rtl8126_phc_settime(tp, ts64);
return ret;
}
static void _rtl8126_phc_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on)
{
struct rtl8126_private *tp = container_of(ptp, struct rtl8126_private, ptp_clock_info);
unsigned long flags;
u16 phy_ocp_data;
if (on) {
tp->pps_enable = 1;
rtl8126_clear_mac_ocp_bit(tp, 0xDC00, BIT_6);
rtl8126_clear_mac_ocp_bit(tp, 0xDC20, BIT_1);
spin_lock_irqsave(&tp->phy_lock, flags);
/* Set periodic pulse 1pps */
/* E432[8:0] = 0x017d */
phy_ocp_data = rtl8126_mdio_direct_read_phy_ocp(tp, 0xE432);
phy_ocp_data &= 0xFE00;
phy_ocp_data |= 0x017d;
rtl8126_mdio_direct_write_phy_ocp(tp, 0xE432, phy_ocp_data);
rtl8126_mdio_direct_write_phy_ocp(tp, 0xE434, 0x7840);
/* E436[8:0] = 0xbe */
phy_ocp_data = rtl8126_mdio_direct_read_phy_ocp(tp, 0xE436);
phy_ocp_data &= 0xFE00;
phy_ocp_data |= 0xbe;
rtl8126_mdio_direct_write_phy_ocp(tp, 0xE436, phy_ocp_data);
rtl8126_mdio_direct_write_phy_ocp(tp, 0xE438, 0xbc20);
spin_unlock_irqrestore(&tp->phy_lock, flags);
/* start hrtimer */
hrtimer_start(&tp->pps_timer, 1000000000, HRTIMER_MODE_REL);
} else
tp->pps_enable = 0;
}
static int rtl8126_phc_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on)
{
switch (rq->type) {
case PTP_CLK_REQ_PPS:
_rtl8126_phc_enable(ptp, rq, on);
return 0;
default:
return -EOPNOTSUPP;
}
}
static void rtl8126_ptp_enable_config(struct rtl8126_private *tp)
{
if (tp->syncE_en)
rtl8126_set_eth_phy_ocp_bit(tp, PTP_SYNCE_CTL, BIT_0);
else
rtl8126_clear_eth_phy_ocp_bit(tp, PTP_SYNCE_CTL, BIT_0);
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CTL, PTP_CTL_TYPE_3 | BIT_12);
rtl8126_set_eth_phy_ocp_bit(tp, 0xA640, BIT_15);
}
int rtl8126_get_ts_info(struct net_device *netdev,
struct ethtool_ts_info *info)
{
struct rtl8126_private *tp = netdev_priv(netdev);
/* we always support timestamping disabled */
info->rx_filters = BIT(HWTSTAMP_FILTER_NONE);
if (tp->HwSuppPtpVer == 0)
return ethtool_op_get_ts_info(netdev, info);
info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_SOFTWARE |
SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
if (tp->ptp_clock)
info->phc_index = ptp_clock_index(tp->ptp_clock);
else
info->phc_index = -1;
info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) |
BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
BIT(HWTSTAMP_FILTER_PTP_V2_SYNC) |
BIT(HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
BIT(HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
BIT(HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ);
return 0;
}
static const struct ptp_clock_info rtl_ptp_clock_info = {
.owner = THIS_MODULE,
.n_alarm = 0,
.n_ext_ts = 0,
.n_per_out = 0,
.n_pins = 0,
.pps = 1,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,2,0)
.adjfine = rtl8126_ptp_adjfine,
#else
.adjfreq = rtl8126_phc_adjfreq,
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6,2,0) */
.adjtime = rtl8126_phc_adjtime,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
.gettimex64 = rtl8126_phc_gettime,
#else
.gettime64 = rtl8126_phc_gettime,
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) */
.settime64 = rtl8126_phc_settime,
.enable = rtl8126_phc_enable,
};
static u16 rtl8126_ptp_get_tx_msgtype(struct rtl8126_private *tp)
{
u16 tx_ts_ready = 0;
int i;
for (i = 0; i < R8126_CHANNEL_WAIT_COUNT; i++) {
tx_ts_ready = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_STA) & 0xF000;
if (tx_ts_ready)
break;
}
switch (tx_ts_ready) {
case TX_TS_PDLYRSP_RDY:
return PTP_MSGTYPE_PDELAY_RESP;
case TX_TS_PDLYREQ_RDY:
return PTP_MSGTYPE_PDELAY_REQ;
case TX_TS_DLYREQ_RDY:
return PTP_MSGTYPE_DELAY_REQ;
case TX_TS_SYNC_RDY:
default:
return PTP_MSGTYPE_SYNC;
}
}
/*
static u16 rtl8126_ptp_get_rx_msgtype(struct rtl8126_private *tp)
{
u16 rx_ts_ready = 0;
int i;
for (i = 0; i < R8126_CHANNEL_WAIT_COUNT; i++) {
rx_ts_ready = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_STA) & 0x0F00;
if (rx_ts_ready)
break;
}
switch (rx_ts_ready) {
case RX_TS_PDLYRSP_RDY:
return PTP_MSGTYPE_PDELAY_RESP;
case RX_TS_PDLYREQ_RDY:
return PTP_MSGTYPE_PDELAY_REQ;
case RX_TS_DLYREQ_RDY:
return PTP_MSGTYPE_DELAY_REQ;
case RX_TS_SYNC_RDY:
default:
return PTP_MSGTYPE_SYNC;
}
}
*/
static void rtl8126_wait_trx_ts_ready(struct rtl8126_private *tp)
{
int i;
for (i = 0; i < R8126_CHANNEL_WAIT_COUNT; i++)
if (!(rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_STA) & TRX_TS_RD))
break;
}
static void rtl8126_set_trx_ts_cmd(struct rtl8126_private *tp, u16 cmd)
{
rtl8126_clear_and_set_eth_phy_ocp_bit(tp,
PTP_TRX_TS_STA,
TRXTS_SEL | BIT_3 | BIT_2,
TRX_TS_RD | cmd);
rtl8126_wait_trx_ts_ready(tp);
}
static void rtl8126_ptp_egresstime(struct rtl8126_private *tp, struct timespec64 *ts64)
{
u16 msgtype;
msgtype = rtl8126_ptp_get_tx_msgtype(tp);
msgtype <<= 2;
rtl8126_set_trx_ts_cmd(tp, (msgtype | BIT_4));
/* nanoseconds */
//Ns[29:16] E448[13:0]
ts64->tv_nsec = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_NS_HI) & 0x3fff;
ts64->tv_nsec <<= 16;
//Ns[15:0] E446[15:0]
ts64->tv_nsec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_NS_LO);
/* seconds */
//S[47:32] E44E[15:0]
ts64->tv_sec = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_S_HI);
ts64->tv_sec <<= 16;
//S[31:16] E44C[15:0]
ts64->tv_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_S_MI);
ts64->tv_sec <<= 16;
//S[15:0] E44A[15:0]
ts64->tv_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_S_LO);
}
static void rtl8126_ptp_ingresstime(struct rtl8126_private *tp, struct timespec64 *ts64, u8 type)
{
u16 msgtype;
switch (type) {
case PTP_MSGTYPE_PDELAY_RESP:
case PTP_MSGTYPE_PDELAY_REQ:
case PTP_MSGTYPE_DELAY_REQ:
case PTP_MSGTYPE_SYNC:
msgtype = type << 2;
break;
default:
return;
}
rtl8126_set_trx_ts_cmd(tp, (TRXTS_SEL | msgtype | BIT_4));
/* nanoseconds */
//Ns[29:16] E448[13:0]
ts64->tv_nsec = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_NS_HI) & 0x3fff;
ts64->tv_nsec <<= 16;
//Ns[15:0] E446[15:0]
ts64->tv_nsec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_NS_LO);
/* seconds */
//S[47:32] E44E[15:0]
ts64->tv_sec = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_S_HI);
ts64->tv_sec <<= 16;
//S[31:16] E44C[15:0]
ts64->tv_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_S_MI);
ts64->tv_sec <<= 16;
//S[15:0] E44A[15:0]
ts64->tv_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_S_LO);
}
static void rtl8126_ptp_tx_hwtstamp(struct rtl8126_private *tp)
{
struct sk_buff *skb = tp->ptp_tx_skb;
struct skb_shared_hwtstamps shhwtstamps = { 0 };
struct timespec64 ts64;
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_INSR, TX_TX_INTR);
rtl8126_ptp_egresstime(tp, &ts64);
/* Upper 32 bits contain s, lower 32 bits contain ns. */
shhwtstamps.hwtstamp = ktime_set(ts64.tv_sec,
ts64.tv_nsec);
/* Clear the lock early before calling skb_tstamp_tx so that
* applications are not woken up before the lock bit is clear. We use
* a copy of the skb pointer to ensure other threads can't change it
* while we're notifying the stack.
*/
tp->ptp_tx_skb = NULL;
clear_bit_unlock(__RTL8126_PTP_TX_IN_PROGRESS, &tp->state);
/* Notify the stack and free the skb after we've unlocked */
skb_tstamp_tx(skb, &shhwtstamps);
dev_kfree_skb_any(skb);
}
#define RTL8126_PTP_TX_TIMEOUT (HZ * 15)
static void rtl8126_ptp_tx_work(struct work_struct *work)
{
struct rtl8126_private *tp = container_of(work, struct rtl8126_private,
ptp_tx_work);
unsigned long flags;
if (!tp->ptp_tx_skb)
return;
if (time_is_before_jiffies(tp->ptp_tx_start +
RTL8126_PTP_TX_TIMEOUT)) {
dev_kfree_skb_any(tp->ptp_tx_skb);
tp->ptp_tx_skb = NULL;
clear_bit_unlock(__RTL8126_PTP_TX_IN_PROGRESS, &tp->state);
tp->tx_hwtstamp_timeouts++;
/* Clear the tx valid bit in TSYNCTXCTL register to enable
* interrupt
*/
spin_lock_irqsave(&tp->phy_lock, flags);
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_INSR, TX_TX_INTR);
spin_unlock_irqrestore(&tp->phy_lock, flags);
return;
}
spin_lock_irqsave(&tp->phy_lock, flags);
if (rtl8126_mdio_direct_read_phy_ocp(tp, PTP_INSR) & TX_TX_INTR) {
rtl8126_ptp_tx_hwtstamp(tp);
spin_unlock_irqrestore(&tp->phy_lock, flags);
} else {
spin_unlock_irqrestore(&tp->phy_lock, flags);
/* reschedule to check later */
schedule_work(&tp->ptp_tx_work);
}
}
static int rtl8126_hwtstamp_enable(struct rtl8126_private *tp, bool enable)
{
unsigned long flags;
spin_lock_irqsave(&tp->phy_lock, flags);
if (enable) {
//trx timestamp interrupt enable
rtl8126_set_eth_phy_ocp_bit(tp, PTP_INER, BIT_2 | BIT_3);
//set isr clear mode
rtl8126_set_eth_phy_ocp_bit(tp, PTP_GEN_CFG, BIT_0);
//clear ptp isr
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_INSR, 0xFFFF);
//enable ptp
rtl8126_ptp_enable_config(tp);
//rtl8126_set_local_time(tp);
} else {
/* trx timestamp interrupt disable */
rtl8126_clear_eth_phy_ocp_bit(tp, PTP_INER, BIT_2 | BIT_3);
/* disable ptp */
rtl8126_clear_eth_phy_ocp_bit(tp, PTP_SYNCE_CTL, BIT_0);
rtl8126_clear_eth_phy_ocp_bit(tp, PTP_CTL, BIT_0);
rtl8126_set_eth_phy_ocp_bit(tp, 0xA640, BIT_15);
}
spin_unlock_irqrestore(&tp->phy_lock, flags);
return 0;
}
void rtl8126_set_local_time(struct rtl8126_private *tp)
{
struct timespec64 ts64;
//set system time
ktime_get_real_ts64(&ts64);
_rtl8126_phc_settime(tp, &ts64);
}
static long rtl8126_ptp_create_clock(struct rtl8126_private *tp)
{
struct net_device *netdev = tp->dev;
long err;
if (!IS_ERR_OR_NULL(tp->ptp_clock))
return 0;
if (tp->HwSuppPtpVer == 0) {
tp->ptp_clock = NULL;
return -EOPNOTSUPP;
}
tp->ptp_clock_info = rtl_ptp_clock_info;
tp->ptp_clock_info.max_adj = 488281;//0x1FFFFF * 10^9 / 2^32
snprintf(tp->ptp_clock_info.name, sizeof(tp->ptp_clock_info.name),
"%pm", tp->dev->dev_addr);
tp->ptp_clock = ptp_clock_register(&tp->ptp_clock_info, &tp->pci_dev->dev);
if (IS_ERR(tp->ptp_clock)) {
err = PTR_ERR(tp->ptp_clock);
tp->ptp_clock = NULL;
netif_err(tp, drv, tp->dev, "ptp_clock_register failed\n");
return err;
} else
netif_info(tp, drv, tp->dev, "registered PHC device on %s\n", netdev->name);
return 0;
}
static enum hrtimer_restart
rtl8126_hrtimer_for_pps(struct hrtimer *timer) {
struct rtl8126_private *tp = container_of(timer, struct rtl8126_private, pps_timer);
u16 tai_cfg = BIT_8 | BIT_3 | BIT_1 | BIT_0;
s64 pps_sec;
if (tp->pps_enable)
{
unsigned long flags;
spin_lock_irqsave(&tp->phy_lock, flags);
//Direct Read
rtl8126_set_clkadj_mode(tp, DIRECT_READ);
pps_sec = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_S_HI_8126);
pps_sec <<= 16;
pps_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_S_MI_8126);
pps_sec <<= 16;
pps_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_S_LO_8126);
pps_sec++;
//E42A[15:0]
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_TAI_TS_S_LO, pps_sec & 0xffff);
//E42C[31:16]
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_TAI_TS_S_HI, (pps_sec & 0xffff0000) >> 16);
//Periodic Tai start
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_TAI_CFG, tai_cfg);
spin_unlock_irqrestore(&tp->phy_lock, flags);
hrtimer_forward_now(&tp->pps_timer, 1000000000); //rekick
return HRTIMER_RESTART;
} else
return HRTIMER_NORESTART;
}
void rtl8126_ptp_reset(struct rtl8126_private *tp)
{
if (!tp->ptp_clock)
return;
netif_info(tp, drv, tp->dev, "reset PHC clock\n");
rtl8126_hwtstamp_enable(tp, false);
}
void rtl8126_ptp_init(struct rtl8126_private *tp)
{
/* obtain a PTP device, or re-use an existing device */
if (rtl8126_ptp_create_clock(tp))
return;
/* we have a clock so we can initialize work now */
INIT_WORK(&tp->ptp_tx_work, rtl8126_ptp_tx_work);
/* init a hrtimer for pps */
tp->pps_enable = 0;
hrtimer_init(&tp->pps_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
tp->pps_timer.function = rtl8126_hrtimer_for_pps;
/* reset the PTP related hardware bits */
rtl8126_ptp_reset(tp);
return;
}
void rtl8126_ptp_suspend(struct rtl8126_private *tp)
{
if (!tp->ptp_clock)
return;
netif_info(tp, drv, tp->dev, "suspend PHC clock\n");
rtl8126_hwtstamp_enable(tp, false);
/* ensure that we cancel any pending PTP Tx work item in progress */
cancel_work_sync(&tp->ptp_tx_work);
hrtimer_cancel(&tp->pps_timer);
}
void rtl8126_ptp_stop(struct rtl8126_private *tp)
{
struct net_device *netdev = tp->dev;
netif_info(tp, drv, tp->dev, "stop PHC clock\n");
/* first, suspend PTP activity */
rtl8126_ptp_suspend(tp);
/* disable the PTP clock device */
if (tp->ptp_clock) {
ptp_clock_unregister(tp->ptp_clock);
tp->ptp_clock = NULL;
netif_info(tp, drv, tp->dev, "removed PHC on %s\n",
netdev->name);
}
}
static int rtl8126_set_tstamp(struct net_device *netdev, struct ifreq *ifr)
{
struct rtl8126_private *tp = netdev_priv(netdev);
struct hwtstamp_config config;
bool hwtstamp = 0;
//netif_info(tp, drv, tp->dev, "ptp set ts\n");
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
return -EFAULT;
if (config.flags)
return -EINVAL;
switch (config.tx_type) {
case HWTSTAMP_TX_ON:
hwtstamp = 1;
break;
case HWTSTAMP_TX_OFF:
break;
case HWTSTAMP_TX_ONESTEP_SYNC:
default:
return -ERANGE;
}
switch (config.rx_filter) {
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
hwtstamp = 1;
tp->flags |= RTL_FLAG_RX_HWTSTAMP_ENABLED;
break;
case HWTSTAMP_FILTER_NONE:
tp->flags &= ~RTL_FLAG_RX_HWTSTAMP_ENABLED;
break;
default:
tp->flags &= ~RTL_FLAG_RX_HWTSTAMP_ENABLED;
return -ERANGE;
}
if (tp->hwtstamp_config.tx_type != config.tx_type ||
tp->hwtstamp_config.rx_filter != config.rx_filter) {
tp->hwtstamp_config = config;
rtl8126_hwtstamp_enable(tp, hwtstamp);
}
return copy_to_user(ifr->ifr_data, &config,
sizeof(config)) ? -EFAULT : 0;
}
static int rtl8126_get_tstamp(struct net_device *netdev, struct ifreq *ifr)
{
struct rtl8126_private *tp = netdev_priv(netdev);
//netif_info(tp, drv, tp->dev, "ptp get ts\n");
return copy_to_user(ifr->ifr_data, &tp->hwtstamp_config,
sizeof(tp->hwtstamp_config)) ? -EFAULT : 0;
}
int rtl8126_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
int ret;
//netif_info(tp, drv, tp->dev, "ptp ioctl\n");
switch (cmd) {
#ifdef ENABLE_PTP_SUPPORT
case SIOCSHWTSTAMP:
ret = rtl8126_set_tstamp(netdev, ifr);
break;
case SIOCGHWTSTAMP:
ret = rtl8126_get_tstamp(netdev, ifr);
break;
#endif
default:
ret = -EOPNOTSUPP;
break;
}
return ret;
}
static void rtl8126_rx_ptp_pktstamp(struct rtl8126_private *tp, struct sk_buff *skb, u8 type)
{
struct timespec64 ts64;
unsigned long flags;
spin_lock_irqsave(&tp->phy_lock, flags);
rtl8126_ptp_ingresstime(tp, &ts64, type);
spin_unlock_irqrestore(&tp->phy_lock, flags);
skb_hwtstamps(skb)->hwtstamp = ktime_set(ts64.tv_sec, ts64.tv_nsec);
return;
}
void rtl8126_rx_ptp_timestamp(struct rtl8126_private *tp, struct sk_buff *skb)
{
unsigned int ptp_class;
struct ptp_header *hdr;
u8 msgtype;
ptp_class = ptp_classify_raw(skb);
if (ptp_class == PTP_CLASS_NONE)
return;
skb_reset_mac_header(skb);
hdr = ptp_parse_header(skb, ptp_class);
if (unlikely(!hdr))
return;
msgtype = ptp_get_msgtype(hdr, ptp_class);
rtl8126_rx_ptp_pktstamp(tp, skb, msgtype);
return;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0)
struct ptp_header *ptp_parse_header(struct sk_buff *skb, unsigned int type)
{
u8 *ptr = skb_mac_header(skb);
if (type & PTP_CLASS_VLAN)
//ptr += VLAN_HLEN;
ptr += 4;
switch (type & PTP_CLASS_PMASK) {
case PTP_CLASS_IPV4:
ptr += IPV4_HLEN(ptr) + UDP_HLEN;
break;
case PTP_CLASS_IPV6:
ptr += IP6_HLEN + UDP_HLEN;
break;
case PTP_CLASS_L2:
break;
default:
return NULL;
}
ptr += ETH_HLEN;
/* Ensure that the entire header is present in this packet. */
if (ptr + sizeof(struct ptp_header) > skb->data + skb->len)
return NULL;
return (struct ptp_header *)ptr;
}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) */

View File

@ -0,0 +1,202 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_R8126_PTP_H
#define _LINUX_R8126_PTP_H
#include <linux/ktime.h>
#include <linux/timecounter.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/ptp_classify.h>
#ifndef PTP_CLASS_NONE
#define PTP_CLASS_NONE 0x00
#endif
#ifndef PTP_MSGTYPE_SYNC
#define PTP_MSGTYPE_SYNC 0x0
#endif
#ifndef PTP_MSGTYPE_DELAY_REQ
#define PTP_MSGTYPE_DELAY_REQ 0x1
#endif
#ifndef PTP_MSGTYPE_PDELAY_REQ
#define PTP_MSGTYPE_PDELAY_REQ 0x2
#endif
#ifndef PTP_MSGTYPE_PDELAY_RESP
#define PTP_MSGTYPE_PDELAY_RESP 0x3
#endif
struct rtl8126_ptp_info {
s64 time_sec;
u32 time_ns;
u16 ts_info;
};
#ifndef _STRUCT_TIMESPEC
#define _STRUCT_TIMESPEC
struct timespec {
__kernel_old_time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
#endif
enum PTP_CMD_TYPE {
PTP_CMD_SET_LOCAL_TIME = 0,
PTP_CMD_DRIFT_LOCAL_TIME,
PTP_CMD_LATCHED_LOCAL_TIME,
};
enum PTP_CLKADJ_MOD_TYPE {
NO_FUNCTION = 0,
CLKADJ_MODE_SET = 1,
RESERVED = 2,
DIRECT_READ = 4,
DIRECT_WRITE = 6,
INCREMENT_STEP = 8,
DECREMENT_STEP = 10,
RATE_READ = 12,
RATE_WRITE = 14,
};
enum PTP_INSR_TYPE {
EVENT_CAP_INTR = (1 << 0),
TRIG_GEN_INTR = (1 << 1),
RX_TS_INTR = (1 << 2),
TX_TX_INTR = (1 << 3),
};
enum PTP_TRX_TS_STA_REG {
TRX_TS_RD = (1 << 0),
TRXTS_SEL = (1 << 1),
RX_TS_PDLYRSP_RDY = (1 << 8),
RX_TS_PDLYREQ_RDY = (1 << 9),
RX_TS_DLYREQ_RDY = (1 << 10),
RX_TS_SYNC_RDY = (1 << 11),
TX_TS_PDLYRSP_RDY = (1 << 12),
TX_TS_PDLYREQ_RDY = (1 << 13),
TX_TS_DLYREQ_RDY = (1 << 14),
TX_TS_SYNC_RDY = (1 << 15),
};
#define PTP_CTL_TYPE_0 (0xF3F)
#define PTP_CTL_TYPE_1 (0x2FF)
#define PTP_CTL_TYPE_2 (0x0FF)
#define PTP_CTL_TYPE_3 (0x03F)
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0)
struct clock_identity {
u8 id[8];
} __packed;
struct port_identity {
struct clock_identity clock_identity;
__be16 port_number;
} __packed;
struct ptp_header {
u8 tsmt; /* transportSpecific | messageType */
u8 ver; /* reserved | versionPTP */
__be16 message_length;
u8 domain_number;
u8 reserved1;
u8 flag_field[2];
__be64 correction;
__be32 reserved2;
struct port_identity source_port_identity;
__be16 sequence_id;
u8 control;
u8 log_message_interval;
} __packed;
/**
* ptp_parse_header - Get pointer to the PTP v2 header
* @skb: packet buffer
* @type: type of the packet (see ptp_classify_raw())
*
* This function takes care of the VLAN, UDP, IPv4 and IPv6 headers. The length
* is checked.
*
* Note, internally skb_mac_header() is used. Make sure that the @skb is
* initialized accordingly.
*
* Return: Pointer to the ptp v2 header or NULL if not found
*/
struct ptp_header *ptp_parse_header(struct sk_buff *skb, unsigned int type);
/**
* ptp_get_msgtype - Extract ptp message type from given header
* @hdr: ptp header
* @type: type of the packet (see ptp_classify_raw())
*
* This function returns the message type for a given ptp header. It takes care
* of the different ptp header versions (v1 or v2).
*
* Return: The message type
*/
static inline u8 ptp_get_msgtype(const struct ptp_header *hdr,
unsigned int type)
{
u8 msgtype;
if (unlikely(type & PTP_CLASS_V1)) {
/* msg type is located at the control field for ptp v1 */
msgtype = hdr->control;
} else {
msgtype = hdr->tsmt & 0x0f;
}
return msgtype;
}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) */
struct rtl8126_private;
struct RxDescV3;
int rtl8126_get_ts_info(struct net_device *netdev,
struct ethtool_ts_info *info);
void rtl8126_ptp_reset(struct rtl8126_private *tp);
void rtl8126_ptp_init(struct rtl8126_private *tp);
void rtl8126_ptp_suspend(struct rtl8126_private *tp);
void rtl8126_ptp_stop(struct rtl8126_private *tp);
int rtl8126_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
void rtl8126_rx_ptp_timestamp(struct rtl8126_private *tp, struct sk_buff *skb);
void rtl8126_set_local_time(struct rtl8126_private *tp);
#endif /* _LINUX_R8126_PTP_H */

View File

@ -0,0 +1,118 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_R8126_REALWOW_H
#define _LINUX_R8126_REALWOW_H
#define SIOCDEVPRIVATE_RTLREALWOW SIOCDEVPRIVATE+3
#define MAX_RealWoW_KCP_SIZE (100)
#define MAX_RealWoW_Payload (64)
#define KA_TX_PACKET_SIZE (100)
#define KA_WAKEUP_PATTERN_SIZE (120)
//HwSuppKeepAliveOffloadVer
#define HW_SUPPORT_KCP_OFFLOAD(_M) ((_M)->HwSuppKCPOffloadVer > 0)
enum rtl_realwow_cmd {
RTL_REALWOW_SET_KCP_DISABLE=0,
RTL_REALWOW_SET_KCP_INFO,
RTL_REALWOW_SET_KCP_CONTENT,
RTL_REALWOW_SET_KCP_ACKPKTINFO,
RTL_REALWOW_SET_KCP_WPINFO,
RTL_REALWOW_SET_KCPDHCP_TIMEOUT,
RTLT_REALWOW_COMMAND_INVALID
};
struct rtl_realwow_ioctl_struct {
__u32 cmd;
__u32 offset;
__u32 len;
union {
__u32 data;
void *data_buffer;
};
};
typedef struct _MP_KCPInfo {
u8 DIPv4[4];
u8 MacID[6];
u16 UdpPort[2];
u8 PKTLEN[2];
u16 ackLostCnt;
u8 KCP_WakePattern[MAX_RealWoW_Payload];
u8 KCP_AckPacket[MAX_RealWoW_Payload];
u32 KCP_interval;
u8 KCP_WakePattern_Len;
u8 KCP_AckPacket_Len;
u8 KCP_TxPacket[2][KA_TX_PACKET_SIZE];
} MP_KCP_INFO, *PMP_KCP_INFO;
typedef struct _KCPInfo {
u32 nId; // = id
u8 DIPv4[4];
u8 MacID[6];
u16 UdpPort;
u16 PKTLEN;
} KCPInfo, *PKCPInfo;
typedef struct _KCPContent {
u32 id; // = id
u32 mSec; // = msec
u32 size; // =size
u8 bPacket[MAX_RealWoW_KCP_SIZE]; // put packet here
} KCPContent, *PKCPContent;
typedef struct _RealWoWAckPktInfo {
u16 ackLostCnt;
u16 patterntSize;
u8 pattern[MAX_RealWoW_Payload];
} RealWoWAckPktInfo,*PRealWoWAckPktInfo;
typedef struct _RealWoWWPInfo {
u16 patterntSize;
u8 pattern[MAX_RealWoW_Payload];
} RealWoWWPInfo,*PRealWoWWPInfo;
int rtl8126_realwow_ioctl(struct net_device *dev, struct ifreq *ifr);
void rtl8126_realwow_hw_init(struct net_device *dev);
void rtl8126_get_realwow_hw_version(struct net_device *dev);
void rtl8126_set_realwow_d3_para(struct net_device *dev);
#endif /* _LINUX_R8126_REALWOW_H */

View File

@ -0,0 +1,583 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
################################################################################
#
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/version.h>
#include "r8126.h"
enum rtl8126_rss_register_content {
/* RSS */
RSS_CTRL_TCP_IPV4_SUPP = (1 << 0),
RSS_CTRL_IPV4_SUPP = (1 << 1),
RSS_CTRL_TCP_IPV6_SUPP = (1 << 2),
RSS_CTRL_IPV6_SUPP = (1 << 3),
RSS_CTRL_IPV6_EXT_SUPP = (1 << 4),
RSS_CTRL_TCP_IPV6_EXT_SUPP = (1 << 5),
RSS_HALF_SUPP = (1 << 7),
RSS_CTRL_UDP_IPV4_SUPP = (1 << 11),
RSS_CTRL_UDP_IPV6_SUPP = (1 << 12),
RSS_CTRL_UDP_IPV6_EXT_SUPP = (1 << 13),
RSS_QUAD_CPU_EN = (1 << 16),
RSS_HQ_Q_SUP_R = (1 << 31),
};
static int rtl8126_get_rss_hash_opts(struct rtl8126_private *tp,
struct ethtool_rxnfc *cmd)
{
cmd->data = 0;
/* Report default options for RSS */
switch (cmd->flow_type) {
case TCP_V4_FLOW:
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough;
case UDP_V4_FLOW:
if (tp->rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV4)
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough;
case IPV4_FLOW:
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
break;
case TCP_V6_FLOW:
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough;
case UDP_V6_FLOW:
if (tp->rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV6)
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough;
case IPV6_FLOW:
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
break;
default:
return -EINVAL;
}
return 0;
}
int rtl8126_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
u32 *rule_locs)
{
struct rtl8126_private *tp = netdev_priv(dev);
int ret = -EOPNOTSUPP;
if (!(dev->features & NETIF_F_RXHASH))
return ret;
switch (cmd->cmd) {
case ETHTOOL_GRXRINGS:
cmd->data = rtl8126_tot_rx_rings(tp);
ret = 0;
break;
case ETHTOOL_GRXFH:
ret = rtl8126_get_rss_hash_opts(tp, cmd);
break;
default:
break;
}
return ret;
}
u32 rtl8126_rss_indir_tbl_entries(struct rtl8126_private *tp)
{
return tp->HwSuppIndirTblEntries;
}
#define RSS_MASK_BITS_OFFSET (8)
#define RSS_CPU_NUM_OFFSET (16)
#define RTL8126_UDP_RSS_FLAGS (RTL_8125_RSS_FLAG_HASH_UDP_IPV4 | \
RTL_8125_RSS_FLAG_HASH_UDP_IPV6)
static int _rtl8126_set_rss_hash_opt(struct rtl8126_private *tp)
{
u32 rss_flags = tp->rss_flags;
u32 hash_mask_len;
u32 rss_ctrl;
rss_ctrl = ilog2(rtl8126_tot_rx_rings(tp));
rss_ctrl &= (BIT_0 | BIT_1 | BIT_2);
rss_ctrl <<= RSS_CPU_NUM_OFFSET;
/* Perform hash on these packet types */
rss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP
| RSS_CTRL_IPV4_SUPP
| RSS_CTRL_IPV6_SUPP
| RSS_CTRL_IPV6_EXT_SUPP
| RSS_CTRL_TCP_IPV6_SUPP
| RSS_CTRL_TCP_IPV6_EXT_SUPP;
if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV4)
rss_ctrl |= RSS_CTRL_UDP_IPV4_SUPP;
if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV6)
rss_ctrl |= RSS_CTRL_UDP_IPV6_SUPP |
RSS_CTRL_UDP_IPV6_EXT_SUPP;
hash_mask_len = ilog2(rtl8126_rss_indir_tbl_entries(tp));
hash_mask_len &= (BIT_0 | BIT_1 | BIT_2);
rss_ctrl |= hash_mask_len << RSS_MASK_BITS_OFFSET;
RTL_W32(tp, RSS_CTRL_8125, rss_ctrl);
return 0;
}
static int rtl8126_set_rss_hash_opt(struct rtl8126_private *tp,
struct ethtool_rxnfc *nfc)
{
u32 rss_flags = tp->rss_flags;
/*
* RSS does not support anything other than hashing
* to queues on src and dst IPs and ports
*/
if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3))
return -EINVAL;
switch (nfc->flow_type) {
case TCP_V4_FLOW:
case TCP_V6_FLOW:
if (!(nfc->data & RXH_IP_SRC) ||
!(nfc->data & RXH_IP_DST) ||
!(nfc->data & RXH_L4_B_0_1) ||
!(nfc->data & RXH_L4_B_2_3))
return -EINVAL;
break;
case UDP_V4_FLOW:
if (!(nfc->data & RXH_IP_SRC) ||
!(nfc->data & RXH_IP_DST))
return -EINVAL;
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
case 0:
rss_flags &= ~RTL_8125_RSS_FLAG_HASH_UDP_IPV4;
break;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
rss_flags |= RTL_8125_RSS_FLAG_HASH_UDP_IPV4;
break;
default:
return -EINVAL;
}
break;
case UDP_V6_FLOW:
if (!(nfc->data & RXH_IP_SRC) ||
!(nfc->data & RXH_IP_DST))
return -EINVAL;
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
case 0:
rss_flags &= ~RTL_8125_RSS_FLAG_HASH_UDP_IPV6;
break;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
rss_flags |= RTL_8125_RSS_FLAG_HASH_UDP_IPV6;
break;
default:
return -EINVAL;
}
break;
case SCTP_V4_FLOW:
case AH_ESP_V4_FLOW:
case AH_V4_FLOW:
case ESP_V4_FLOW:
case SCTP_V6_FLOW:
case AH_ESP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
case IP_USER_FLOW:
case ETHER_FLOW:
/* RSS is not supported for these protocols */
if (nfc->data) {
netif_err(tp, drv, tp->dev, "Command parameters not supported\n");
return -EINVAL;
}
return 0;
break;
default:
return -EINVAL;
}
/* if we changed something we need to update flags */
if (rss_flags != tp->rss_flags) {
u32 rss_ctrl = RTL_R32(tp, RSS_CTRL_8125);
if ((rss_flags & RTL8126_UDP_RSS_FLAGS) &&
!(tp->rss_flags & RTL8126_UDP_RSS_FLAGS))
netdev_warn(tp->dev,
"enabling UDP RSS: fragmented packets may "
"arrive out of order to the stack above\n");
tp->rss_flags = rss_flags;
/* Perform hash on these packet types */
rss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP
| RSS_CTRL_IPV4_SUPP
| RSS_CTRL_IPV6_SUPP
| RSS_CTRL_IPV6_EXT_SUPP
| RSS_CTRL_TCP_IPV6_SUPP
| RSS_CTRL_TCP_IPV6_EXT_SUPP;
rss_ctrl &= ~(RSS_CTRL_UDP_IPV4_SUPP |
RSS_CTRL_UDP_IPV6_SUPP |
RSS_CTRL_UDP_IPV6_EXT_SUPP);
if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV4)
rss_ctrl |= RSS_CTRL_UDP_IPV4_SUPP;
if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV6)
rss_ctrl |= RSS_CTRL_UDP_IPV6_SUPP |
RSS_CTRL_UDP_IPV6_EXT_SUPP;
RTL_W32(tp, RSS_CTRL_8125, rss_ctrl);
}
return 0;
}
int rtl8126_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
{
struct rtl8126_private *tp = netdev_priv(dev);
int ret = -EOPNOTSUPP;
if (!(dev->features & NETIF_F_RXHASH))
return ret;
switch (cmd->cmd) {
case ETHTOOL_SRXFH:
ret = rtl8126_set_rss_hash_opt(tp, cmd);
break;
default:
break;
}
return ret;
}
static u32 _rtl8126_get_rxfh_key_size(struct rtl8126_private *tp)
{
return sizeof(tp->rss_key);
}
u32 rtl8126_get_rxfh_key_size(struct net_device *dev)
{
struct rtl8126_private *tp = netdev_priv(dev);
if (!(dev->features & NETIF_F_RXHASH))
return 0;
return _rtl8126_get_rxfh_key_size(tp);
}
u32 rtl8126_rss_indir_size(struct net_device *dev)
{
struct rtl8126_private *tp = netdev_priv(dev);
if (!(dev->features & NETIF_F_RXHASH))
return 0;
return rtl8126_rss_indir_tbl_entries(tp);
}
static void rtl8126_get_reta(struct rtl8126_private *tp, u32 *indir)
{
int i, reta_size = rtl8126_rss_indir_tbl_entries(tp);
for (i = 0; i < reta_size; i++)
indir[i] = tp->rss_indir_tbl[i];
}
static u32 rtl8126_rss_key_reg(struct rtl8126_private *tp)
{
return RSS_KEY_8125;
}
static u32 rtl8126_rss_indir_tbl_reg(struct rtl8126_private *tp)
{
return RSS_INDIRECTION_TBL_8125_V2;
}
static void rtl8126_store_reta(struct rtl8126_private *tp)
{
u16 indir_tbl_reg = rtl8126_rss_indir_tbl_reg(tp);
u32 i, reta_entries = rtl8126_rss_indir_tbl_entries(tp);
u32 reta = 0;
u8 *indir_tbl = tp->rss_indir_tbl;
/* Write redirection table to HW */
for (i = 0; i < reta_entries; i++) {
reta |= indir_tbl[i] << (i & 0x3) * 8;
if ((i & 3) == 3) {
RTL_W32(tp, indir_tbl_reg, reta);
indir_tbl_reg += 4;
reta = 0;
}
}
}
static void rtl8126_store_rss_key(struct rtl8126_private *tp)
{
const u16 rss_key_reg = rtl8126_rss_key_reg(tp);
u32 i, rss_key_size = _rtl8126_get_rxfh_key_size(tp);
u32 *rss_key = (u32*)tp->rss_key;
/* Write redirection table to HW */
for (i = 0; i < rss_key_size; i+=4)
RTL_W32(tp, rss_key_reg + i, *rss_key++);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0)
int rtl8126_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh)
{
struct rtl8126_private *tp = netdev_priv(dev);
if (!(dev->features & NETIF_F_RXHASH))
return -EOPNOTSUPP;
rxfh->hfunc = ETH_RSS_HASH_TOP;
if (rxfh->indir)
rtl8126_get_reta(tp, rxfh->indir);
if (rxfh->key)
memcpy(rxfh->key, tp->rss_key, RTL8126_RSS_KEY_SIZE);
return 0;
}
int rtl8126_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack)
{
struct rtl8126_private *tp = netdev_priv(dev);
int i;
u32 reta_entries = rtl8126_rss_indir_tbl_entries(tp);
/* We require at least one supported parameter to be changed and no
* change in any of the unsupported parameters
*/
if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
/* Fill out the redirection table */
if (rxfh->indir) {
int max_queues = tp->num_rx_rings;
/* Verify user input. */
for (i = 0; i < reta_entries; i++)
if (rxfh->indir[i] >= max_queues)
return -EINVAL;
for (i = 0; i < reta_entries; i++)
tp->rss_indir_tbl[i] = rxfh->indir[i];
}
/* Fill out the rss hash key */
if (rxfh->key)
memcpy(tp->rss_key, rxfh->key, RTL8126_RSS_KEY_SIZE);
rtl8126_store_reta(tp);
rtl8126_store_rss_key(tp);
return 0;
}
#else
int rtl8126_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
u8 *hfunc)
{
struct rtl8126_private *tp = netdev_priv(dev);
if (!(dev->features & NETIF_F_RXHASH))
return -EOPNOTSUPP;
if (hfunc)
*hfunc = ETH_RSS_HASH_TOP;
if (indir)
rtl8126_get_reta(tp, indir);
if (key)
memcpy(key, tp->rss_key, RTL8126_RSS_KEY_SIZE);
return 0;
}
int rtl8126_set_rxfh(struct net_device *dev, const u32 *indir,
const u8 *key, const u8 hfunc)
{
struct rtl8126_private *tp = netdev_priv(dev);
int i;
u32 reta_entries = rtl8126_rss_indir_tbl_entries(tp);
/* We require at least one supported parameter to be changed and no
* change in any of the unsupported parameters
*/
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
/* Fill out the redirection table */
if (indir) {
int max_queues = tp->num_rx_rings;
/* Verify user input. */
for (i = 0; i < reta_entries; i++)
if (indir[i] >= max_queues)
return -EINVAL;
for (i = 0; i < reta_entries; i++)
tp->rss_indir_tbl[i] = indir[i];
}
/* Fill out the rss hash key */
if (key)
memcpy(tp->rss_key, key, RTL8126_RSS_KEY_SIZE);
rtl8126_store_reta(tp);
rtl8126_store_rss_key(tp);
return 0;
}
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0) */
static u32 rtl8126_get_rx_desc_hash(struct rtl8126_private *tp,
struct RxDesc *desc)
{
switch (tp->InitRxDescType) {
case RX_DESC_RING_TYPE_3:
return le32_to_cpu(((struct RxDescV3 *)desc)->RxDescNormalDDWord2.RSSResult);
case RX_DESC_RING_TYPE_4:
return le32_to_cpu(((struct RxDescV4 *)desc)->RxDescNormalDDWord1.RSSResult);
default:
return 0;
}
}
#define RXS_8125B_RSS_UDP BIT(9)
#define RXS_8125_RSS_IPV4 BIT(10)
#define RXS_8125_RSS_IPV6 BIT(12)
#define RXS_8125_RSS_TCP BIT(13)
#define RTL8126_RXS_RSS_L3_TYPE_MASK (RXS_8125_RSS_IPV4 | RXS_8125_RSS_IPV6)
#define RTL8126_RXS_RSS_L4_TYPE_MASK (RXS_8125_RSS_TCP | RXS_8125B_RSS_UDP)
#define RXS_8125B_RSS_UDP_V4 BIT(27)
#define RXS_8125_RSS_IPV4_V4 BIT(28)
#define RXS_8125_RSS_IPV6_V4 BIT(29)
#define RXS_8125_RSS_TCP_V4 BIT(30)
#define RTL8126_RXS_RSS_L3_TYPE_MASK_V4 (RXS_8125_RSS_IPV4_V4 | RXS_8125_RSS_IPV6_V4)
#define RTL8126_RXS_RSS_L4_TYPE_MASK_V4 (RXS_8125_RSS_TCP_V4 | RXS_8125B_RSS_UDP_V4)
static void rtl8126_rx_hash_v3(struct rtl8126_private *tp,
struct RxDescV3 *descv3,
struct sk_buff *skb)
{
u16 rss_header_info;
if (!(tp->dev->features & NETIF_F_RXHASH))
return;
rss_header_info = le16_to_cpu(descv3->RxDescNormalDDWord2.HeaderInfo);
if (!(rss_header_info & RTL8126_RXS_RSS_L3_TYPE_MASK))
return;
skb_set_hash(skb, rtl8126_get_rx_desc_hash(tp, (struct RxDesc *)descv3),
(RTL8126_RXS_RSS_L4_TYPE_MASK & rss_header_info) ?
PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
}
static void rtl8126_rx_hash_v4(struct rtl8126_private *tp,
struct RxDescV4 *descv4,
struct sk_buff *skb)
{
u32 rss_header_info;
if (!(tp->dev->features & NETIF_F_RXHASH))
return;
rss_header_info = le32_to_cpu(descv4->RxDescNormalDDWord1.RSSInfo);
if (!(rss_header_info & RTL8126_RXS_RSS_L3_TYPE_MASK_V4))
return;
skb_set_hash(skb, rtl8126_get_rx_desc_hash(tp, (struct RxDesc *)descv4),
(RTL8126_RXS_RSS_L4_TYPE_MASK_V4 & rss_header_info) ?
PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
}
void rtl8126_rx_hash(struct rtl8126_private *tp,
struct RxDesc *desc,
struct sk_buff *skb)
{
switch (tp->InitRxDescType) {
case RX_DESC_RING_TYPE_3:
rtl8126_rx_hash_v3(tp, (struct RxDescV3 *)desc, skb);
break;
case RX_DESC_RING_TYPE_4:
rtl8126_rx_hash_v4(tp, (struct RxDescV4 *)desc, skb);
break;
default:
return;
}
}
void rtl8126_disable_rss(struct rtl8126_private *tp)
{
RTL_W32(tp, RSS_CTRL_8125, 0x00);
}
void _rtl8126_config_rss(struct rtl8126_private *tp)
{
_rtl8126_set_rss_hash_opt(tp);
rtl8126_store_reta(tp);
rtl8126_store_rss_key(tp);
}
void rtl8126_config_rss(struct rtl8126_private *tp)
{
if (!tp->EnableRss) {
rtl8126_disable_rss(tp);
return;
}
_rtl8126_config_rss(tp);
}
void rtl8126_init_rss(struct rtl8126_private *tp)
{
int i;
for (i = 0; i < rtl8126_rss_indir_tbl_entries(tp); i++)
tp->rss_indir_tbl[i] = ethtool_rxfh_indir_default(i, tp->num_rx_rings);
netdev_rss_key_fill(tp->rss_key, RTL8126_RSS_KEY_SIZE);
}

View File

@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_R8126_RSS_H
#define _LINUX_R8126_RSS_H
#include <linux/netdevice.h>
#include <linux/types.h>
#define RTL8126_RSS_KEY_SIZE 40 /* size of RSS Hash Key in bytes */
#define RTL8126_MAX_INDIRECTION_TABLE_ENTRIES 128
enum rtl8126_rss_flag {
RTL_8125_RSS_FLAG_HASH_UDP_IPV4 = (1 << 0),
RTL_8125_RSS_FLAG_HASH_UDP_IPV6 = (1 << 1),
};
struct rtl8126_private;
struct RxDesc;
int rtl8126_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
u32 *rule_locs);
int rtl8126_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd);
u32 rtl8126_get_rxfh_key_size(struct net_device *netdev);
u32 rtl8126_rss_indir_size(struct net_device *netdev);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0)
int rtl8126_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh);
int rtl8126_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack);
#else
int rtl8126_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
u8 *hfunc);
int rtl8126_set_rxfh(struct net_device *netdev, const u32 *indir,
const u8 *key, const u8 hfunc);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0) */
void rtl8126_rx_hash(struct rtl8126_private *tp,
struct RxDesc *desc,
struct sk_buff *skb);
void _rtl8126_config_rss(struct rtl8126_private *tp);
void rtl8126_config_rss(struct rtl8126_private *tp);
void rtl8126_init_rss(struct rtl8126_private *tp);
u32 rtl8126_rss_indir_tbl_entries(struct rtl8126_private *tp);
void rtl8126_disable_rss(struct rtl8126_private *tp);
#endif /* _LINUX_R8126_RSS_H */

View File

@ -0,0 +1,285 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
################################################################################
#
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <asm/io.h>
#include "r8126.h"
#include "rtl_eeprom.h"
//-------------------------------------------------------------------
//rtl8126_eeprom_type():
// tell the eeprom type
//return value:
// 0: the eeprom type is 93C46
// 1: the eeprom type is 93C56 or 93C66
//-------------------------------------------------------------------
void rtl8126_eeprom_type(struct rtl8126_private *tp)
{
u16 magic = 0;
if (tp->mcfg == CFG_METHOD_DEFAULT)
goto out_no_eeprom;
if(RTL_R8(tp, 0xD2)&0x04) {
//not support
//tp->eeprom_type = EEPROM_TWSI;
//tp->eeprom_len = 256;
goto out_no_eeprom;
} else if(RTL_R32(tp, RxConfig) & RxCfg_9356SEL) {
tp->eeprom_type = EEPROM_TYPE_93C56;
tp->eeprom_len = 256;
} else {
tp->eeprom_type = EEPROM_TYPE_93C46;
tp->eeprom_len = 128;
}
magic = rtl8126_eeprom_read_sc(tp, 0);
out_no_eeprom:
if ((magic != 0x8129) && (magic != 0x8128)) {
tp->eeprom_type = EEPROM_TYPE_NONE;
tp->eeprom_len = 0;
}
}
void rtl8126_eeprom_cleanup(struct rtl8126_private *tp)
{
u8 x;
x = RTL_R8(tp, Cfg9346);
x &= ~(Cfg9346_EEDI | Cfg9346_EECS);
RTL_W8(tp, Cfg9346, x);
rtl8126_raise_clock(tp, &x);
rtl8126_lower_clock(tp, &x);
}
static int rtl8126_eeprom_cmd_done(struct rtl8126_private *tp)
{
u8 x;
int i;
rtl8126_stand_by(tp);
for (i = 0; i < 50000; i++) {
x = RTL_R8(tp, Cfg9346);
if (x & Cfg9346_EEDO) {
fsleep(RTL_CLOCK_RATE * 2 * 3);
return 0;
}
fsleep(1);
}
return -1;
}
//-------------------------------------------------------------------
//rtl8126_eeprom_read_sc():
// read one word from eeprom
//-------------------------------------------------------------------
u16 rtl8126_eeprom_read_sc(struct rtl8126_private *tp, u16 reg)
{
int addr_sz = 6;
u8 x;
u16 data;
if(tp->eeprom_type == EEPROM_TYPE_NONE)
return -1;
if (tp->eeprom_type==EEPROM_TYPE_93C46)
addr_sz = 6;
else if (tp->eeprom_type==EEPROM_TYPE_93C56)
addr_sz = 8;
x = Cfg9346_EEM1 | Cfg9346_EECS;
RTL_W8(tp, Cfg9346, x);
rtl8126_shift_out_bits(tp, RTL_EEPROM_READ_OPCODE, 3);
rtl8126_shift_out_bits(tp, reg, addr_sz);
data = rtl8126_shift_in_bits(tp);
rtl8126_eeprom_cleanup(tp);
RTL_W8(tp, Cfg9346, 0);
return data;
}
//-------------------------------------------------------------------
//rtl8126_eeprom_write_sc():
// write one word to a specific address in the eeprom
//-------------------------------------------------------------------
void rtl8126_eeprom_write_sc(struct rtl8126_private *tp, u16 reg, u16 data)
{
u8 x;
int addr_sz = 6;
int w_dummy_addr = 4;
if(tp->eeprom_type == EEPROM_TYPE_NONE)
return;
if (tp->eeprom_type==EEPROM_TYPE_93C46) {
addr_sz = 6;
w_dummy_addr = 4;
} else if (tp->eeprom_type==EEPROM_TYPE_93C56) {
addr_sz = 8;
w_dummy_addr = 6;
}
x = Cfg9346_EEM1 | Cfg9346_EECS;
RTL_W8(tp, Cfg9346, x);
rtl8126_shift_out_bits(tp, RTL_EEPROM_EWEN_OPCODE, 5);
rtl8126_shift_out_bits(tp, reg, w_dummy_addr);
rtl8126_stand_by(tp);
rtl8126_shift_out_bits(tp, RTL_EEPROM_ERASE_OPCODE, 3);
rtl8126_shift_out_bits(tp, reg, addr_sz);
if (rtl8126_eeprom_cmd_done(tp) < 0)
return;
rtl8126_stand_by(tp);
rtl8126_shift_out_bits(tp, RTL_EEPROM_WRITE_OPCODE, 3);
rtl8126_shift_out_bits(tp, reg, addr_sz);
rtl8126_shift_out_bits(tp, data, 16);
if (rtl8126_eeprom_cmd_done(tp) < 0)
return;
rtl8126_stand_by(tp);
rtl8126_shift_out_bits(tp, RTL_EEPROM_EWDS_OPCODE, 5);
rtl8126_shift_out_bits(tp, reg, w_dummy_addr);
rtl8126_eeprom_cleanup(tp);
RTL_W8(tp, Cfg9346, 0);
}
void rtl8126_raise_clock(struct rtl8126_private *tp, u8 *x)
{
*x = *x | Cfg9346_EESK;
RTL_W8(tp, Cfg9346, *x);
fsleep(RTL_CLOCK_RATE);
}
void rtl8126_lower_clock(struct rtl8126_private *tp, u8 *x)
{
*x = *x & ~Cfg9346_EESK;
RTL_W8(tp, Cfg9346, *x);
fsleep(RTL_CLOCK_RATE);
}
void rtl8126_shift_out_bits(struct rtl8126_private *tp, int data, int count)
{
u8 x;
int mask;
mask = 0x01 << (count - 1);
x = RTL_R8(tp, Cfg9346);
x &= ~(Cfg9346_EEDI | Cfg9346_EEDO);
do {
if (data & mask)
x |= Cfg9346_EEDI;
else
x &= ~Cfg9346_EEDI;
RTL_W8(tp, Cfg9346, x);
fsleep(RTL_CLOCK_RATE);
rtl8126_raise_clock(tp, &x);
rtl8126_lower_clock(tp, &x);
mask = mask >> 1;
} while(mask);
x &= ~Cfg9346_EEDI;
RTL_W8(tp, Cfg9346, x);
}
u16 rtl8126_shift_in_bits(struct rtl8126_private *tp)
{
u8 x;
u16 d, i;
x = RTL_R8(tp, Cfg9346);
x &= ~(Cfg9346_EEDI | Cfg9346_EEDO);
d = 0;
for (i = 0; i < 16; i++) {
d = d << 1;
rtl8126_raise_clock(tp, &x);
x = RTL_R8(tp, Cfg9346);
x &= ~Cfg9346_EEDI;
if (x & Cfg9346_EEDO)
d |= 1;
rtl8126_lower_clock(tp, &x);
}
return d;
}
void rtl8126_stand_by(struct rtl8126_private *tp)
{
u8 x;
x = RTL_R8(tp, Cfg9346);
x &= ~(Cfg9346_EECS | Cfg9346_EESK);
RTL_W8(tp, Cfg9346, x);
fsleep(RTL_CLOCK_RATE);
x |= Cfg9346_EECS;
RTL_W8(tp, Cfg9346, x);
}
void rtl8126_set_eeprom_sel_low(struct rtl8126_private *tp)
{
RTL_W8(tp, Cfg9346, Cfg9346_EEM1);
RTL_W8(tp, Cfg9346, Cfg9346_EEM1 | Cfg9346_EESK);
fsleep(20);
RTL_W8(tp, Cfg9346, Cfg9346_EEM1);
}

View File

@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_RTLEEPROM_H
#define _LINUX_RTLEEPROM_H
//EEPROM opcodes
#define RTL_EEPROM_READ_OPCODE 06
#define RTL_EEPROM_WRITE_OPCODE 05
#define RTL_EEPROM_ERASE_OPCODE 07
#define RTL_EEPROM_EWEN_OPCODE 19
#define RTL_EEPROM_EWDS_OPCODE 16
#define RTL_CLOCK_RATE 3
void rtl8126_eeprom_type(struct rtl8126_private *tp);
void rtl8126_eeprom_cleanup(struct rtl8126_private *tp);
u16 rtl8126_eeprom_read_sc(struct rtl8126_private *tp, u16 reg);
void rtl8126_eeprom_write_sc(struct rtl8126_private *tp, u16 reg, u16 data);
void rtl8126_shift_out_bits(struct rtl8126_private *tp, int data, int count);
u16 rtl8126_shift_in_bits(struct rtl8126_private *tp);
void rtl8126_raise_clock(struct rtl8126_private *tp, u8 *x);
void rtl8126_lower_clock(struct rtl8126_private *tp, u8 *x);
void rtl8126_stand_by(struct rtl8126_private *tp);
void rtl8126_set_eeprom_sel_low(struct rtl8126_private *tp);
#endif /* _LINUX_RTLEEPROM_H */

View File

@ -0,0 +1,295 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
################################################################################
#
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/in.h>
#include <linux/ethtool.h>
#include <asm/uaccess.h>
#include "r8126.h"
#include "rtl_eeprom.h"
#include "rtltool.h"
int rtl8126_tool_ioctl(struct rtl8126_private *tp, struct ifreq *ifr)
{
struct rtltool_cmd my_cmd;
int ret;
if (copy_from_user(&my_cmd, ifr->ifr_data, sizeof(my_cmd)))
return -EFAULT;
ret = 0;
switch (my_cmd.cmd) {
case RTLTOOL_READ_MAC:
if ((my_cmd.offset + my_cmd.len) > pci_resource_len(tp->pci_dev, 2)) {
ret = -EINVAL;
break;
}
if (my_cmd.len==1)
my_cmd.data = readb(tp->mmio_addr+my_cmd.offset);
else if (my_cmd.len==2)
my_cmd.data = readw(tp->mmio_addr+(my_cmd.offset&~1));
else if (my_cmd.len==4)
my_cmd.data = readl(tp->mmio_addr+(my_cmd.offset&~3));
else {
ret = -EOPNOTSUPP;
break;
}
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_MAC:
if ((my_cmd.offset + my_cmd.len) > pci_resource_len(tp->pci_dev, 2)) {
ret = -EINVAL;
break;
}
if (my_cmd.len==1)
writeb(my_cmd.data, tp->mmio_addr+my_cmd.offset);
else if (my_cmd.len==2)
writew(my_cmd.data, tp->mmio_addr+(my_cmd.offset&~1));
else if (my_cmd.len==4)
writel(my_cmd.data, tp->mmio_addr+(my_cmd.offset&~3));
else {
ret = -EOPNOTSUPP;
break;
}
break;
case RTLTOOL_READ_PHY:
my_cmd.data = rtl8126_mdio_prot_read(tp, my_cmd.offset);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_PHY:
rtl8126_mdio_prot_write(tp, my_cmd.offset, my_cmd.data);
break;
case RTLTOOL_READ_EPHY:
my_cmd.data = rtl8126_ephy_read(tp, my_cmd.offset);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_EPHY:
rtl8126_ephy_write(tp, my_cmd.offset, my_cmd.data);
break;
case RTLTOOL_READ_ERI:
my_cmd.data = 0;
if (my_cmd.len==1 || my_cmd.len==2 || my_cmd.len==4) {
my_cmd.data = rtl8126_eri_read(tp, my_cmd.offset, my_cmd.len, ERIAR_ExGMAC);
} else {
ret = -EOPNOTSUPP;
break;
}
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_ERI:
if (my_cmd.len==1 || my_cmd.len==2 || my_cmd.len==4) {
rtl8126_eri_write(tp, my_cmd.offset, my_cmd.len, my_cmd.data, ERIAR_ExGMAC);
} else {
ret = -EOPNOTSUPP;
break;
}
break;
case RTLTOOL_READ_PCI:
my_cmd.data = 0;
if (my_cmd.len==1)
pci_read_config_byte(tp->pci_dev, my_cmd.offset,
(u8 *)&my_cmd.data);
else if (my_cmd.len==2)
pci_read_config_word(tp->pci_dev, my_cmd.offset,
(u16 *)&my_cmd.data);
else if (my_cmd.len==4)
pci_read_config_dword(tp->pci_dev, my_cmd.offset,
&my_cmd.data);
else {
ret = -EOPNOTSUPP;
break;
}
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_PCI:
if (my_cmd.len==1)
pci_write_config_byte(tp->pci_dev, my_cmd.offset,
my_cmd.data);
else if (my_cmd.len==2)
pci_write_config_word(tp->pci_dev, my_cmd.offset,
my_cmd.data);
else if (my_cmd.len==4)
pci_write_config_dword(tp->pci_dev, my_cmd.offset,
my_cmd.data);
else {
ret = -EOPNOTSUPP;
break;
}
break;
case RTLTOOL_READ_EEPROM:
my_cmd.data = rtl8126_eeprom_read_sc(tp, my_cmd.offset);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_EEPROM:
rtl8126_eeprom_write_sc(tp, my_cmd.offset, my_cmd.data);
break;
case RTL_READ_OOB_MAC:
rtl8126_oob_mutex_lock(tp);
my_cmd.data = rtl8126_ocp_read(tp, my_cmd.offset, 4);
rtl8126_oob_mutex_unlock(tp);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTL_WRITE_OOB_MAC:
if (my_cmd.len == 0 || my_cmd.len > 4)
return -EOPNOTSUPP;
rtl8126_oob_mutex_lock(tp);
rtl8126_ocp_write(tp, my_cmd.offset, my_cmd.len, my_cmd.data);
rtl8126_oob_mutex_unlock(tp);
break;
case RTL_ENABLE_PCI_DIAG:
tp->rtk_enable_diag = 1;
dprintk("enable rtk diag\n");
break;
case RTL_DISABLE_PCI_DIAG:
tp->rtk_enable_diag = 0;
dprintk("disable rtk diag\n");
break;
case RTL_READ_MAC_OCP:
if (my_cmd.offset % 2)
return -EOPNOTSUPP;
my_cmd.data = rtl8126_mac_ocp_read(tp, my_cmd.offset);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTL_WRITE_MAC_OCP:
if ((my_cmd.offset % 2) || (my_cmd.len != 2))
return -EOPNOTSUPP;
rtl8126_mac_ocp_write(tp, my_cmd.offset, (u16)my_cmd.data);
break;
case RTL_DIRECT_READ_PHY_OCP:
my_cmd.data = rtl8126_mdio_prot_direct_read_phy_ocp(tp, my_cmd.offset);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTL_DIRECT_WRITE_PHY_OCP:
rtl8126_mdio_prot_direct_write_phy_ocp(tp, my_cmd.offset, my_cmd.data);
break;
#ifdef ENABLE_FIBER_SUPPORT
case RTL_READ_FIBER_PHY:
if (!HW_FIBER_STATUS_CONNECTED(tp)) {
ret = -EOPNOTSUPP;
break;
}
my_cmd.data = rtl8126_fiber_mdio_read(tp, my_cmd.offset);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTL_WRITE_FIBER_PHY:
if (!HW_FIBER_STATUS_CONNECTED(tp)) {
ret = -EOPNOTSUPP;
break;
}
rtl8126_fiber_mdio_write(tp, my_cmd.offset, my_cmd.data);
break;
#endif /* ENABLE_FIBER_SUPPORT */
default:
ret = -EOPNOTSUPP;
break;
}
return ret;
}

View File

@ -0,0 +1,89 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_RTLTOOL_H
#define _LINUX_RTLTOOL_H
#define SIOCRTLTOOL SIOCDEVPRIVATE+1
enum rtl_cmd {
RTLTOOL_READ_MAC=0,
RTLTOOL_WRITE_MAC,
RTLTOOL_READ_PHY,
RTLTOOL_WRITE_PHY,
RTLTOOL_READ_EPHY,
RTLTOOL_WRITE_EPHY,
RTLTOOL_READ_ERI,
RTLTOOL_WRITE_ERI,
RTLTOOL_READ_PCI,
RTLTOOL_WRITE_PCI,
RTLTOOL_READ_EEPROM,
RTLTOOL_WRITE_EEPROM,
RTL_READ_OOB_MAC,
RTL_WRITE_OOB_MAC,
RTL_ENABLE_PCI_DIAG,
RTL_DISABLE_PCI_DIAG,
RTL_READ_MAC_OCP,
RTL_WRITE_MAC_OCP,
RTL_DIRECT_READ_PHY_OCP,
RTL_DIRECT_WRITE_PHY_OCP,
RTL_READ_FIBER_PHY,
RTL_WRITE_FIBER_PHY,
RTLTOOL_INVALID
};
struct rtltool_cmd {
__u32 cmd;
__u32 offset;
__u32 len;
__u32 data;
};
enum mode_access {
MODE_NONE=0,
MODE_READ,
MODE_WRITE
};
#ifdef __KERNEL__
int rtl8126_tool_ioctl(struct rtl8126_private *tp, struct ifreq *ifr);
#endif
#endif /* _LINUX_RTLTOOL_H */

View File

@ -0,0 +1 @@
savedcmd_drivers/net/ethernet/realtek/r8168/built-in.a := rm -f drivers/net/ethernet/realtek/r8168/built-in.a; printf "drivers/net/ethernet/realtek/r8168/%s " r8168_n.o r8168_asf.o rtl_eeprom.o rtltool.o | xargs ar cDPrST drivers/net/ethernet/realtek/r8168/built-in.a

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
config R8168
tristate "Realtek GBE Ethernet driver (r8168)"
depends on PCI && MII
help
This is the official Realtek GBE Ethernet driver.

View File

@ -0,0 +1,68 @@
obj-$(CONFIG_R8168) += r8168.o
r8168-objs += r8168_n.o r8168_asf.o rtl_eeprom.o rtltool.o
EXTRA_CFLAGS += -DCONFIG_SOC_LAN
EXTRA_CFLAGS += -DCONFIG_ASPM
EXTRA_CFLAGS += -DENABLE_S5WOL
EXTRA_CFLAGS += -DCONFIG_DYNAMIC_ASPM
# EXTRA_CFLAGS += -DCONFIG_R8168_VLAN # Need to check if needed
#
# Other options that can be enabled if needed.
#
#
# ENABLE_REALWOW_SUPPORT:
# r8168-objs += r8168_realwow.o
# EXTRA_CFLAGS += -DENABLE_REALWOW_SUPPORT
#
# ENABLE_FIBER_SUPPORT:
# r8168-objs += r8168_fiber.o
# EXTRA_CFLAGS += -DENABLE_FIBER_SUPPORT
#
# ENABLE_DASH_SUPPORT:
# r8168-objs += r8168_dash.o
# EXTRA_CFLAGS += -DENABLE_DASH_SUPPORT
#
# ENABLE_DASH_PRINTER_SUPPORT:
# r8168-objs += r8168_dash.o
# EXTRA_CFLAGS += -DENABLE_DASH_SUPPORT -DENABLE_DASH_PRINTER_SUPPORT
#
# ENABLE_RSS_SUPPORT:
# EXTRA_CFLAGS += -DCONFIG_R8168_NAPI
#
# CONFIG_DOWN_SPEED_100:
# EXTRA_CFLAGS += -DCONFIG_DOWN_SPEED_100
#
# ENABLE_S5_KEEP_CURR_MAC:
# EXTRA_CFLAGS += -DENABLE_S5_KEEP_CURR_MAC
#
# ENABLE_EEE:
# EXTRA_CFLAGS += -DENABLE_EEE
#
# ENABLE_S0_MAGIC_PACKET:
# EXTRA_CFLAGS += -DENABLE_S0_MAGIC_PACKET
#
# CONFIG_DYNAMIC_ASPM:
# EXTRA_CFLAGS += -DCONFIG_DYNAMIC_ASPM
#
# ENABLE_USE_FIRMWARE_FILE:
# r8168-objs += r8168_firmware.o
# EXTRA_CFLAGS += -DENABLE_USE_FIRMWARE_FILE
#
# CONFIG_CTAP_SHORT_OFF:
# EXTRA_CFLAGS += -DCONFIG_CTAP_SHORT_OFF
#
# ENABLE_MULTIPLE_TX_QUEUE:
# EXTRA_CFLAGS += -DENABLE_MULTIPLE_TX_QUEUE
#
# ENABLE_RSS_SUPPORT:
# r8168-objs += r8168_rss.o
# EXTRA_CFLAGS += -DENABLE_RSS_SUPPORT
#
# ENABLE_LIB_SUPPORT:
# r8168-objs += r8168_lib.o
# EXTRA_CFLAGS += -DENABLE_LIB_SUPPORT
#
# DISABLE_WOL_SUPPORT:
# EXTRA_CFLAGS += -DDISABLE_WOL_SUPPORT

View File

@ -0,0 +1,11 @@
!<thin>
// 50 `
r8168_n.o/
r8168_asf.o/
rtl_eeprom.o/
rtltool.o/
/0 0 0 0 644 1256280 `
/11 0 0 0 644 15656 `
/24 0 0 0 644 10088 `
/38 0 0 0 644 5840 `

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,416 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
################################################################################
#
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/if_vlan.h>
#include <linux/crc32.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/init.h>
#include <linux/rtnetlink.h>
#include <asm/uaccess.h>
#include "r8168.h"
#include "r8168_asf.h"
#include "rtl_eeprom.h"
int rtl8168_asf_ioctl(struct net_device *dev,
struct ifreq *ifr)
{
struct rtl8168_private *tp = netdev_priv(dev);
void *user_data = ifr->ifr_data;
struct asf_ioctl_struct asf_usrdata;
if (tp->mcfg != CFG_METHOD_7 && tp->mcfg != CFG_METHOD_8)
return -EOPNOTSUPP;
if (copy_from_user(&asf_usrdata, user_data, sizeof(struct asf_ioctl_struct)))
return -EFAULT;
switch (asf_usrdata.offset) {
case HBPeriod:
rtl8168_asf_hbperiod(tp, asf_usrdata.arg, asf_usrdata.u.data);
break;
case WD8Timer:
break;
case WD16Rst:
rtl8168_asf_wd16rst(tp, asf_usrdata.arg, asf_usrdata.u.data);
break;
case WD8Rst:
rtl8168_asf_time_period(tp, asf_usrdata.arg, WD8Rst, asf_usrdata.u.data);
break;
case LSnsrPollCycle:
rtl8168_asf_time_period(tp, asf_usrdata.arg, LSnsrPollCycle, asf_usrdata.u.data);
break;
case ASFSnsrPollPrd:
rtl8168_asf_time_period(tp, asf_usrdata.arg, ASFSnsrPollPrd, asf_usrdata.u.data);
break;
case AlertReSendItvl:
rtl8168_asf_time_period(tp, asf_usrdata.arg, AlertReSendItvl, asf_usrdata.u.data);
break;
case SMBAddr:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, SMBAddr, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case ASFConfigR0:
rtl8168_asf_config_regs(tp, asf_usrdata.arg, ASFConfigR0, asf_usrdata.u.data);
break;
case ASFConfigR1:
rtl8168_asf_config_regs(tp, asf_usrdata.arg, ASFConfigR1, asf_usrdata.u.data);
break;
case ConsoleMA:
rtl8168_asf_console_mac(tp, asf_usrdata.arg, asf_usrdata.u.data);
break;
case ConsoleIP:
rtl8168_asf_ip_address(tp, asf_usrdata.arg, ConsoleIP, asf_usrdata.u.data);
break;
case IPAddr:
rtl8168_asf_ip_address(tp, asf_usrdata.arg, IPAddr, asf_usrdata.u.data);
break;
case UUID:
rtl8168_asf_rw_uuid(tp, asf_usrdata.arg, asf_usrdata.u.data);
break;
case IANA:
rtl8168_asf_rw_iana(tp, asf_usrdata.arg, asf_usrdata.u.data);
break;
case SysID:
rtl8168_asf_rw_systemid(tp, asf_usrdata.arg, asf_usrdata.u.data);
break;
case Community:
rtl8168_asf_community_string(tp, asf_usrdata.arg, asf_usrdata.u.string);
break;
case StringLength:
rtl8168_asf_community_string_len(tp, asf_usrdata.arg, asf_usrdata.u.data);
break;
case FmCapMsk:
rtl8168_asf_capability_masks(tp, asf_usrdata.arg, FmCapMsk, asf_usrdata.u.data);
break;
case SpCMDMsk:
rtl8168_asf_capability_masks(tp, asf_usrdata.arg, SpCMDMsk, asf_usrdata.u.data);
break;
case SysCapMsk:
rtl8168_asf_capability_masks(tp, asf_usrdata.arg, SysCapMsk, asf_usrdata.u.data);
break;
case RmtRstAddr:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, RmtRstAddr, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case RmtRstCmd:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, RmtRstCmd, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case RmtRstData:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, RmtRstData, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case RmtPwrOffAddr:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, RmtPwrOffAddr, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case RmtPwrOffCmd:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, RmtPwrOffCmd, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case RmtPwrOffData:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, RmtPwrOffData, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case RmtPwrOnAddr:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, RmtPwrOnAddr, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case RmtPwrOnCmd:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, RmtPwrOnCmd, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case RmtPwrOnData:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, RmtPwrOnData, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case RmtPCRAddr:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, RmtPCRAddr, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case RmtPCRCmd:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, RmtPCRCmd, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case RmtPCRData:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, RmtPCRData, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case ASFSnsr0Addr:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, ASFSnsr0Addr, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case LSnsrAddr0:
rtl8168_asf_rw_hexadecimal(tp, asf_usrdata.arg, LSnsrAddr0, RW_ONE_BYTE, asf_usrdata.u.data);
break;
case KO:
/* Get/Set Key Operation */
rtl8168_asf_key_access(tp, asf_usrdata.arg, KO, asf_usrdata.u.data);
break;
case KA:
/* Get/Set Key Administrator */
rtl8168_asf_key_access(tp, asf_usrdata.arg, KA, asf_usrdata.u.data);
break;
case KG:
/* Get/Set Key Generation */
rtl8168_asf_key_access(tp, asf_usrdata.arg, KG, asf_usrdata.u.data);
break;
case KR:
/* Get/Set Key Random */
rtl8168_asf_key_access(tp, asf_usrdata.arg, KR, asf_usrdata.u.data);
break;
default:
return -EOPNOTSUPP;
}
if (copy_to_user(user_data, &asf_usrdata, sizeof(struct asf_ioctl_struct)))
return -EFAULT;
return 0;
}
void rtl8168_asf_hbperiod(struct rtl8168_private *tp, int arg, unsigned int *data)
{
if (arg == ASF_GET)
data[ASFHBPERIOD] = rtl8168_eri_read(tp, HBPeriod, RW_TWO_BYTES, ERIAR_ASF);
else if (arg == ASF_SET) {
rtl8168_eri_write(tp, HBPeriod, RW_TWO_BYTES, data[ASFHBPERIOD], ERIAR_ASF);
rtl8168_eri_write(tp, 0x1EC, RW_ONE_BYTE, 0x07, ERIAR_ASF);
}
}
void rtl8168_asf_wd16rst(struct rtl8168_private *tp, int arg, unsigned int *data)
{
data[ASFWD16RST] = rtl8168_eri_read(tp, WD16Rst, RW_TWO_BYTES, ERIAR_ASF);
}
void rtl8168_asf_console_mac(struct rtl8168_private *tp, int arg, unsigned int *data)
{
int i;
if (arg == ASF_GET) {
for (i = 0; i < 6; i++)
data[i] = rtl8168_eri_read(tp, ConsoleMA + i, RW_ONE_BYTE, ERIAR_ASF);
} else if (arg == ASF_SET) {
for (i = 0; i < 6; i++)
rtl8168_eri_write(tp, ConsoleMA + i, RW_ONE_BYTE, data[i], ERIAR_ASF);
/* write the new console MAC address to EEPROM */
rtl8168_eeprom_write_sc(tp, 70, (data[1] << 8) | data[0]);
rtl8168_eeprom_write_sc(tp, 71, (data[3] << 8) | data[2]);
rtl8168_eeprom_write_sc(tp, 72, (data[5] << 8) | data[4]);
}
}
void rtl8168_asf_ip_address(struct rtl8168_private *tp, int arg, int offset, unsigned int *data)
{
int i;
int eeprom_off = 0;
if (arg == ASF_GET) {
for (i = 0; i < 4; i++)
data[i] = rtl8168_eri_read(tp, offset + i, RW_ONE_BYTE, ERIAR_ASF);
} else if (arg == ASF_SET) {
for (i = 0; i < 4; i++)
rtl8168_eri_write(tp, offset + i, RW_ONE_BYTE, data[i], ERIAR_ASF);
if (offset == ConsoleIP)
eeprom_off = 73;
else if (offset == IPAddr)
eeprom_off = 75;
/* write the new IP address to EEPROM */
rtl8168_eeprom_write_sc(tp, eeprom_off, (data[1] << 8) | data[0]);
rtl8168_eeprom_write_sc(tp, eeprom_off + 1, (data[3] << 8) | data[2]);
}
}
void rtl8168_asf_config_regs(struct rtl8168_private *tp, int arg, int offset, unsigned int *data)
{
unsigned int value;
if (arg == ASF_GET) {
data[ASFCAPABILITY] = (rtl8168_eri_read(tp, offset, RW_ONE_BYTE, ERIAR_ASF) & data[ASFCONFIG]) ? FUNCTION_ENABLE : FUNCTION_DISABLE;
} else if (arg == ASF_SET) {
value = rtl8168_eri_read(tp, offset, RW_ONE_BYTE, ERIAR_ASF);
if (data[ASFCAPABILITY] == FUNCTION_ENABLE)
value |= data[ASFCONFIG];
else if (data[ASFCAPABILITY] == FUNCTION_DISABLE)
value &= ~data[ASFCONFIG];
rtl8168_eri_write(tp, offset, RW_ONE_BYTE, value, ERIAR_ASF);
}
}
void rtl8168_asf_capability_masks(struct rtl8168_private *tp, int arg, int offset, unsigned int *data)
{
unsigned int len, bit_mask;
bit_mask = DISABLE_MASK;
if (offset == FmCapMsk) {
/* System firmware capabilities */
len = RW_FOUR_BYTES;
if (data[ASFCAPMASK] == FUNCTION_ENABLE)
bit_mask = FMW_CAP_MASK;
} else if (offset == SpCMDMsk) {
/* Special commands */
len = RW_TWO_BYTES;
if (data[ASFCAPMASK] == FUNCTION_ENABLE)
bit_mask = SPC_CMD_MASK;
} else {
/* System capability (offset == SysCapMsk)*/
len = RW_ONE_BYTE;
if (data[ASFCAPMASK] == FUNCTION_ENABLE)
bit_mask = SYS_CAP_MASK;
}
if (arg == ASF_GET)
data[ASFCAPMASK] = rtl8168_eri_read(tp, offset, len, ERIAR_ASF) ? FUNCTION_ENABLE : FUNCTION_DISABLE;
else /* arg == ASF_SET */
rtl8168_eri_write(tp, offset, len, bit_mask, ERIAR_ASF);
}
void rtl8168_asf_community_string(struct rtl8168_private *tp, int arg, char *string)
{
int i;
if (arg == ASF_GET) {
for (i = 0; i < COMMU_STR_MAX_LEN; i++)
string[i] = rtl8168_eri_read(tp, Community + i, RW_ONE_BYTE, ERIAR_ASF);
} else { /* arg == ASF_SET */
for (i = 0; i < COMMU_STR_MAX_LEN; i++)
rtl8168_eri_write(tp, Community + i, RW_ONE_BYTE, string[i], ERIAR_ASF);
}
}
void rtl8168_asf_community_string_len(struct rtl8168_private *tp, int arg, unsigned int *data)
{
if (arg == ASF_GET)
data[ASFCOMMULEN] = rtl8168_eri_read(tp, StringLength, RW_ONE_BYTE, ERIAR_ASF);
else /* arg == ASF_SET */
rtl8168_eri_write(tp, StringLength, RW_ONE_BYTE, data[ASFCOMMULEN], ERIAR_ASF);
}
void rtl8168_asf_time_period(struct rtl8168_private *tp, int arg, int offset, unsigned int *data)
{
int pos = 0;
if (offset == WD8Rst)
pos = ASFWD8RESET;
else if (offset == LSnsrPollCycle)
pos = ASFLSNRPOLLCYC;
else if (offset == ASFSnsrPollPrd)
pos = ASFSNRPOLLCYC;
else if (offset == AlertReSendItvl)
pos = ASFALERTRESND;
if (arg == ASF_GET)
data[pos] = rtl8168_eri_read(tp, offset, RW_ONE_BYTE, ERIAR_ASF);
else /* arg == ASF_SET */
rtl8168_eri_write(tp, offset, RW_ONE_BYTE, data[pos], ERIAR_ASF);
}
void rtl8168_asf_key_access(struct rtl8168_private *tp, int arg, int offset, unsigned int *data)
{
int i, j;
int key_off = 0;
if (arg == ASF_GET) {
for (i = 0; i < KEY_LEN; i++)
data[i] = rtl8168_eri_read(tp, offset + KEY_LEN - (i + 1), RW_ONE_BYTE, ERIAR_ASF);
} else {
if (offset == KO)
key_off = 162;
else if (offset == KA)
key_off = 172;
else if (offset == KG)
key_off = 182;
else if (offset == KR)
key_off = 192;
/* arg == ASF_SET */
for (i = 0; i < KEY_LEN; i++)
rtl8168_eri_write(tp, offset + KEY_LEN - (i + 1), RW_ONE_BYTE, data[i], ERIAR_ASF);
/* write the new key to EEPROM */
for (i = 0, j = 19; i < 10; i++, j = j - 2)
rtl8168_eeprom_write_sc(tp, key_off + i, (data[j - 1] << 8) | data[j]);
}
}
void rtl8168_asf_rw_hexadecimal(struct rtl8168_private *tp, int arg, int offset, int len, unsigned int *data)
{
if (arg == ASF_GET)
data[ASFRWHEXNUM] = rtl8168_eri_read(tp, offset, len, ERIAR_ASF);
else /* arg == ASF_SET */
rtl8168_eri_write(tp, offset, len, data[ASFRWHEXNUM], ERIAR_ASF);
}
void rtl8168_asf_rw_systemid(struct rtl8168_private *tp, int arg, unsigned int *data)
{
int i;
if (arg == ASF_GET)
for (i = 0; i < SYSID_LEN; i++)
data[i] = rtl8168_eri_read(tp, SysID + i, RW_ONE_BYTE, ERIAR_ASF);
else /* arg == ASF_SET */
for (i = 0; i < SYSID_LEN; i++)
rtl8168_eri_write(tp, SysID + i, RW_ONE_BYTE, data[i], ERIAR_ASF);
}
void rtl8168_asf_rw_iana(struct rtl8168_private *tp, int arg, unsigned int *data)
{
int i;
if (arg == ASF_GET)
for (i = 0; i < RW_FOUR_BYTES; i++)
data[i] = rtl8168_eri_read(tp, IANA + i, RW_ONE_BYTE, ERIAR_ASF);
else /* arg == ASF_SET */
for (i = 0; i < RW_FOUR_BYTES; i++)
rtl8168_eri_write(tp, IANA + i, RW_ONE_BYTE, data[i], ERIAR_ASF);
}
void rtl8168_asf_rw_uuid(struct rtl8168_private *tp, int arg, unsigned int *data)
{
int i, j;
if (arg == ASF_GET)
for (i = UUID_LEN - 1, j = 0; i >= 0; i--, j++)
data[j] = rtl8168_eri_read(tp, UUID + i, RW_ONE_BYTE, ERIAR_ASF);
else /* arg == ASF_SET */
for (i = UUID_LEN - 1, j = 0; i >= 0; i--, j++)
rtl8168_eri_write(tp, UUID + i, RW_ONE_BYTE, data[j], ERIAR_ASF);
}

View File

@ -0,0 +1,295 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#define SIOCDEVPRIVATE_RTLASF SIOCDEVPRIVATE
#define FUNCTION_ENABLE 1
#define FUNCTION_DISABLE 0
#define ASFCONFIG 0
#define ASFCAPABILITY 1
#define ASFCOMMULEN 0
#define ASFHBPERIOD 0
#define ASFWD16RST 0
#define ASFCAPMASK 0
#define ASFALERTRESND 0
#define ASFLSNRPOLLCYC 0
#define ASFSNRPOLLCYC 0
#define ASFWD8RESET 0
#define ASFRWHEXNUM 0
#define FMW_CAP_MASK 0x0000F867
#define SPC_CMD_MASK 0x1F00
#define SYS_CAP_MASK 0xFF
#define DISABLE_MASK 0x00
#define MAX_DATA_LEN 200
#define MAX_STR_LEN 200
#define COMMU_STR_MAX_LEN 23
#define KEY_LEN 20
#define UUID_LEN 16
#define SYSID_LEN 2
#define RW_ONE_BYTE 1
#define RW_TWO_BYTES 2
#define RW_FOUR_BYTES 4
enum asf_registers {
HBPeriod = 0x0000,
WD8Rst = 0x0002,
WD8Timer = 0x0003,
WD16Rst = 0x0004,
LSnsrPollCycle = 0x0006,
ASFSnsrPollPrd = 0x0007,
AlertReSendCnt = 0x0008,
AlertReSendItvl = 0x0009,
SMBAddr = 0x000A,
SMBCap = 0x000B,
ASFConfigR0 = 0x000C,
ASFConfigR1 = 0x000D,
WD16Timer = 0x000E,
ConsoleMA = 0x0010,
ConsoleIP = 0x0016,
IPAddr = 0x001A,
UUID = 0x0020,
IANA = 0x0030,
SysID = 0x0034,
Community = 0x0036,
StringLength = 0x004D,
LC = 0x004E,
EntityInst = 0x004F,
FmCapMsk = 0x0050,
SpCMDMsk = 0x0054,
SysCapMsk = 0x0056,
WDSysSt = 0x0057,
RxMsgType = 0x0058,
RxSpCMD = 0x0059,
RxSpCMDPa = 0x005A,
RxBtOpMsk = 0x005C,
RmtRstAddr = 0x005E,
RmtRstCmd = 0x005F,
RmtRstData = 0x0060,
RmtPwrOffAddr = 0x0061,
RmtPwrOffCmd = 0x0062,
RmtPwrOffData = 0x0063,
RmtPwrOnAddr = 0x0064,
RmtPwrOnCmd = 0x0065,
RmtPwrOnData = 0x0066,
RmtPCRAddr = 0x0067,
RmtPCRCmd = 0x0068,
RmtPCRData = 0x0069,
RMCP_IANA = 0x006A,
RMCP_OEM = 0x006E,
ASFSnsr0Addr = 0x0070,
ASFSnsrEvSt = 0x0073,
ASFSnsrEvAlert = 0x0081,
LSnsrNo = 0x00AD,
AssrtEvntMsk = 0x00AE,
DeAssrtEvntMsk = 0x00AF,
LSnsrAddr0 = 0x00B0,
LAlertCMD0 = 0x00B1,
LAlertDataMsk0 = 0x00B2,
LAlertCmp0 = 0x00B3,
LAlertESnsrT0 = 0x00B4,
LAlertET0 = 0x00B5,
LAlertEOffset0 = 0x00B6,
LAlertES0 = 0x00B7,
LAlertSN0 = 0x00B8,
LAlertEntity0 = 0x00B9,
LAlertEI0 = 0x00BA,
LSnsrState0 = 0x00BB,
LSnsrAddr1 = 0x00BD,
LAlertCMD1 = 0x00BE,
LAlertDataMsk1 = 0x00BF,
LAlertCmp1 = 0x00C0,
LAlertESnsrT1 = 0x00C1,
LAlertET1 = 0x00C2,
LAlertEOffset1 = 0x00C3,
LAlertES1 = 0x00C4,
LAlertSN1 = 0x00C5,
LAlertEntity1 = 0x00C6,
LAlertEI1 = 0x00C7,
LSnsrState1 = 0x00C8,
LSnsrAddr2 = 0x00CA,
LAlertCMD2 = 0x00CB,
LAlertDataMsk2 = 0x00CC,
LAlertCmp2 = 0x00CD,
LAlertESnsrT2 = 0x00CE,
LAlertET2 = 0x00CF,
LAlertEOffset2 = 0x00D0,
LAlertES2 = 0x00D1,
LAlertSN2 = 0x00D2,
LAlertEntity2 = 0x00D3,
LAlertEI2 = 0x00D4,
LSnsrState2 = 0x00D5,
LSnsrAddr3 = 0x00D7,
LAlertCMD3 = 0x00D8,
LAlertDataMsk3 = 0x00D9,
LAlertCmp3 = 0x00DA,
LAlertESnsrT3 = 0x00DB,
LAlertET3 = 0x00DC,
LAlertEOffset3 = 0x00DD,
LAlertES3 = 0x00DE,
LAlertSN3 = 0x00DF,
LAlertEntity3 = 0x00E0,
LAlertEI3 = 0x00E1,
LSnsrState3 = 0x00E2,
LSnsrAddr4 = 0x00E4,
LAlertCMD4 = 0x00E5,
LAlertDataMsk4 = 0x00E6,
LAlertCmp4 = 0x00E7,
LAlertESnsrT4 = 0x00E8,
LAlertET4 = 0x00E9,
LAlertEOffset4 = 0x00EA,
LAlertES4 = 0x00EB,
LAlertSN4 = 0x00EC,
LAlertEntity4 = 0x00ED,
LAlertEI4 = 0x00EE,
LSnsrState4 = 0x00EF,
LSnsrAddr5 = 0x00F1,
LAlertCMD5 = 0x00F2,
LAlertDataMsk5 = 0x00F3,
LAlertCmp5 = 0x00F4,
LAlertESnsrT5 = 0x00F5,
LAlertET5 = 0x00F6,
LAlertEOffset5 = 0x00F7,
LAlertES5 = 0x00F8,
LAlertSN5 = 0x00F9,
LAlertEntity5 = 0x00FA,
LAlertEI5 = 0x00FB,
LSnsrState5 = 0x00FC,
LSnsrAddr6 = 0x00FE,
LAlertCMD6 = 0x00FF,
LAlertDataMsk6 = 0x0100,
LAlertCmp6 = 0x0101,
LAlertESnsrT6 = 0x0102,
LAlertET6 = 0x0103,
LAlertEOffset6 = 0x0104,
LAlertES6 = 0x0105,
LAlertSN6 = 0x0106,
LAlertEntity6 = 0x0107,
LAlertEI6 = 0x0108,
LSnsrState6 = 0x0109,
LSnsrAddr7 = 0x010B,
LAlertCMD7 = 0x010C,
LAlertDataMsk7 = 0x010D,
LAlertCmp7 = 0x010E,
LAlertESnsrT7 = 0x010F,
LAlertET7 = 0x0110,
LAlertEOffset7 = 0x0111,
LAlertES7 = 0x0112,
LAlertSN7 = 0x0113,
LAlertEntity7 = 0x0114,
LAlertEI7 = 0x0115,
LSnsrState7 = 0x0116,
LAssert = 0x0117,
LDAssert = 0x0118,
IPServiceType = 0x0119,
IPIdfr = 0x011A,
FlagFOffset = 0x011C,
TTL = 0x011E,
HbtEI = 0x011F,
MgtConSID1 = 0x0120,
MgtConSID2 = 0x0124,
MgdCltSID = 0x0128,
StCd = 0x012C,
MgtConUR = 0x012D,
MgtConUNL = 0x012E,
AuthPd = 0x0130,
IntyPd = 0x0138,
MgtConRN = 0x0140,
MgdCtlRN = 0x0150,
MgtConUN = 0x0160,
Rakp2IntCk = 0x0170,
KO = 0x017C,
KA = 0x0190,
KG = 0x01A4,
KR = 0x01B8,
CP = 0x01CC,
CQ = 0x01D0,
KC = 0x01D4,
ConsoleSid = 0x01E8,
SIK1 = 0x01FC,
SIK2 = 0x0210,
Udpsrc_port = 0x0224,
Udpdes_port = 0x0226,
Asf_debug_mux = 0x0228
};
enum asf_cmdln_opt {
ASF_GET,
ASF_SET,
ASF_HELP
};
struct asf_ioctl_struct {
unsigned int arg;
unsigned int offset;
union {
unsigned int data[MAX_DATA_LEN];
char string[MAX_STR_LEN];
} u;
};
int rtl8168_asf_ioctl(struct net_device *dev, struct ifreq *ifr);
void rtl8168_asf_hbperiod(struct rtl8168_private *tp, int arg, unsigned int *data);
void rtl8168_asf_wd16rst(struct rtl8168_private *tp, int arg, unsigned int *data);
void rtl8168_asf_console_mac(struct rtl8168_private *, int arg, unsigned int *data);
void rtl8168_asf_ip_address(struct rtl8168_private *, int arg, int offset, unsigned int *data);
void rtl8168_asf_config_regs(struct rtl8168_private *tp, int arg, int offset, unsigned int *data);
void rtl8168_asf_capability_masks(struct rtl8168_private *tp, int arg, int offset, unsigned int *data);
void rtl8168_asf_community_string(struct rtl8168_private *tp, int arg, char *string);
void rtl8168_asf_community_string_len(struct rtl8168_private *tp, int arg, unsigned int *data);
void rtl8168_asf_alert_resend_interval(struct rtl8168_private *tp, int arg, unsigned int *data);
void rtl8168_asf_time_period(struct rtl8168_private *tp, int arg, int offset, unsigned int *data);
void rtl8168_asf_key_access(struct rtl8168_private *, int arg, int offset, unsigned int *data);
void rtl8168_asf_rw_hexadecimal(struct rtl8168_private *tp, int arg, int offset, int len, unsigned int *data);
void rtl8168_asf_rw_iana(struct rtl8168_private *tp, int arg, unsigned int *data);
void rtl8168_asf_rw_uuid(struct rtl8168_private *tp, int arg, unsigned int *data);
void rtl8168_asf_rw_systemid(struct rtl8168_private *tp, int arg, unsigned int *data);

View File

@ -0,0 +1,261 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_R8168_DASH_H
#define _LINUX_R8168_DASH_H
#define SIOCDEVPRIVATE_RTLDASH SIOCDEVPRIVATE+2
enum rtl_dash_cmd {
RTL_DASH_ARP_NS_OFFLOAD = 0,
RTL_DASH_SET_OOB_IPMAC,
RTL_DASH_NOTIFY_OOB,
RTL_DASH_SEND_BUFFER_DATA_TO_DASH_FW,
RTL_DASH_CHECK_SEND_BUFFER_TO_DASH_FW_COMPLETE,
RTL_DASH_GET_RCV_FROM_FW_BUFFER_DATA,
RTL_DASH_OOB_REQ,
RTL_DASH_OOB_ACK,
RTL_DASH_DETACH_OOB_REQ,
RTL_DASH_DETACH_OOB_ACK,
RTL_FW_SET_IPV4 = 0x10,
RTL_FW_GET_IPV4,
RTL_FW_SET_IPV6,
RTL_FW_GET_IPV6,
RTL_FW_SET_EXT_SNMP,
RTL_FW_GET_EXT_SNMP,
RTL_FW_SET_WAKEUP_PATTERN,
RTL_FW_GET_WAKEUP_PATTERN,
RTL_FW_DEL_WAKEUP_PATTERN,
RTLT_DASH_COMMAND_INVALID,
};
struct rtl_dash_ip_mac {
struct sockaddr ifru_addr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
};
struct rtl_dash_ioctl_struct {
__u32 cmd;
__u32 offset;
__u32 len;
union {
__u32 data;
void *data_buffer;
};
};
struct settings_ipv4 {
__u32 IPv4addr;
__u32 IPv4mask;
__u32 IPv4Gateway;
};
struct settings_ipv6 {
__u32 reserved;
__u32 prefixLen;
__u16 IPv6addr[8];
__u16 IPv6Gateway[8];
};
struct settings_ext_snmp {
__u16 index;
__u16 oid_get_len;
__u8 oid_for_get[24];
__u8 reserved0[26];
__u16 value_len;
__u8 value[256];
__u8 supported;
__u8 reserved1[27];
};
struct wakeup_pattern {
__u8 index;
__u8 valid;
__u8 start;
__u8 length;
__u8 name[36];
__u8 mask[16];
__u8 pattern[128];
__u32 reserved[2];
};
typedef struct _RX_DASH_FROM_FW_DESC {
__le16 length;
__le16 status;
__le32 resv;
__le64 BufferAddress;
}
RX_DASH_FROM_FW_DESC, *PRX_DASH_FROM_FW_DESC;
typedef struct _TX_DASH_SEND_FW_DESC {
__le16 length;
__le16 status;
__le32 resv;
__le64 BufferAddress;
}
TX_DASH_SEND_FW_DESC, *PTX_DASH_SEND_FW_DESC;
typedef struct _OSOOBHdr {
__le32 len;
u8 type;
u8 flag;
u8 hostReqV;
u8 res;
}
OSOOBHdr, *POSOOBHdr;
typedef struct _RX_DASH_BUFFER_TYPE_2 {
OSOOBHdr oobhdr;
u8 RxDataBuffer[0];
}
RX_DASH_BUFFER_TYPE_2, *PRX_DASH_BUFFER_TYPE_2;
#define ALIGN_8 (0x7)
#define ALIGN_16 (0xf)
#define ALIGN_32 (0x1f)
#define ALIGN_64 (0x3f)
#define ALIGN_256 (0xff)
#define ALIGN_4096 (0xfff)
#define OCP_REG_CONFIG0 (0x10)
#define OCP_REG_CONFIG0_REV_F (0xB8)
#define OCP_REG_DASH_POLL (0x30)
#define OCP_REG_HOST_REQ (0x34)
#define OCP_REG_DASH_REQ (0x35)
#define OCP_REG_CR (0x36)
#define OCP_REG_DMEMSTA (0x38)
#define OCP_REG_GPHYAR (0x60)
#define OCP_REG_FIRMWARE_MAJOR_VERSION (0x120)
#define OCP_REG_CONFIG0_DASHEN BIT_15
#define OCP_REG_CONFIG0_OOBRESET BIT_14
#define OCP_REG_CONFIG0_APRDY BIT_13
#define OCP_REG_CONFIG0_FIRMWARERDY BIT_12
#define OCP_REG_CONFIG0_DRIVERRDY BIT_11
#define OCP_REG_CONFIG0_OOB_WDT BIT_9
#define OCP_REG_CONFIG0_DRV_WAIT_OOB BIT_8
#define OCP_REG_CONFIG0_TLSEN BIT_7
#define HW_DASH_SUPPORT_DASH(_M) ((_M)->HwSuppDashVer > 0)
#define HW_DASH_SUPPORT_TYPE_1(_M) ((_M)->HwSuppDashVer == 1)
#define HW_DASH_SUPPORT_TYPE_2(_M) ((_M)->HwSuppDashVer == 2)
#define HW_DASH_SUPPORT_TYPE_3(_M) ((_M)->HwSuppDashVer == 3)
#define HW_DASH_SUPPORT_CMAC(_M) (HW_DASH_SUPPORT_TYPE_2(_M) || HW_DASH_SUPPORT_TYPE_3(_M))
#define HW_DASH_SUPPORT_GET_FIRMWARE_VERSION(_M) (HW_DASH_SUPPORT_TYPE_2(_M) || \
HW_DASH_SUPPORT_TYPE_3(_M))
#define RECV_FROM_FW_BUF_SIZE (2048)
#define SEND_TO_FW_BUF_SIZE (2048)
#define RX_DASH_FROM_FW_OWN BIT_15
#define TX_DASH_SEND_FW_OWN BIT_15
#define TXS_CC3_0 (BIT_0|BIT_1|BIT_2|BIT_3)
#define TXS_EXC BIT_4
#define TXS_LNKF BIT_5
#define TXS_OWC BIT_6
#define TXS_TES BIT_7
#define TXS_UNF BIT_9
#define TXS_LGSEN BIT_11
#define TXS_LS BIT_12
#define TXS_FS BIT_13
#define TXS_EOR BIT_14
#define TXS_OWN BIT_15
#define TPPool_HRDY 0x20
#define HostReqReg (0xC0)
#define SystemMasterDescStartAddrLow (0xF0)
#define SystemMasterDescStartAddrHigh (0xF4)
#define SystemSlaveDescStartAddrLow (0xF8)
#define SystemSlaveDescStartAddrHigh (0xFC)
//DASH Request Type
#define WSMANREG 0x01
#define OSPUSHDATA 0x02
#define RXS_OWN BIT_15
#define RXS_EOR BIT_14
#define RXS_FS BIT_13
#define RXS_LS BIT_12
#define ISRIMR_DP_DASH_OK BIT_15
#define ISRIMR_DP_HOST_OK BIT_13
#define ISRIMR_DP_REQSYS_OK BIT_11
#define ISRIMR_DASH_INTR_EN BIT_12
#define ISRIMR_DASH_INTR_CMAC_RESET BIT_15
#define ISRIMR_DASH_TYPE2_ROK BIT_0
#define ISRIMR_DASH_TYPE2_RDU BIT_1
#define ISRIMR_DASH_TYPE2_TOK BIT_2
#define ISRIMR_DASH_TYPE2_TDU BIT_3
#define ISRIMR_DASH_TYPE2_TX_FIFO_FULL BIT_4
#define ISRIMR_DASH_TYPE2_TX_DISABLE_IDLE BIT_5
#define ISRIMR_DASH_TYPE2_RX_DISABLE_IDLE BIT_6
#define CMAC_OOB_STOP 0x25
#define CMAC_OOB_INIT 0x26
#define CMAC_OOB_RESET 0x2a
#define NO_BASE_ADDRESS 0x00000000
#define RTL8168FP_OOBMAC_BASE 0xBAF70000
#define RTL8168FP_CMAC_IOBASE 0xBAF20000
#define RTL8168FP_KVM_BASE 0xBAF80400
#define CMAC_SYNC_REG 0x20
#define CMAC_RXDESC_OFFSET 0x90 //RX: 0x90 - 0x98
#define CMAC_TXDESC_OFFSET 0x98 //TX: 0x98 - 0x9F
/* cmac write/read MMIO register */
#define RTL_CMAC_W8(tp, reg, val8) writeb ((val8), tp->cmac_ioaddr + (reg))
#define RTL_CMAC_W16(tp, reg, val16) writew ((val16), tp->cmac_ioaddr + (reg))
#define RTL_CMAC_W32(tp, reg, val32) writel ((val32), tp->cmac_ioaddr + (reg))
#define RTL_CMAC_R8(tp, reg) readb (tp->cmac_ioaddr + (reg))
#define RTL_CMAC_R16(tp, reg) readw (tp->cmac_ioaddr + (reg))
#define RTL_CMAC_R32(tp, reg) ((unsigned long) readl (tp->cmac_ioaddr + (reg)))
int rtl8168_dash_ioctl(struct net_device *dev, struct ifreq *ifr);
bool CheckDashInterrupt(struct net_device *dev, u16 status);
void HandleDashInterrupt(struct net_device *dev);
int AllocateDashShareMemory(struct net_device *dev);
void FreeAllocatedDashShareMemory(struct net_device *dev);
void DashHwInit(struct net_device *dev);
#endif /* _LINUX_R8168_DASH_H */

View File

@ -0,0 +1,75 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_R8168_FIBER_H
#define _LINUX_R8168_FIBER_H
enum {
FIBER_MODE_NIC_ONLY = 0,
FIBER_MODE_RTL8168H_RTL8211FS,
FIBER_MODE_RTL8168H_MDI_SWITCH_RTL8211FS,
FIBER_MODE_MAX
};
enum {
FIBER_STAT_NOT_CHECKED = 0,
FIBER_STAT_CONNECT_EEPROM,
FIBER_STAT_DISCONNECT,
FIBER_STAT_CONNECT_GPO,
FIBER_STAT_MAX
};
enum {
FIBER_LED_MODE_DEFAULT = 0,
FIBER_LED_MODE_1,
FIBER_LED_MODE_MAX
};
#define HW_FIBER_MODE_ENABLED(_M) ((_M)->HwFiberModeVer > 0)
#define HW_FIBER_STATUS_CONNECTED(_M) (((_M)->HwFiberStat == FIBER_STAT_CONNECT_EEPROM) || ((_M)->HwFiberStat == FIBER_STAT_CONNECT_GPO))
#define HW_FIBER_STATUS_DISCONNECTED(_M) ((_M)->HwFiberStat == FIBER_STAT_DISCONNECT)
struct rtl8168_private;
void rtl8168_hw_init_fiber_nic(struct rtl8168_private *tp);
void rtl8168_hw_fiber_nic_d3_para(struct rtl8168_private *tp);
void rtl8168_hw_fiber_phy_config(struct rtl8168_private *tp);
void rtl8168_hw_switch_mdi_to_fiber(struct rtl8168_private *tp);
void rtl8168_hw_switch_mdi_to_nic(struct rtl8168_private *tp);
unsigned int rtl8168_hw_fiber_link_ok(struct rtl8168_private *tp);
void rtl8168_check_fiber_link_status(struct rtl8168_private *tp);
void rtl8168_check_hw_fiber_mode_support(struct rtl8168_private *tp);
void rtl8168_set_fiber_mode_software_variable(struct rtl8168_private *tp);
#endif /* _LINUX_R8168_FIBER_H */

View File

@ -0,0 +1,264 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
################################################################################
#
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/version.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include "r8168_firmware.h"
enum rtl_fw_opcode {
PHY_READ = 0x0,
PHY_DATA_OR = 0x1,
PHY_DATA_AND = 0x2,
PHY_BJMPN = 0x3,
PHY_MDIO_CHG = 0x4,
PHY_CLEAR_READCOUNT = 0x7,
PHY_WRITE = 0x8,
PHY_READCOUNT_EQ_SKIP = 0x9,
PHY_COMP_EQ_SKIPN = 0xa,
PHY_COMP_NEQ_SKIPN = 0xb,
PHY_WRITE_PREVIOUS = 0xc,
PHY_SKIPN = 0xd,
PHY_DELAY_MS = 0xe,
};
struct fw_info {
u32 magic;
char version[RTL8168_VER_SIZE];
__le32 fw_start;
__le32 fw_len;
u8 chksum;
} __packed;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,16,0)
#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
#endif
#define FW_OPCODE_SIZE sizeof_field(struct rtl8168_fw_phy_action, code[0])
static bool rtl8168_fw_format_ok(struct rtl8168_fw *rtl_fw)
{
const struct firmware *fw = rtl_fw->fw;
struct fw_info *fw_info = (struct fw_info *)fw->data;
struct rtl8168_fw_phy_action *pa = &rtl_fw->phy_action;
if (fw->size < FW_OPCODE_SIZE)
return false;
if (!fw_info->magic) {
size_t i, size, start;
u8 checksum = 0;
if (fw->size < sizeof(*fw_info))
return false;
for (i = 0; i < fw->size; i++)
checksum += fw->data[i];
if (checksum != 0)
return false;
start = le32_to_cpu(fw_info->fw_start);
if (start > fw->size)
return false;
size = le32_to_cpu(fw_info->fw_len);
if (size > (fw->size - start) / FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, fw_info->version, RTL8168_VER_SIZE);
pa->code = (__le32 *)(fw->data + start);
pa->size = size;
} else {
if (fw->size % FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, rtl_fw->fw_name, RTL8168_VER_SIZE);
pa->code = (__le32 *)fw->data;
pa->size = fw->size / FW_OPCODE_SIZE;
}
return true;
}
static bool rtl8168_fw_data_ok(struct rtl8168_fw *rtl_fw)
{
struct rtl8168_fw_phy_action *pa = &rtl_fw->phy_action;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 val = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
switch (action >> 28) {
case PHY_READ:
case PHY_DATA_OR:
case PHY_DATA_AND:
case PHY_CLEAR_READCOUNT:
case PHY_WRITE:
case PHY_WRITE_PREVIOUS:
case PHY_DELAY_MS:
break;
case PHY_MDIO_CHG:
if (val > 1)
goto out;
break;
case PHY_BJMPN:
if (regno > index)
goto out;
break;
case PHY_READCOUNT_EQ_SKIP:
if (index + 2 >= pa->size)
goto out;
break;
case PHY_COMP_EQ_SKIPN:
case PHY_COMP_NEQ_SKIPN:
case PHY_SKIPN:
if (index + 1 + regno >= pa->size)
goto out;
break;
default:
dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
return false;
}
}
return true;
out:
dev_err(rtl_fw->dev, "Out of range of firmware\n");
return false;
}
void rtl8168_fw_write_firmware(struct rtl8168_private *tp, struct rtl8168_fw *rtl_fw)
{
struct rtl8168_fw_phy_action *pa = &rtl_fw->phy_action;
rtl8168_fw_write_t fw_write = rtl_fw->phy_write;
rtl8168_fw_read_t fw_read = rtl_fw->phy_read;
int predata = 0, count = 0;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 data = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
enum rtl_fw_opcode opcode = action >> 28;
if (!action)
break;
switch (opcode) {
case PHY_READ:
predata = fw_read(tp, regno);
count++;
break;
case PHY_DATA_OR:
predata |= data;
break;
case PHY_DATA_AND:
predata &= data;
break;
case PHY_BJMPN:
index -= (regno + 1);
break;
case PHY_MDIO_CHG:
if (data) {
fw_write = rtl_fw->mac_mcu_write;
fw_read = rtl_fw->mac_mcu_read;
} else {
fw_write = rtl_fw->phy_write;
fw_read = rtl_fw->phy_read;
}
break;
case PHY_CLEAR_READCOUNT:
count = 0;
break;
case PHY_WRITE:
fw_write(tp, regno, data);
break;
case PHY_READCOUNT_EQ_SKIP:
if (count == data)
index++;
break;
case PHY_COMP_EQ_SKIPN:
if (predata == data)
index += regno;
break;
case PHY_COMP_NEQ_SKIPN:
if (predata != data)
index += regno;
break;
case PHY_WRITE_PREVIOUS:
fw_write(tp, regno, predata);
break;
case PHY_SKIPN:
index += regno;
break;
case PHY_DELAY_MS:
mdelay(data);
break;
}
}
}
void rtl8168_fw_release_firmware(struct rtl8168_fw *rtl_fw)
{
release_firmware(rtl_fw->fw);
}
int rtl8168_fw_request_firmware(struct rtl8168_fw *rtl_fw)
{
int rc;
rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
if (rc < 0)
goto out;
if (!rtl8168_fw_format_ok(rtl_fw) || !rtl8168_fw_data_ok(rtl_fw)) {
release_firmware(rtl_fw->fw);
rc = -EINVAL;
goto out;
}
return 0;
out:
dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
rtl_fw->fw_name, rc);
return rc;
}

View File

@ -0,0 +1,68 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8168 is the Linux device driver released for Realtek 2.5Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_RTL8168_FIRMWARE_H
#define _LINUX_RTL8168_FIRMWARE_H
#include <linux/device.h>
#include <linux/firmware.h>
struct rtl8168_private;
typedef void (*rtl8168_fw_write_t)(struct rtl8168_private *tp, u16 reg, u16 val);
typedef u32 (*rtl8168_fw_read_t)(struct rtl8168_private *tp, u16 reg);
#define RTL8168_VER_SIZE 32
struct rtl8168_fw {
rtl8168_fw_write_t phy_write;
rtl8168_fw_read_t phy_read;
rtl8168_fw_write_t mac_mcu_write;
rtl8168_fw_read_t mac_mcu_read;
const struct firmware *fw;
const char *fw_name;
struct device *dev;
char version[RTL8168_VER_SIZE];
struct rtl8168_fw_phy_action {
__le32 *code;
size_t size;
} phy_action;
};
int rtl8168_fw_request_firmware(struct rtl8168_fw *rtl_fw);
void rtl8168_fw_release_firmware(struct rtl8168_fw *rtl_fw);
void rtl8168_fw_write_firmware(struct rtl8168_private *tp, struct rtl8168_fw *rtl_fw);
#endif /* _LINUX_RTL8168_FIRMWARE_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,118 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_R8168_REALWOW_H
#define _LINUX_R8168_REALWOW_H
#define SIOCDEVPRIVATE_RTLREALWOW SIOCDEVPRIVATE+3
#define MAX_RealWoW_KCP_SIZE (100)
#define MAX_RealWoW_Payload (64)
#define KA_TX_PACKET_SIZE (100)
#define KA_WAKEUP_PATTERN_SIZE (120)
//HwSuppKeepAliveOffloadVer
#define HW_SUPPORT_KCP_OFFLOAD(_M) ((_M)->HwSuppKCPOffloadVer > 0)
enum rtl_realwow_cmd {
RTL_REALWOW_SET_KCP_DISABLE=0,
RTL_REALWOW_SET_KCP_INFO,
RTL_REALWOW_SET_KCP_CONTENT,
RTL_REALWOW_SET_KCP_ACKPKTINFO,
RTL_REALWOW_SET_KCP_WPINFO,
RTL_REALWOW_SET_KCPDHCP_TIMEOUT,
RTLT_REALWOW_COMMAND_INVALID
};
struct rtl_realwow_ioctl_struct {
__u32 cmd;
__u32 offset;
__u32 len;
union {
__u32 data;
void *data_buffer;
};
};
typedef struct _MP_KCPInfo {
u8 DIPv4[4];
u8 MacID[6];
u16 UdpPort[2];
u8 PKTLEN[2];
u16 ackLostCnt;
u8 KCP_WakePattern[MAX_RealWoW_Payload];
u8 KCP_AckPacket[MAX_RealWoW_Payload];
u32 KCP_interval;
u8 KCP_WakePattern_Len;
u8 KCP_AckPacket_Len;
u8 KCP_TxPacket[2][KA_TX_PACKET_SIZE];
} MP_KCP_INFO, *PMP_KCP_INFO;
typedef struct _KCPInfo {
u32 nId; // = id
u8 DIPv4[4];
u8 MacID[6];
u16 UdpPort;
u16 PKTLEN;
} KCPInfo, *PKCPInfo;
typedef struct _KCPContent {
u32 id; // = id
u32 mSec; // = msec
u32 size; // =size
u8 bPacket[MAX_RealWoW_KCP_SIZE]; // put packet here
} KCPContent, *PKCPContent;
typedef struct _RealWoWAckPktInfo {
u16 ackLostCnt;
u16 patterntSize;
u8 pattern[MAX_RealWoW_Payload];
} RealWoWAckPktInfo,*PRealWoWAckPktInfo;
typedef struct _RealWoWWPInfo {
u16 patterntSize;
u8 pattern[MAX_RealWoW_Payload];
} RealWoWWPInfo,*PRealWoWWPInfo;
int rtl8168_realwow_ioctl(struct net_device *dev, struct ifreq *ifr);
void rtl8168_realwow_hw_init(struct net_device *dev);
void rtl8168_get_realwow_hw_version(struct net_device *dev);
void rtl8168_set_realwow_d3_para(struct net_device *dev);
#endif /* _LINUX_R8168_REALWOW_H */

View File

@ -0,0 +1,482 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
################################################################################
#
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/version.h>
#include "r8168.h"
enum rtl8168_rss_register_content {
/* RSS */
RSS_CTRL_TCP_IPV4_SUPP = (1 << 0),
RSS_CTRL_IPV4_SUPP = (1 << 1),
RSS_CTRL_TCP_IPV6_SUPP = (1 << 2),
RSS_CTRL_IPV6_SUPP = (1 << 3),
RSS_CTRL_IPV6_EXT_SUPP = (1 << 4),
RSS_CTRL_TCP_IPV6_EXT_SUPP = (1 << 5),
RSS_HALF_SUPP = (1 << 7),
RSS_QUAD_CPU_EN = (1 << 16),
RSS_HQ_Q_SUP_R = (1 << 31),
};
static int rtl8168_get_rss_hash_opts(struct rtl8168_private *tp,
struct ethtool_rxnfc *cmd)
{
cmd->data = 0;
/* Report default options for RSS */
switch (cmd->flow_type) {
case TCP_V4_FLOW:
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough;
case IPV4_FLOW:
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
break;
case TCP_V6_FLOW:
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough;
case IPV6_FLOW:
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
break;
default:
return -EINVAL;
}
return 0;
}
int rtl8168_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
u32 *rule_locs)
{
struct rtl8168_private *tp = netdev_priv(dev);
int ret = -EOPNOTSUPP;
if (!(dev->features & NETIF_F_RXHASH))
return ret;
switch (cmd->cmd) {
case ETHTOOL_GRXRINGS:
cmd->data = rtl8168_tot_rx_rings(tp);
ret = 0;
break;
case ETHTOOL_GRXFH:
ret = rtl8168_get_rss_hash_opts(tp, cmd);
break;
default:
break;
}
return ret;
}
u32 rtl8168_rss_indir_tbl_entries(struct rtl8168_private *tp)
{
return tp->HwSuppIndirTblEntries;
}
#define RSS_MASK_BITS_OFFSET (8)
static int _rtl8168_set_rss_hash_opt(struct rtl8168_private *tp)
{
u32 hash_mask_len;
u32 rss_ctrl;
/* Perform hash on these packet types */
rss_ctrl = RSS_CTRL_TCP_IPV4_SUPP
| RSS_CTRL_IPV4_SUPP
| RSS_CTRL_IPV6_SUPP
| RSS_CTRL_IPV6_EXT_SUPP
| RSS_CTRL_TCP_IPV6_SUPP
| RSS_CTRL_TCP_IPV6_EXT_SUPP;
if (R8168_MULTI_RSS_4Q(tp))
rss_ctrl |= RSS_QUAD_CPU_EN;
hash_mask_len = ilog2(rtl8168_rss_indir_tbl_entries(tp));
hash_mask_len &= (BIT_0 | BIT_1 | BIT_2);
rss_ctrl |= hash_mask_len << RSS_MASK_BITS_OFFSET;
rtl8168_eri_write(tp, RSS_CTRL_8168, 4, rss_ctrl, ERIAR_ExGMAC);
return 0;
}
static int rtl8168_set_rss_hash_opt(struct rtl8168_private *tp,
struct ethtool_rxnfc *nfc)
{
u32 rss_flags = tp->rss_flags;
/*
* RSS does not support anything other than hashing
* to queues on src and dst IPs and ports
*/
if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3))
return -EINVAL;
switch (nfc->flow_type) {
case TCP_V4_FLOW:
case TCP_V6_FLOW:
if (!(nfc->data & RXH_IP_SRC) ||
!(nfc->data & RXH_IP_DST) ||
!(nfc->data & RXH_L4_B_0_1) ||
!(nfc->data & RXH_L4_B_2_3))
return -EINVAL;
break;
case SCTP_V4_FLOW:
case AH_ESP_V4_FLOW:
case AH_V4_FLOW:
case ESP_V4_FLOW:
case SCTP_V6_FLOW:
case AH_ESP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
case IP_USER_FLOW:
case ETHER_FLOW:
/* RSS is not supported for these protocols */
if (nfc->data) {
netif_err(tp, drv, tp->dev, "Command parameters not supported\n");
return -EINVAL;
}
return 0;
default:
return -EINVAL;
}
/* if we changed something we need to update flags */
if (rss_flags != tp->rss_flags) {
u32 rss_ctrl = rtl8168_eri_read(tp, RSS_CTRL_8168, 4, ERIAR_ExGMAC);
tp->rss_flags = rss_flags;
/* Perform hash on these packet types */
rss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP
| RSS_CTRL_IPV4_SUPP
| RSS_CTRL_IPV6_SUPP
| RSS_CTRL_IPV6_EXT_SUPP
| RSS_CTRL_TCP_IPV6_SUPP
| RSS_CTRL_TCP_IPV6_EXT_SUPP;
if (R8168_MULTI_RSS_4Q(tp))
rss_ctrl |= RSS_QUAD_CPU_EN;
else
rss_ctrl &= ~RSS_QUAD_CPU_EN;
rtl8168_eri_write(tp, RSS_CTRL_8168, 4, rss_ctrl, ERIAR_ExGMAC);
}
return 0;
}
int rtl8168_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
{
struct rtl8168_private *tp = netdev_priv(dev);
int ret = -EOPNOTSUPP;
if (!(dev->features & NETIF_F_RXHASH))
return ret;
switch (cmd->cmd) {
case ETHTOOL_SRXFH:
ret = rtl8168_set_rss_hash_opt(tp, cmd);
break;
default:
break;
}
return ret;
}
static u32 _rtl8168_get_rxfh_key_size(struct rtl8168_private *tp)
{
return sizeof(tp->rss_key);
}
u32 rtl8168_get_rxfh_key_size(struct net_device *dev)
{
struct rtl8168_private *tp = netdev_priv(dev);
if (!(dev->features & NETIF_F_RXHASH))
return 0;
return _rtl8168_get_rxfh_key_size(tp);
}
u32 rtl8168_rss_indir_size(struct net_device *dev)
{
struct rtl8168_private *tp = netdev_priv(dev);
if (!(dev->features & NETIF_F_RXHASH))
return 0;
return rtl8168_rss_indir_tbl_entries(tp);
}
static void rtl8168_get_reta(struct rtl8168_private *tp, u32 *indir)
{
int i, reta_size = rtl8168_rss_indir_tbl_entries(tp);
for (i = 0; i < reta_size; i++)
indir[i] = tp->rss_indir_tbl[i];
}
static u32 rtl8168_rss_key_reg(struct rtl8168_private *tp)
{
return RSS_KEY_8168;
}
static u32 rtl8168_rss_indir_tbl_reg(struct rtl8168_private *tp)
{
return Rss_indir_tbl;
}
static void rtl8168_store_reta(struct rtl8168_private *tp)
{
u32 reta_entries = rtl8168_rss_indir_tbl_entries(tp);
u16 indir_tbl_reg = rtl8168_rss_indir_tbl_reg(tp);
u32 hw_indir[RTL8168_RSS_INDIR_TBL_SIZE] = {0};
u8 *indir = tp->rss_indir_tbl;
u32 bit_on_cnt = 0x00000001;
u32 i, j;
/* Mapping redirection table to HW */
for (i = 0, j = 0; i < reta_entries; i++) {
if ((indir[i] & 2) && R8168_MULTI_RSS_4Q(tp))
hw_indir[j + 4] |= bit_on_cnt;
if (indir[i] & 1)
hw_indir[j] |= bit_on_cnt;
if (bit_on_cnt == 0x80000000) {
bit_on_cnt = 0x00000001;
j++;
continue;
}
bit_on_cnt <<= 1;
}
/* Write redirection table to HW */
for (i = 0; i < RTL8168_RSS_INDIR_TBL_SIZE; i++)
RTL_W32(tp, indir_tbl_reg + i*4, hw_indir[i]);
}
static void rtl8168_store_rss_key(struct rtl8168_private *tp)
{
const u16 rss_key_reg = rtl8168_rss_key_reg(tp);
u32 i, rss_key_size = _rtl8168_get_rxfh_key_size(tp);
u32 *rss_key = (u32*)tp->rss_key;
/* Write redirection table to HW */
for (i = 0; i < rss_key_size; i+=4)
rtl8168_eri_write(tp, rss_key_reg + i, 4, *rss_key++, ERIAR_ExGMAC);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0)
int rtl8168_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh)
{
struct rtl8168_private *tp = netdev_priv(dev);
if (!(dev->features & NETIF_F_RXHASH))
return -EOPNOTSUPP;
rxfh->hfunc = ETH_RSS_HASH_TOP;
if (rxfh->indir)
rtl8168_get_reta(tp, rxfh->indir);
if (rxfh->key)
memcpy(rxfh->key, tp->rss_key, RTL8168_RSS_KEY_SIZE);
return 0;
}
int rtl8168_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack)
{
struct rtl8168_private *tp = netdev_priv(dev);
u32 reta_entries = rtl8168_rss_indir_tbl_entries(tp);
int i;
/* We require at least one supported parameter to be changed and no
* change in any of the unsupported parameters
*/
if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
/* Fill out the redirection table */
if (rxfh->indir) {
int max_queues = tp->num_rx_rings;
/* Verify user input. */
for (i = 0; i < reta_entries; i++)
if (rxfh->indir[i] >= max_queues)
return -EINVAL;
for (i = 0; i < reta_entries; i++)
tp->rss_indir_tbl[i] = rxfh->indir[i];
}
/* Fill out the rss hash key */
if (rxfh->key)
memcpy(tp->rss_key, rxfh->key, RTL8168_RSS_KEY_SIZE);
rtl8168_store_reta(tp);
rtl8168_store_rss_key(tp);
return 0;
}
#else
int rtl8168_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
u8 *hfunc)
{
struct rtl8168_private *tp = netdev_priv(dev);
if (!(dev->features & NETIF_F_RXHASH))
return -EOPNOTSUPP;
if (hfunc)
*hfunc = ETH_RSS_HASH_TOP;
if (indir)
rtl8168_get_reta(tp, indir);
if (key)
memcpy(key, tp->rss_key, RTL8168_RSS_KEY_SIZE);
return 0;
}
int rtl8168_set_rxfh(struct net_device *dev, const u32 *indir,
const u8 *key, const u8 hfunc)
{
struct rtl8168_private *tp = netdev_priv(dev);
u32 reta_entries = rtl8168_rss_indir_tbl_entries(tp);
int i;
/* We require at least one supported parameter to be changed and no
* change in any of the unsupported parameters
*/
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
/* Fill out the redirection table */
if (indir) {
int max_queues = tp->num_rx_rings;
/* Verify user input. */
for (i = 0; i < reta_entries; i++)
if (indir[i] >= max_queues)
return -EINVAL;
for (i = 0; i < reta_entries; i++)
tp->rss_indir_tbl[i] = indir[i];
}
/* Fill out the rss hash key */
if (key)
memcpy(tp->rss_key, key, RTL8168_RSS_KEY_SIZE);
rtl8168_store_reta(tp);
rtl8168_store_rss_key(tp);
return 0;
}
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0) */
static u32 rtl8168_get_rx_desc_hash(struct rtl8168_private *tp,
struct RxDescV2 *desc)
{
if (!desc->RSSResult)
fsleep(1);
return le32_to_cpu(desc->RSSResult);
}
#define RXS_8168_RSS_IPV4 BIT(17)
#define RXS_8168_RSS_IPV6 BIT(18)
#define RXS_8168_RSS_TCP BIT(19)
#define RTL8168_RXS_RSS_L3_TYPE_MASK (RXS_8168_RSS_IPV4 | RXS_8168_RSS_IPV6)
#define RTL8168_RXS_RSS_L4_TYPE_MASK (RXS_8168_RSS_TCP)
void rtl8168_rx_hash(struct rtl8168_private *tp,
struct RxDescV2 *desc,
struct sk_buff *skb)
{
u32 rss_header_info;
if (!(tp->dev->features & NETIF_F_RXHASH))
return;
rss_header_info = le32_to_cpu(desc->opts2);
if (!(rss_header_info & RTL8168_RXS_RSS_L3_TYPE_MASK))
return;
skb_set_hash(skb, rtl8168_get_rx_desc_hash(tp, desc),
(RTL8168_RXS_RSS_L4_TYPE_MASK & rss_header_info) ?
PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
}
void rtl8168_disable_rss(struct rtl8168_private *tp)
{
rtl8168_eri_write(tp, RSS_CTRL_8168, 4, 0x00000000, ERIAR_ExGMAC);
}
void _rtl8168_config_rss(struct rtl8168_private *tp)
{
_rtl8168_set_rss_hash_opt(tp);
rtl8168_store_reta(tp);
rtl8168_store_rss_key(tp);
}
void rtl8168_config_rss(struct rtl8168_private *tp)
{
if (!HW_RSS_SUPPORT_RSS(tp))
return;
if (!tp->EnableRss) {
rtl8168_disable_rss(tp);
return;
}
_rtl8168_config_rss(tp);
}
void rtl8168_init_rss(struct rtl8168_private *tp)
{
int i;
for (i = 0; i < rtl8168_rss_indir_tbl_entries(tp); i++)
tp->rss_indir_tbl[i] = ethtool_rxfh_indir_default(i, tp->num_rx_rings);
netdev_rss_key_fill(tp->rss_key, RTL8168_RSS_KEY_SIZE);
}

View File

@ -0,0 +1,72 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_RTL8168_RSS_H
#define _LINUX_RTL8168_RSS_H
#include <linux/netdevice.h>
#include <linux/types.h>
#define RTL8168_RSS_INDIR_TBL_SIZE 8
#define RTL8168_RSS_KEY_SIZE 40 /* size of RSS Hash Key in bytes */
#define RTL8168_MAX_INDIRECTION_TABLE_ENTRIES 128
struct rtl8168_private;
struct RxDescV2;
int rtl8168_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
u32 *rule_locs);
int rtl8168_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd);
u32 rtl8168_get_rxfh_key_size(struct net_device *netdev);
u32 rtl8168_rss_indir_size(struct net_device *netdev);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0)
int rtl8168_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh);
int rtl8168_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack);
#else
int rtl8168_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
u8 *hfunc);
int rtl8168_set_rxfh(struct net_device *netdev, const u32 *indir,
const u8 *key, const u8 hfunc);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0) */
void rtl8168_rx_hash(struct rtl8168_private *tp,
struct RxDescV2 *desc,
struct sk_buff *skb);
void _rtl8168_config_rss(struct rtl8168_private *tp);
void rtl8168_config_rss(struct rtl8168_private *tp);
void rtl8168_init_rss(struct rtl8168_private *tp);
u32 rtl8168_rss_indir_tbl_entries(struct rtl8168_private *tp);
void rtl8168_disable_rss(struct rtl8168_private *tp);
#endif /* _LINUX_RTL8168_RSS_H */

View File

@ -0,0 +1,286 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
################################################################################
#
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <asm/io.h>
#include "r8168.h"
#include "rtl_eeprom.h"
//-------------------------------------------------------------------
//rtl8168_eeprom_type():
// tell the eeprom type
//return value:
// 0: the eeprom type is 93C46
// 1: the eeprom type is 93C56 or 93C66
//-------------------------------------------------------------------
void rtl8168_eeprom_type(struct rtl8168_private *tp)
{
u16 magic = 0;
if (tp->mcfg == CFG_METHOD_DEFAULT)
goto out_no_eeprom;
if(RTL_R8(tp, 0xD2)&0x04) {
//not support
//tp->eeprom_type = EEPROM_TWSI;
//tp->eeprom_len = 256;
goto out_no_eeprom;
} else if(RTL_R32(tp, RxConfig) & RxCfg_9356SEL) {
tp->eeprom_type = EEPROM_TYPE_93C56;
tp->eeprom_len = 256;
} else {
tp->eeprom_type = EEPROM_TYPE_93C46;
tp->eeprom_len = 128;
}
magic = rtl8168_eeprom_read_sc(tp, 0);
out_no_eeprom:
if ((magic != 0x8129) && (magic != 0x8128)) {
tp->eeprom_type = EEPROM_TYPE_NONE;
tp->eeprom_len = 0;
}
}
void rtl8168_eeprom_cleanup(struct rtl8168_private *tp)
{
u8 x;
x = RTL_R8(tp, Cfg9346);
x &= ~(Cfg9346_EEDI | Cfg9346_EECS);
RTL_W8(tp, Cfg9346, x);
rtl8168_raise_clock(tp, &x);
rtl8168_lower_clock(tp, &x);
}
static int rtl8168_eeprom_cmd_done(struct rtl8168_private *tp)
{
u8 x;
int i;
rtl8168_stand_by(tp);
for (i = 0; i < 50000; i++) {
x = RTL_R8(tp, Cfg9346);
if (x & Cfg9346_EEDO) {
fsleep(RTL_CLOCK_RATE * 2 * 3);
return 0;
}
fsleep(1);
}
return -1;
}
//-------------------------------------------------------------------
//rtl8168_eeprom_read_sc():
// read one word from eeprom
//-------------------------------------------------------------------
u16 rtl8168_eeprom_read_sc(struct rtl8168_private *tp, u16 reg)
{
int addr_sz = 6;
u8 x;
u16 data;
if(tp->eeprom_type == EEPROM_TYPE_NONE) {
return -1;
}
if (tp->eeprom_type==EEPROM_TYPE_93C46)
addr_sz = 6;
else if (tp->eeprom_type==EEPROM_TYPE_93C56)
addr_sz = 8;
x = Cfg9346_EEM1 | Cfg9346_EECS;
RTL_W8(tp, Cfg9346, x);
rtl8168_shift_out_bits(tp, RTL_EEPROM_READ_OPCODE, 3);
rtl8168_shift_out_bits(tp, reg, addr_sz);
data = rtl8168_shift_in_bits(tp);
rtl8168_eeprom_cleanup(tp);
RTL_W8(tp, Cfg9346, 0);
return data;
}
//-------------------------------------------------------------------
//rtl8168_eeprom_write_sc():
// write one word to a specific address in the eeprom
//-------------------------------------------------------------------
void rtl8168_eeprom_write_sc(struct rtl8168_private *tp, u16 reg, u16 data)
{
u8 x;
int addr_sz = 6;
int w_dummy_addr = 4;
if(tp->eeprom_type == EEPROM_TYPE_NONE)
return;
if (tp->eeprom_type==EEPROM_TYPE_93C46) {
addr_sz = 6;
w_dummy_addr = 4;
} else if (tp->eeprom_type==EEPROM_TYPE_93C56) {
addr_sz = 8;
w_dummy_addr = 6;
}
x = Cfg9346_EEM1 | Cfg9346_EECS;
RTL_W8(tp, Cfg9346, x);
rtl8168_shift_out_bits(tp, RTL_EEPROM_EWEN_OPCODE, 5);
rtl8168_shift_out_bits(tp, reg, w_dummy_addr);
rtl8168_stand_by(tp);
rtl8168_shift_out_bits(tp, RTL_EEPROM_ERASE_OPCODE, 3);
rtl8168_shift_out_bits(tp, reg, addr_sz);
if (rtl8168_eeprom_cmd_done(tp) < 0)
return;
rtl8168_stand_by(tp);
rtl8168_shift_out_bits(tp, RTL_EEPROM_WRITE_OPCODE, 3);
rtl8168_shift_out_bits(tp, reg, addr_sz);
rtl8168_shift_out_bits(tp, data, 16);
if (rtl8168_eeprom_cmd_done(tp) < 0)
return;
rtl8168_stand_by(tp);
rtl8168_shift_out_bits(tp, RTL_EEPROM_EWDS_OPCODE, 5);
rtl8168_shift_out_bits(tp, reg, w_dummy_addr);
rtl8168_eeprom_cleanup(tp);
RTL_W8(tp, Cfg9346, 0);
}
void rtl8168_raise_clock(struct rtl8168_private *tp, u8 *x)
{
*x = *x | Cfg9346_EESK;
RTL_W8(tp, Cfg9346, *x);
fsleep(RTL_CLOCK_RATE);
}
void rtl8168_lower_clock(struct rtl8168_private *tp, u8 *x)
{
*x = *x & ~Cfg9346_EESK;
RTL_W8(tp, Cfg9346, *x);
fsleep(RTL_CLOCK_RATE);
}
void rtl8168_shift_out_bits(struct rtl8168_private *tp, int data, int count)
{
u8 x;
int mask;
mask = 0x01 << (count - 1);
x = RTL_R8(tp, Cfg9346);
x &= ~(Cfg9346_EEDI | Cfg9346_EEDO);
do {
if (data & mask)
x |= Cfg9346_EEDI;
else
x &= ~Cfg9346_EEDI;
RTL_W8(tp, Cfg9346, x);
fsleep(RTL_CLOCK_RATE);
rtl8168_raise_clock(tp, &x);
rtl8168_lower_clock(tp, &x);
mask = mask >> 1;
} while(mask);
x &= ~Cfg9346_EEDI;
RTL_W8(tp, Cfg9346, x);
}
u16 rtl8168_shift_in_bits(struct rtl8168_private *tp)
{
u8 x;
u16 d, i;
x = RTL_R8(tp, Cfg9346);
x &= ~(Cfg9346_EEDI | Cfg9346_EEDO);
d = 0;
for (i = 0; i < 16; i++) {
d = d << 1;
rtl8168_raise_clock(tp, &x);
x = RTL_R8(tp, Cfg9346);
x &= ~Cfg9346_EEDI;
if (x & Cfg9346_EEDO)
d |= 1;
rtl8168_lower_clock(tp, &x);
}
return d;
}
void rtl8168_stand_by(struct rtl8168_private *tp)
{
u8 x;
x = RTL_R8(tp, Cfg9346);
x &= ~(Cfg9346_EECS | Cfg9346_EESK);
RTL_W8(tp, Cfg9346, x);
fsleep(RTL_CLOCK_RATE);
x |= Cfg9346_EECS;
RTL_W8(tp, Cfg9346, x);
}
void rtl8168_set_eeprom_sel_low(struct rtl8168_private *tp)
{
RTL_W8(tp, Cfg9346, Cfg9346_EEM1);
RTL_W8(tp, Cfg9346, Cfg9346_EEM1 | Cfg9346_EESK);
fsleep(20);
RTL_W8(tp, Cfg9346, Cfg9346_EEM1);
}

View File

@ -0,0 +1,56 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
//EEPROM opcodes
#define RTL_EEPROM_READ_OPCODE 06
#define RTL_EEPROM_WRITE_OPCODE 05
#define RTL_EEPROM_ERASE_OPCODE 07
#define RTL_EEPROM_EWEN_OPCODE 19
#define RTL_EEPROM_EWDS_OPCODE 16
#define RTL_CLOCK_RATE 3
void rtl8168_eeprom_type(struct rtl8168_private *tp);
void rtl8168_eeprom_cleanup(struct rtl8168_private *tp);
u16 rtl8168_eeprom_read_sc(struct rtl8168_private *tp, u16 reg);
void rtl8168_eeprom_write_sc(struct rtl8168_private *tp, u16 reg, u16 data);
void rtl8168_shift_out_bits(struct rtl8168_private *tp, int data, int count);
u16 rtl8168_shift_in_bits(struct rtl8168_private *tp);
void rtl8168_raise_clock(struct rtl8168_private *tp, u8 *x);
void rtl8168_lower_clock(struct rtl8168_private *tp, u8 *x);
void rtl8168_stand_by(struct rtl8168_private *tp);
void rtl8168_set_eeprom_sel_low(struct rtl8168_private *tp);

View File

@ -0,0 +1,242 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
################################################################################
#
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/in.h>
#include <linux/ethtool.h>
#include <asm/uaccess.h>
#include "r8168.h"
#include "rtl_eeprom.h"
#include "rtltool.h"
int rtl8168_tool_ioctl(struct rtl8168_private *tp, struct ifreq *ifr)
{
struct rtltool_cmd my_cmd;
int ret;
if (copy_from_user(&my_cmd, ifr->ifr_data, sizeof(my_cmd)))
return -EFAULT;
ret = 0;
switch (my_cmd.cmd) {
case RTLTOOL_READ_MAC:
if ((my_cmd.offset + my_cmd.len) > R8168_REGS_SIZE) {
ret = -EINVAL;
break;
}
if (my_cmd.len==1)
my_cmd.data = readb(tp->mmio_addr+my_cmd.offset);
else if (my_cmd.len==2)
my_cmd.data = readw(tp->mmio_addr+(my_cmd.offset&~1));
else if (my_cmd.len==4)
my_cmd.data = readl(tp->mmio_addr+(my_cmd.offset&~3));
else {
ret = -EOPNOTSUPP;
break;
}
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_MAC:
if ((my_cmd.offset + my_cmd.len) > R8168_REGS_SIZE) {
ret = -EINVAL;
break;
}
if (my_cmd.len==1)
writeb(my_cmd.data, tp->mmio_addr+my_cmd.offset);
else if (my_cmd.len==2)
writew(my_cmd.data, tp->mmio_addr+(my_cmd.offset&~1));
else if (my_cmd.len==4)
writel(my_cmd.data, tp->mmio_addr+(my_cmd.offset&~3));
else {
ret = -EOPNOTSUPP;
break;
}
break;
case RTLTOOL_READ_PHY:
my_cmd.data = rtl8168_mdio_prot_read(tp, my_cmd.offset);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_PHY:
rtl8168_mdio_prot_write(tp, my_cmd.offset, my_cmd.data);
break;
case RTLTOOL_READ_EPHY:
my_cmd.data = rtl8168_ephy_read(tp, my_cmd.offset);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_EPHY:
rtl8168_ephy_write(tp, my_cmd.offset, my_cmd.data);
break;
case RTLTOOL_READ_ERI:
my_cmd.data = 0;
if (my_cmd.len==1 || my_cmd.len==2 || my_cmd.len==4) {
my_cmd.data = rtl8168_eri_read(tp, my_cmd.offset, my_cmd.len, ERIAR_ExGMAC);
} else {
ret = -EOPNOTSUPP;
break;
}
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_ERI:
if (my_cmd.len==1 || my_cmd.len==2 || my_cmd.len==4) {
rtl8168_eri_write(tp, my_cmd.offset, my_cmd.len, my_cmd.data, ERIAR_ExGMAC);
} else {
ret = -EOPNOTSUPP;
break;
}
break;
case RTLTOOL_READ_PCI:
my_cmd.data = 0;
if (my_cmd.len==1)
pci_read_config_byte(tp->pci_dev, my_cmd.offset,
(u8 *)&my_cmd.data);
else if (my_cmd.len==2)
pci_read_config_word(tp->pci_dev, my_cmd.offset,
(u16 *)&my_cmd.data);
else if (my_cmd.len==4)
pci_read_config_dword(tp->pci_dev, my_cmd.offset,
&my_cmd.data);
else {
ret = -EOPNOTSUPP;
break;
}
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_PCI:
if (my_cmd.len==1)
pci_write_config_byte(tp->pci_dev, my_cmd.offset,
my_cmd.data);
else if (my_cmd.len==2)
pci_write_config_word(tp->pci_dev, my_cmd.offset,
my_cmd.data);
else if (my_cmd.len==4)
pci_write_config_dword(tp->pci_dev, my_cmd.offset,
my_cmd.data);
else {
ret = -EOPNOTSUPP;
break;
}
break;
case RTLTOOL_READ_EEPROM:
my_cmd.data = rtl8168_eeprom_read_sc(tp, my_cmd.offset);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTLTOOL_WRITE_EEPROM:
rtl8168_eeprom_write_sc(tp, my_cmd.offset, my_cmd.data);
break;
case RTL_READ_OOB_MAC:
rtl8168_oob_mutex_lock(tp);
my_cmd.data = rtl8168_ocp_read(tp, my_cmd.offset, 4);
rtl8168_oob_mutex_unlock(tp);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTL_WRITE_OOB_MAC:
if (my_cmd.len == 0 || my_cmd.len > 4)
return -EOPNOTSUPP;
rtl8168_oob_mutex_lock(tp);
rtl8168_ocp_write(tp, my_cmd.offset, my_cmd.len, my_cmd.data);
rtl8168_oob_mutex_unlock(tp);
break;
case RTL_ENABLE_PCI_DIAG:
tp->rtk_enable_diag = 1;
dprintk("enable rtk diag\n");
break;
case RTL_DISABLE_PCI_DIAG:
tp->rtk_enable_diag = 0;
dprintk("disable rtk diag\n");
break;
case RTL_READ_MAC_OCP:
if (my_cmd.offset % 2)
return -EOPNOTSUPP;
my_cmd.data = rtl8168_mac_ocp_read(tp, my_cmd.offset);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTL_WRITE_MAC_OCP:
if ((my_cmd.offset % 2) || (my_cmd.len != 2))
return -EOPNOTSUPP;
rtl8168_mac_ocp_write(tp, my_cmd.offset, (u16)my_cmd.data);
break;
case RTL_DIRECT_READ_PHY_OCP:
my_cmd.data = rtl8168_mdio_prot_direct_read_phy_ocp(tp, my_cmd.offset);
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
ret = -EFAULT;
break;
}
break;
case RTL_DIRECT_WRITE_PHY_OCP:
rtl8168_mdio_prot_direct_write_phy_ocp(tp, my_cmd.offset, my_cmd.data);
break;
default:
ret = -EOPNOTSUPP;
break;
}
return ret;
}

View File

@ -0,0 +1,86 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
################################################################################
#
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
#
################################################################################
*/
/************************************************************************************
* This product is covered by one or more of the following patents:
* US6,570,884, US6,115,776, and US6,327,625.
***********************************************************************************/
#ifndef _LINUX_RTLTOOL_H
#define _LINUX_RTLTOOL_H
#define SIOCRTLTOOL SIOCDEVPRIVATE+1
enum rtl_cmd {
RTLTOOL_READ_MAC=0,
RTLTOOL_WRITE_MAC,
RTLTOOL_READ_PHY,
RTLTOOL_WRITE_PHY,
RTLTOOL_READ_EPHY,
RTLTOOL_WRITE_EPHY,
RTLTOOL_READ_ERI,
RTLTOOL_WRITE_ERI,
RTLTOOL_READ_PCI,
RTLTOOL_WRITE_PCI,
RTLTOOL_READ_EEPROM,
RTLTOOL_WRITE_EEPROM,
RTL_READ_OOB_MAC,
RTL_WRITE_OOB_MAC,
RTL_ENABLE_PCI_DIAG,
RTL_DISABLE_PCI_DIAG,
RTL_READ_MAC_OCP,
RTL_WRITE_MAC_OCP,
RTL_DIRECT_READ_PHY_OCP,
RTL_DIRECT_WRITE_PHY_OCP,
RTLTOOL_INVALID
};
struct rtltool_cmd {
__u32 cmd;
__u32 offset;
__u32 len;
__u32 data;
};
enum mode_access {
MODE_NONE=0,
MODE_READ,
MODE_WRITE
};
#ifdef __KERNEL__
int rtl8168_tool_ioctl(struct rtl8168_private *tp, struct ifreq *ifr);
#endif
#endif /* _LINUX_RTLTOOL_H */

132
build.sh
View File

@ -2,12 +2,14 @@
source ./dependencies.sh
[[ -z $KERNEL_VERSION ]] && KERNEL_VERSION='6.6.69'
[[ -z $BUILDROOT_VERSION ]] && BUILDROOT_VERSION='2024.02.9'
[[ -z $KERNEL_VERSION ]] && KERNEL_VERSION='6.12.35'
[[ -z $BUILDROOT_VERSION ]] && BUILDROOT_VERSION='2025.02.4'
declare -ar ARCHITECTURES=("x64" "x86" "arm64")
PIPE_JOINED_ARCHITECTURES=$(IFS="|"; echo "${ARCHITECTURES[@]}"; unset IFS)
PROJECT_DIRECTORY="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
Usage() {
echo -e "Usage: $0 [-knfvh?] [-a x64]"
echo -e "\t\t-a --arch [$PIPE_JOINED_ARCHITECTURES] (optional) pick the architecture to build. Default is to build for all."
@ -19,12 +21,12 @@ Usage() {
echo -e "\t\t-h --help -? Display this message."
exit 0
}
[[ -n $arch ]] && unset $arch
[[ -n "$arch" ]] && unset "$arch"
shortopts="?hkfnia:p:"
longopts="help,kernel-only,filesystem-only,noconfirm,install-dep,arch:,path:"
optargs=$(getopt -o $shortopts -l $longopts -n "$0" -- "$@")
optargs=$(getopt -o "$shortopts" -l "$longopts" -n "$0" -- "$@")
[[ $? -ne 0 ]] && Usage
eval set -- "$optargs"
@ -33,7 +35,6 @@ while :; do
case $1 in
-\? | -h | --help)
Usage
exit 0
;;
-k | --kernel-only)
buildKernelOnly="y"
@ -53,10 +54,9 @@ while :; do
;;
-a | --arch)
arch=$2
if ! echo ${ARCHITECTURES[@]} | grep -w $arch >/dev/null; then
if ! echo "${ARCHITECTURES[@]}" | grep -w "$arch" >/dev/null; then
echo "Error: Invalid architecture specified. Valid options are: $PIPE_JOINED_ARCHITECTURES"
Usage
exit 1
fi
shift 2
;;
@ -71,21 +71,20 @@ while :; do
*)
echo "Error: Invalid option."
Usage
exit 1
;;
esac
done
[[ -z $arch ]] && arch="${ARCHITECTURES[@]}"
[[ -z $buildPath ]] && buildPath=$(dirname $(readlink -f $0))
[[ -z $arch ]] && arch="${ARCHITECTURES[*]}"
[[ -z $buildPath ]] && buildPath="$(dirname "$(readlink -f "$0")")"
[[ -z $confirm ]] && confirm="y"
[[ -z $installDep ]] && installDep="n"
checkDependencies
installDependencies $installDep
installDependencies "$installDep"
cd $buildPath || exit 1
cd "$buildPath" || exit 1
function buildFilesystem() {
@ -95,18 +94,18 @@ function buildFilesystem() {
if [[ ! -d fssource$arch ]]; then
if [[ ! -f buildroot-$BUILDROOT_VERSION.tar.xz ]]; then
dots "Downloading buildroot source package"
wget -q $brURL && echo "Done"
wget -q "$brURL" && echo "Done"
if [[ $? -ne 0 ]]; then
echo "Failed"
exit 1
fi
fi
dots "Extracting buildroot sources"
tar xJf buildroot-$BUILDROOT_VERSION.tar.xz
mv buildroot-$BUILDROOT_VERSION fssource$arch
tar xJf "buildroot-$BUILDROOT_VERSION.tar.xz"
mv "buildroot-$BUILDROOT_VERSION" "fssource$arch"
echo "Done"
fi
cd fssource$arch
cd "fssource$arch" || { echo "Couldn't change directory to fssource$arch"; exit 1; }
if [[ -f ../patch/filesystem/fs.patch ]]; then
dots " * Applying filesystem patch"
echo
@ -127,7 +126,7 @@ function buildFilesystem() {
rsync -avPrI ../Buildroot/ . > /dev/null
sed -i "s/^export initversion=[0-9][0-9]*$/export initversion=$(date +%Y%m%d)/" board/FOG/FOS/rootfs_overlay/usr/share/fog/lib/funcs.sh
if [[ ! -f .config ]]; then
cp ../configs/fs$arch.config .config
cp "../configs/fs$arch.config" .config
case "${arch}" in
x64)
make oldconfig
@ -145,7 +144,7 @@ function buildFilesystem() {
fi
echo "Done"
if [[ $confirm != n ]]; then
read -p "We are ready to build. Would you like to edit the config file [y|n]?" config
read -rp "We are ready to build. Would you like to edit the config file [y|n]?" config
if [[ $config == y ]]; then
case "${arch}" in
x64)
@ -178,7 +177,7 @@ function buildFilesystem() {
;;
esac
fi
read -p "We are ready to build are you [y|n]?" ready
read -rp "We are ready to build are you [y|n]?" ready
if [[ $ready == n ]]; then
echo "Nothing to build!? Skipping."
cd ..
@ -189,27 +188,27 @@ function buildFilesystem() {
PING_LOOP_PID=$!
case "${arch}" in
x64)
make >buildroot$arch.log 2>&1
make > "buildroot$arch.log" 2>&1
status=$?
;;
x86)
make ARCH=i486 >buildroot$arch.log 2>&1
make ARCH=i486 > "buildroot$arch.log" 2>&1
status=$?
;;
arm64)
make ARCH=aarch64 CROSS_COMPILE=aarch64-linux-gnu- >buildroot$arch.log 2>&1
make ARCH=aarch64 CROSS_COMPILE=aarch64-linux-gnu- > "buildroot$arch.log" 2>&1
status=$?
;;
*)
make >buildroot$arch.log 2>&1
make > "buildroot$arch.log" 2>&1
status=$?
;;
esac
kill $PING_LOOP_PID
[[ $status -gt 0 ]] && tail buildroot$arch.log && exit $status
[[ $status -gt 0 ]] && tail "buildroot$arch.log" && exit $status
cd ..
[[ ! -d dist ]] && mkdir dist
cd dist
cd dist || { echo "Couldn't change directory to dist"; exit 1; }
case "${arch}" in
x64)
compiledfile="../fssource$arch/output/images/rootfs.ext2.xz"
@ -224,7 +223,7 @@ function buildFilesystem() {
initfile='arm_init.cpio.gz'
;;
esac
[[ ! -f $compiledfile ]] && echo 'File not found.' || cp $compiledfile $initfile && sha256sum $initfile > ${initfile}.sha256
[[ ! -f $compiledfile ]] && echo 'File not found.' || cp "$compiledfile" "$initfile" && sha256sum "$initfile" > "${initfile}.sha256"
cd ..
}
@ -232,52 +231,57 @@ function buildKernel() {
local arch="$1"
kernelURL="https://www.kernel.org/pub/linux/kernel/v${KERNEL_VERSION:0:1}.x/linux-$KERNEL_VERSION.tar.xz"
echo "Preparing kernel $KERNEL_VERSION on $arch build:"
[[ -d kernelsource$arch ]] && rm -rf kernelsource$arch
[[ -d kernelsource$arch ]] && rm -rf "kernelsource$arch"
if [[ ! -f linux-$KERNEL_VERSION.tar.xz ]]; then
dots "Downloading kernel source"
wget -q $kernelURL && echo "Done"
wget -q "$kernelURL" && echo "Done"
if [[ $? -ne 0 ]]; then
echo "Failed"
exit 1
fi
fi
dots "Extracting kernel source"
tar xJf linux-$KERNEL_VERSION.tar.xz
mv linux-$KERNEL_VERSION kernelsource$arch
tar xJf "linux-$KERNEL_VERSION.tar.xz"
mv "linux-$KERNEL_VERSION" "kernelsource$arch"
echo "Done"
dots "Adding kernel packages"
addKernelPackages
echo "Done"
if [[ ! -d linux-firmware ]]; then
dots "Cloning Linux firmware repository"
git clone git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git >/dev/null 2>&1
echo "Done"
else
dots "Updating Linux firmware repository"
cd linux-firmware
cd linux-firmware || { echo "Couldn't change directory to linux-firmware"; exit 1; }
git pull --rebase >/dev/null 2>&1
cd ..
echo "Done"
fi
dots "Copying firmware files"
cp -r linux-firmware kernelsource$arch/
cp -r linux-firmware "kernelsource$arch/"
echo "Done"
dots "Preparing kernel source"
cd kernelsource$arch
cd "kernelsource$arch" || { echo "Couldn't change directory to kernelsource$arch"; exit 2; }
make mrproper
cp ../configs/kernel$arch.config .config
cp "../configs/kernel$arch.config" .config
echo "Done"
if [[ -f ../patch/kernel/linux.patch ]]; then
dots " * Applying patch"
echo
echo
patch -p1 < ../patch/kernel/linux.patch
if [[ $? -ne 0 ]]; then
echo "Failed"
exit 1
fi
fi
else
echo " * WARNING: Did not find a patch file building vanilla kernel without patches!"
fi
if [[ $confirm != n ]]; then
read -p "We are ready to build. Would you like to edit the config file [y|n]?" config
read -rp "We are ready to build. Would you like to edit the config file [y|n]?" config
if [[ $config == y ]]; then
case "${arch}" in
x64)
@ -310,24 +314,24 @@ function buildKernel() {
;;
esac
fi
read -p "We are ready to build are you [y|n]?" ready
read -rp "We are ready to build are you [y|n]?" ready
if [[ $ready == y ]]; then
echo "This make take a long time. Get some coffee, you'll be here a while!"
case "${arch}" in
x64)
make -j $(nproc) bzImage
make -j "$(nproc)" bzImage
status=$?
;;
x86)
make ARCH=i386 -j $(nproc) bzImage
make ARCH=i386 -j "$(nproc)" bzImage
status=$?
;;
arm64)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j $(nproc) Image
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j "$(nproc)" Image
status=$?
;;
*)
make -j $(nproc) bzImage
make -j "$(nproc)" bzImage
status=$?
;;
esac
@ -341,22 +345,22 @@ function buildKernel() {
case "${arch}" in
x64)
make oldconfig
make -j $(nproc) bzImage
make -j "$(nproc)" bzImage
status=$?
;;
x86)
make ARCH=i386 oldconfig
make ARCH=i386 -j $(nproc) bzImage
make ARCH=i386 -j "$(nproc)" bzImage
status=$?
;;
arm64)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- oldconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j $(nproc) Image
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j "$(nproc)" Image
status=$?
;;
*)
make oldconfig
make -j $(nproc) bzImage
make -j "$(nproc)" bzImage
status=$?
;;
esac
@ -364,7 +368,7 @@ function buildKernel() {
[[ $status -gt 0 ]] && exit $status
cd ..
mkdir -p dist
cd dist
cd dist || { echo "Couldn't change directory to dist"; exit 1; }
case "$arch" in
x64)
compiledfile="../kernelsource$arch/arch/x86/boot/bzImage"
@ -379,24 +383,48 @@ function buildKernel() {
kernelfile='arm_Image'
;;
esac
[[ ! -f $compiledfile ]] && echo 'File not found.' || cp $compiledfile $kernelfile && sha256sum $kernelfile > ${kernelfile}.sha256
[[ ! -f $compiledfile ]] && echo 'File not found.' || cp "$compiledfile" "$kernelfile" && sha256sum "$kernelfile" > "${kernelfile}.sha256"
cd ..
}
dots() {
local pad=$(printf "%0.1s" "."{1..60})
function dots() {
local pad
pad=$(printf "%0.1s" "."{1..60})
printf " * %s%*.*s" "$1" 0 $((60-${#1})) "$pad"
return 0
}
function addKernelPackages() {
local source_kernel_package_dir="$PROJECT_DIRECTORY/KernelPackages"
local target_kernel_dir="$PROJECT_DIRECTORY/kernelsource$arch"
find "$source_kernel_package_dir" -type f | while read -r source_file; do
# Get the relative path from the package directory to the source file
local relative_path="${source_file#"$source_kernel_package_dir"/}"
# Find the corresponding destination path
local destination_file="$target_kernel_dir/$relative_path"
local destination_dir
destination_dir="$(dirname "$destination_file")"
mkdir -p "$destination_dir"
# Append if the destination file exists, otherwise copy
if [[ -e "$destination_file" ]]; then
cat "$source_file" >> "$destination_file"
else
cp "$source_file" "$destination_file"
fi
done
}
for buildArch in $arch
do
if [[ -z $buildKernelOnly ]]; then
buildFilesystem $buildArch
buildFilesystem "$buildArch"
fi
if [[ -z $buildFSOnly ]]; then
buildKernel $buildArch
buildKernel "$buildArch"
fi
done

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,9 @@ declare -ar common_dependencies=(
"file"
"rsync"
"patch"
"unzip"
"bzip2"
"findutils"
)
declare -ar deb_dependencies=(
@ -48,7 +51,8 @@ function __epel_repo_message() {
function checkDependencies() {
local running_os=$(cat /etc/os-release | grep "^ID=" | cut -d'=' -f2 | tr -d '"')
local running_os
running_os=$(grep "^ID=" /etc/os-release | cut -d'=' -f2 | tr -d '"')
package_manager=""
case $running_os in
@ -79,7 +83,7 @@ function checkDependencies() {
missing_packages=""
for package in "${dependencies[@]}"; do
pkgmgr | awk '{print $2}' | cut -d':' -f1 | grep -qe "${package}"
if [[ $? > 0 ]]; then
if [[ $? -ne 0 ]]; then
missing_packages="${missing_packages} ${package}"
fi
done
@ -101,7 +105,7 @@ function installDependencies() {
if [[ -n $missing_packages ]]; then
echo "Atempting to install missing dependencies..."
$package_manager "${dependencies[@]}" > /dev/null 2>&1
if [[ $? > 0 ]]; then
if [[ $? -ne 0 ]]; then
echo "Failed to install dependencies, please install the packages manually. Exiting now."
exit 1
fi

View File

@ -1,8 +1,8 @@
diff --git a/Config.in b/Config.in
index df43db7eff..8a3e0ac0a4 100644
index d730f2034b..9ad4198d14 100644
--- a/Config.in
+++ b/Config.in
@@ -712,6 +712,24 @@ config BR2_GLOBAL_PATCH_DIR
@@ -741,6 +741,24 @@ config BR2_GLOBAL_PATCH_DIR
menu "Advanced"
@ -28,10 +28,10 @@ index df43db7eff..8a3e0ac0a4 100644
bool "Force the building of host dependencies"
help
diff --git a/package/Makefile.in b/package/Makefile.in
index 1cedfefa7e..62bcbd3269 100644
index 829636900b..b2028f9a7c 100644
--- a/package/Makefile.in
+++ b/package/Makefile.in
@@ -431,8 +431,9 @@ else ifeq ($(BR2_SHARED_STATIC_LIBS),y)
@@ -447,8 +447,9 @@ else ifeq ($(BR2_SHARED_STATIC_LIBS),y)
SHARED_STATIC_LIBS_OPTS = --enable-static --enable-shared
endif
@ -53,7 +53,7 @@ index 3430fcce11..71344e2c69 100644
+BR2_COMPILER_PARANOID_UNSAFE_PATH=y
BR2_PACKAGE_BUSYBOX_SHOW_OTHERS=y
diff --git a/toolchain/toolchain-wrapper.c b/toolchain/toolchain-wrapper.c
index e436889760..caadda4eb0 100644
index 8b1fb79dde..6d23b81ef8 100644
--- a/toolchain/toolchain-wrapper.c
+++ b/toolchain/toolchain-wrapper.c
@@ -157,6 +157,7 @@ static const struct str_len_s unsafe_opts[] = {
@ -87,10 +87,10 @@ index e436889760..caadda4eb0 100644
char *env_debug;
+ char *paranoid_wrapper;
+ int paranoid;
int ret, i, count = 0, debug = 0, found_shared = 0;
int ret, i, count = 0, debug = 0, found_shared = 0, found_nonoption = 0;
/* Debug the wrapper to see arguments it was called with.
@@ -474,6 +479,12 @@ int main(int argc, char **argv)
@@ -475,6 +480,12 @@ int main(int argc, char **argv)
#endif
}
@ -103,7 +103,7 @@ index e436889760..caadda4eb0 100644
/* Check for unsafe library and header paths */
for (i = 1; i < argc; i++) {
const struct str_len_s *opt;
@@ -490,9 +501,9 @@ int main(int argc, char **argv)
@@ -491,9 +502,9 @@ int main(int argc, char **argv)
i++;
if (i == argc)
break;