mirror of
https://github.com/bolucat/Archive.git
synced 2025-09-26 20:21:35 +08:00
Update On Sun Jun 16 20:31:17 CEST 2024
This commit is contained in:
1
.github/update.log
vendored
1
.github/update.log
vendored
@@ -674,3 +674,4 @@ Update On Wed Jun 12 20:32:18 CEST 2024
|
||||
Update On Thu Jun 13 20:31:26 CEST 2024
|
||||
Update On Fri Jun 14 20:32:58 CEST 2024
|
||||
Update On Sat Jun 15 20:30:01 CEST 2024
|
||||
Update On Sun Jun 16 20:31:07 CEST 2024
|
||||
|
@@ -28,7 +28,10 @@ type healthCheckSchema struct {
|
||||
}
|
||||
|
||||
type OverrideSchema struct {
|
||||
TFO *bool `provider:"tfo,omitempty"`
|
||||
MPTcp *bool `provider:"mptcp,omitempty"`
|
||||
UDP *bool `provider:"udp,omitempty"`
|
||||
UDPOverTCP *bool `provider:"udp-over-tcp,omitempty"`
|
||||
Up *string `provider:"up,omitempty"`
|
||||
Down *string `provider:"down,omitempty"`
|
||||
DialerProxy *string `provider:"dialer-proxy,omitempty"`
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -373,37 +374,23 @@ func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray
|
||||
mapping["dialer-proxy"] = dialerProxy
|
||||
}
|
||||
|
||||
if override.UDP != nil {
|
||||
mapping["udp"] = *override.UDP
|
||||
}
|
||||
if override.Up != nil {
|
||||
mapping["up"] = *override.Up
|
||||
}
|
||||
if override.Down != nil {
|
||||
mapping["down"] = *override.Down
|
||||
}
|
||||
if override.DialerProxy != nil {
|
||||
mapping["dialer-proxy"] = *override.DialerProxy
|
||||
}
|
||||
if override.SkipCertVerify != nil {
|
||||
mapping["skip-cert-verify"] = *override.SkipCertVerify
|
||||
}
|
||||
if override.Interface != nil {
|
||||
mapping["interface-name"] = *override.Interface
|
||||
}
|
||||
if override.RoutingMark != nil {
|
||||
mapping["routing-mark"] = *override.RoutingMark
|
||||
}
|
||||
if override.IPVersion != nil {
|
||||
mapping["ip-version"] = *override.IPVersion
|
||||
}
|
||||
if override.AdditionalPrefix != nil {
|
||||
name := mapping["name"].(string)
|
||||
mapping["name"] = *override.AdditionalPrefix + name
|
||||
}
|
||||
if override.AdditionalSuffix != nil {
|
||||
name := mapping["name"].(string)
|
||||
mapping["name"] = name + *override.AdditionalSuffix
|
||||
val := reflect.ValueOf(override)
|
||||
for i := 0; i < val.NumField(); i++ {
|
||||
field := val.Field(i)
|
||||
if field.IsNil() {
|
||||
continue
|
||||
}
|
||||
fieldName := strings.Split(val.Type().Field(i).Tag.Get("provider"), ",")[0]
|
||||
switch fieldName {
|
||||
case "additional-prefix":
|
||||
name := mapping["name"].(string)
|
||||
mapping["name"] = *field.Interface().(*string) + name
|
||||
case "additional-suffix":
|
||||
name := mapping["name"].(string)
|
||||
mapping["name"] = name + *field.Interface().(*string)
|
||||
default:
|
||||
mapping[fieldName] = field.Elem().Interface()
|
||||
}
|
||||
}
|
||||
|
||||
proxy, err := adapter.ParseProxy(mapping)
|
||||
|
@@ -36,7 +36,7 @@
|
||||
"react-dom": "18.3.1",
|
||||
"react-error-boundary": "4.0.13",
|
||||
"react-fast-marquee": "1.6.4",
|
||||
"react-hook-form": "7.51.5",
|
||||
"react-hook-form": "7.52.0",
|
||||
"react-hook-form-mui": "7.0.0",
|
||||
"react-i18next": "14.1.2",
|
||||
"react-markdown": "9.0.1",
|
||||
@@ -56,9 +56,10 @@
|
||||
"@typescript-eslint/eslint-plugin": "7.13.0",
|
||||
"@typescript-eslint/parser": "7.13.0",
|
||||
"@vitejs/plugin-react": "4.3.1",
|
||||
"@vitejs/plugin-react-swc": "^3.7.0",
|
||||
"sass": "1.77.5",
|
||||
"shiki": "1.6.4",
|
||||
"vite": "5.3.0",
|
||||
"shiki": "1.6.5",
|
||||
"vite": "5.3.1",
|
||||
"vite-plugin-monaco-editor": "1.1.3",
|
||||
"vite-plugin-sass-dts": "1.3.22",
|
||||
"vite-plugin-svgr": "4.2.0",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import generouted from "@generouted/react-router/plugin";
|
||||
import react from "@vitejs/plugin-react";
|
||||
// import react from "@vitejs/plugin-react-swc";
|
||||
// import react from "@vitejs/plugin-react";
|
||||
import react from "@vitejs/plugin-react-swc";
|
||||
import path from "node:path";
|
||||
import { defineConfig } from "vite";
|
||||
import monaco from "vite-plugin-monaco-editor";
|
||||
@@ -46,10 +46,10 @@ export default defineConfig(({ command }) => {
|
||||
tsconfigPaths(),
|
||||
svgr(),
|
||||
react({
|
||||
// jsxImportSource: "@emotion/react",
|
||||
babel: {
|
||||
plugins: ["@emotion/babel-plugin"],
|
||||
},
|
||||
jsxImportSource: "@emotion/react",
|
||||
// babel: {
|
||||
// plugins: ["@emotion/babel-plugin"],
|
||||
// },
|
||||
}),
|
||||
generouted(),
|
||||
sassDts({ esmExport: true }),
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"manifest_version": 1,
|
||||
"latest": {
|
||||
"mihomo": "v1.18.5",
|
||||
"mihomo_alpha": "alpha-9b02d91",
|
||||
"mihomo_alpha": "alpha-40f40f6",
|
||||
"clash_rs": "v0.1.18",
|
||||
"clash_premium": "2023-09-05-gdcc8d87"
|
||||
},
|
||||
@@ -36,5 +36,5 @@
|
||||
"darwin-x64": "clash-darwin-amd64-n{}.gz"
|
||||
}
|
||||
},
|
||||
"updated_at": "2024-06-14T22:20:16.949Z"
|
||||
"updated_at": "2024-06-15T22:19:49.581Z"
|
||||
}
|
||||
|
222
clash-nyanpasu/pnpm-lock.yaml
generated
222
clash-nyanpasu/pnpm-lock.yaml
generated
@@ -178,7 +178,7 @@ importers:
|
||||
version: 11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-9d4fba0788-20240530)(types-react@19.0.0-rc.0))(react@19.0.0-rc-9d4fba0788-20240530)(types-react@19.0.0-rc.0)
|
||||
'@generouted/react-router':
|
||||
specifier: 1.19.5
|
||||
version: 1.19.5(react-router-dom@6.23.1(react-dom@19.0.0-rc-9d4fba0788-20240530(react@19.0.0-rc-9d4fba0788-20240530))(react@19.0.0-rc-9d4fba0788-20240530))(react@19.0.0-rc-9d4fba0788-20240530)(vite@5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))
|
||||
version: 1.19.5(react-router-dom@6.23.1(react-dom@19.0.0-rc-9d4fba0788-20240530(react@19.0.0-rc-9d4fba0788-20240530))(react@19.0.0-rc-9d4fba0788-20240530))(react@19.0.0-rc-9d4fba0788-20240530)(vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))
|
||||
'@juggle/resize-observer':
|
||||
specifier: 3.4.0
|
||||
version: 3.4.0
|
||||
@@ -246,11 +246,11 @@ importers:
|
||||
specifier: 1.6.4
|
||||
version: 1.6.4(react-dom@19.0.0-rc-9d4fba0788-20240530(react@19.0.0-rc-9d4fba0788-20240530))(react@19.0.0-rc-9d4fba0788-20240530)
|
||||
react-hook-form:
|
||||
specifier: 7.51.5
|
||||
version: 7.51.5(react@19.0.0-rc-9d4fba0788-20240530)
|
||||
specifier: 7.52.0
|
||||
version: 7.52.0(react@19.0.0-rc-9d4fba0788-20240530)
|
||||
react-hook-form-mui:
|
||||
specifier: 7.0.0
|
||||
version: 7.0.0(vzgnxglunplyfvn2vosyka7udq)
|
||||
version: 7.0.0(n2wpefg76qqlnn3amngg4fapru)
|
||||
react-i18next:
|
||||
specifier: 14.1.2
|
||||
version: 14.1.2(i18next@23.11.5)(react-dom@19.0.0-rc-9d4fba0788-20240530(react@19.0.0-rc-9d4fba0788-20240530))(react@19.0.0-rc-9d4fba0788-20240530)
|
||||
@@ -299,28 +299,31 @@ importers:
|
||||
version: 7.13.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@vitejs/plugin-react':
|
||||
specifier: 4.3.1
|
||||
version: 4.3.1(vite@5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))
|
||||
version: 4.3.1(vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))
|
||||
'@vitejs/plugin-react-swc':
|
||||
specifier: ^3.7.0
|
||||
version: 3.7.0(vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))
|
||||
sass:
|
||||
specifier: 1.77.5
|
||||
version: 1.77.5
|
||||
shiki:
|
||||
specifier: 1.6.4
|
||||
version: 1.6.4
|
||||
specifier: 1.6.5
|
||||
version: 1.6.5
|
||||
vite:
|
||||
specifier: 5.3.0
|
||||
version: 5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
specifier: 5.3.1
|
||||
version: 5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
vite-plugin-monaco-editor:
|
||||
specifier: npm:vite-plugin-monaco-editor-new@1.1.3
|
||||
version: vite-plugin-monaco-editor-new@1.1.3(monaco-editor@0.49.0)
|
||||
vite-plugin-sass-dts:
|
||||
specifier: 1.3.22
|
||||
version: 1.3.22(postcss@8.4.38)(prettier@3.3.2)(sass@1.77.5)(vite@5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))
|
||||
version: 1.3.22(postcss@8.4.38)(prettier@3.3.2)(sass@1.77.5)(vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))
|
||||
vite-plugin-svgr:
|
||||
specifier: 4.2.0
|
||||
version: 4.2.0(rollup@4.17.2)(typescript@5.4.5)(vite@5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))
|
||||
version: 4.2.0(rollup@4.17.2)(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))
|
||||
vite-tsconfig-paths:
|
||||
specifier: 4.3.2
|
||||
version: 4.3.2(typescript@5.4.5)(vite@5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))
|
||||
version: 4.3.2(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))
|
||||
|
||||
frontend/ui:
|
||||
dependencies:
|
||||
@@ -1511,8 +1514,8 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@shikijs/core@1.6.4':
|
||||
resolution: {integrity: sha512-WTU9rzZae1p2v6LOxMf6LhtmZOkIHYYW160IuahUyJy7YXPPjyWZLR1ag+SgD22ZMxZtz1gfU6Tccc8t0Il/XA==}
|
||||
'@shikijs/core@1.6.5':
|
||||
resolution: {integrity: sha512-XcQYt6e4L61ruAxHiL3Xg1DL/XkWWjzDdeckB/DtN8jAxoAU+bcxsV6DetC8NafHpL4YpGhxy9iXF0ND/u6HmA==}
|
||||
|
||||
'@sindresorhus/is@4.6.0':
|
||||
resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
|
||||
@@ -1586,6 +1589,81 @@ packages:
|
||||
peerDependencies:
|
||||
'@svgr/core': '*'
|
||||
|
||||
'@swc/core-darwin-arm64@1.6.1':
|
||||
resolution: {integrity: sha512-u6GdwOXsOEdNAdSI6nWq6G2BQw5HiSNIZVcBaH1iSvBnxZvWbnIKyDiZKaYnDwTLHLzig2GuUjjE2NaCJPy4jg==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@swc/core-darwin-x64@1.6.1':
|
||||
resolution: {integrity: sha512-/tXwQibkDNLVbAtr7PUQI0iQjoB708fjhDDDfJ6WILSBVZ3+qs/LHjJ7jHwumEYxVq1XA7Fv2Q7SE/ZSQoWHcQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@swc/core-linux-arm-gnueabihf@1.6.1':
|
||||
resolution: {integrity: sha512-aDgipxhJTms8iH78emHVutFR2c16LNhO+NTRCdYi+X4PyIn58/DyYTH6VDZ0AeEcS5f132ZFldU5AEgExwihXA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-arm64-gnu@1.6.1':
|
||||
resolution: {integrity: sha512-XkJ+eO4zUKG5g458RyhmKPyBGxI0FwfWFgpfIj5eDybxYJ6s4HBT5MoxyBLorB5kMlZ0XoY/usUMobPVY3nL0g==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-arm64-musl@1.6.1':
|
||||
resolution: {integrity: sha512-dr6YbLBg/SsNxs1hDqJhxdcrS8dGMlOXJwXIrUvACiA8jAd6S5BxYCaqsCefLYXtaOmu0bbx1FB/evfodqB70Q==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-x64-gnu@1.6.1':
|
||||
resolution: {integrity: sha512-A0b/3V+yFy4LXh3O9umIE7LXPC7NBWdjl6AQYqymSMcMu0EOb1/iygA6s6uWhz9y3e172Hpb9b/CGsuD8Px/bg==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-x64-musl@1.6.1':
|
||||
resolution: {integrity: sha512-5dJjlzZXhC87nZZZWbpiDP8kBIO0ibis893F/rtPIQBI5poH+iJuA32EU3wN4/WFHeK4et8z6SGSVghPtWyk4g==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-win32-arm64-msvc@1.6.1':
|
||||
resolution: {integrity: sha512-HBi1ZlwvfcUibLtT3g/lP57FaDPC799AD6InolB2KSgkqyBbZJ9wAXM8/CcH67GLIP0tZ7FqblrJTzGXxetTJQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@swc/core-win32-ia32-msvc@1.6.1':
|
||||
resolution: {integrity: sha512-AKqHohlWERclexar5y6ux4sQ8yaMejEXNxeKXm7xPhXrp13/1p4/I3E5bPVX/jMnvpm4HpcKSP0ee2WsqmhhPw==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@swc/core-win32-x64-msvc@1.6.1':
|
||||
resolution: {integrity: sha512-0dLdTLd+ONve8kgC5T6VQ2Y5G+OZ7y0ujjapnK66wpvCBM6BKYGdT/OKhZKZydrC5gUKaxFN6Y5oOt9JOFUrOQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@swc/core@1.6.1':
|
||||
resolution: {integrity: sha512-Yz5uj5hNZpS5brLtBvKY0L4s2tBAbQ4TjmW8xF1EC3YLFxQRrUjMP49Zm1kp/KYyYvTkSaG48Ffj2YWLu9nChw==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
'@swc/helpers': '*'
|
||||
peerDependenciesMeta:
|
||||
'@swc/helpers':
|
||||
optional: true
|
||||
|
||||
'@swc/counter@0.1.3':
|
||||
resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
|
||||
|
||||
'@swc/types@0.1.8':
|
||||
resolution: {integrity: sha512-RNFA3+7OJFNYY78x0FYwi1Ow+iF1eF5WvmfY1nXPOEH4R2p/D4Cr1vzje7dNAI2aLFqpv8Wyz4oKSWqIZArpQA==}
|
||||
|
||||
'@szmarczak/http-timer@4.0.6':
|
||||
resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -1831,6 +1909,11 @@ packages:
|
||||
'@ungap/structured-clone@1.2.0':
|
||||
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
|
||||
|
||||
'@vitejs/plugin-react-swc@3.7.0':
|
||||
resolution: {integrity: sha512-yrknSb3Dci6svCd/qhHqhFPDSw0QtjumcqdKMoNNzmOl5lMXTTiqzjWtG4Qask2HdvvzaNgSunbQGet8/GrKdA==}
|
||||
peerDependencies:
|
||||
vite: ^4 || ^5
|
||||
|
||||
'@vitejs/plugin-react@4.3.1':
|
||||
resolution: {integrity: sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
@@ -4270,8 +4353,8 @@ packages:
|
||||
'@mui/x-date-pickers':
|
||||
optional: true
|
||||
|
||||
react-hook-form@7.51.5:
|
||||
resolution: {integrity: sha512-J2ILT5gWx1XUIJRETiA7M19iXHlG74+6O3KApzvqB/w8S5NQR7AbU8HVZrMALdmDgWpRPYiZJl0zx8Z4L2mP6Q==}
|
||||
react-hook-form@7.52.0:
|
||||
resolution: {integrity: sha512-mJX506Xc6mirzLsmXUJyqlAI3Kj9Ph2RhplYhUVffeOQSnubK2uVqBFOBJmvKikvbFV91pxVXmDiR+QMF19x6A==}
|
||||
engines: {node: '>=12.22.0'}
|
||||
peerDependencies:
|
||||
react: npm:react@rc
|
||||
@@ -4523,8 +4606,8 @@ packages:
|
||||
shell-quote@1.8.1:
|
||||
resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==}
|
||||
|
||||
shiki@1.6.4:
|
||||
resolution: {integrity: sha512-X88chM7w8jnadoZtjPTi5ahCJx9pc9f8GfEkZAEYUTlcUZIEw2D/RY86HI/LkkE7Nj8TQWkiBfaFTJ3VJT6ESg==}
|
||||
shiki@1.6.5:
|
||||
resolution: {integrity: sha512-iFzypldJG0zeyRHKAhaSGCf+YWXpMMyUyOrCVFBFKGGdF5vrB6jbd66/SQljxV20aSrVZEAQwUto/hhuNi/CIg==}
|
||||
|
||||
side-channel@1.0.6:
|
||||
resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
|
||||
@@ -5056,8 +5139,8 @@ packages:
|
||||
vite:
|
||||
optional: true
|
||||
|
||||
vite@5.3.0:
|
||||
resolution: {integrity: sha512-hA6vAVK977NyW1Qw+fLvqSo7xDPej7von7C3DwwqPRmnnnK36XEBC/J3j1V5lP8fbt7y0TgTKJbpNGSwM+Bdeg==}
|
||||
vite@5.3.1:
|
||||
resolution: {integrity: sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -5815,13 +5898,13 @@ snapshots:
|
||||
|
||||
'@floating-ui/utils@0.2.2': {}
|
||||
|
||||
'@generouted/react-router@1.19.5(react-router-dom@6.23.1(react-dom@19.0.0-rc-9d4fba0788-20240530(react@19.0.0-rc-9d4fba0788-20240530))(react@19.0.0-rc-9d4fba0788-20240530))(react@19.0.0-rc-9d4fba0788-20240530)(vite@5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))':
|
||||
'@generouted/react-router@1.19.5(react-router-dom@6.23.1(react-dom@19.0.0-rc-9d4fba0788-20240530(react@19.0.0-rc-9d4fba0788-20240530))(react@19.0.0-rc-9d4fba0788-20240530))(react@19.0.0-rc-9d4fba0788-20240530)(vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))':
|
||||
dependencies:
|
||||
fast-glob: 3.3.2
|
||||
generouted: 1.19.5(vite@5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))
|
||||
generouted: 1.19.5(vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))
|
||||
react: 19.0.0-rc-9d4fba0788-20240530
|
||||
react-router-dom: 6.23.1(react-dom@19.0.0-rc-9d4fba0788-20240530(react@19.0.0-rc-9d4fba0788-20240530))(react@19.0.0-rc-9d4fba0788-20240530)
|
||||
vite: 5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
vite: 5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
|
||||
'@humanwhocodes/config-array@0.11.14':
|
||||
dependencies:
|
||||
@@ -6304,7 +6387,7 @@ snapshots:
|
||||
'@rollup/rollup-win32-x64-msvc@4.17.2':
|
||||
optional: true
|
||||
|
||||
'@shikijs/core@1.6.4': {}
|
||||
'@shikijs/core@1.6.5': {}
|
||||
|
||||
'@sindresorhus/is@4.6.0': {}
|
||||
|
||||
@@ -6378,6 +6461,58 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@swc/core-darwin-arm64@1.6.1':
|
||||
optional: true
|
||||
|
||||
'@swc/core-darwin-x64@1.6.1':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-arm-gnueabihf@1.6.1':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-arm64-gnu@1.6.1':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-arm64-musl@1.6.1':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-x64-gnu@1.6.1':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-x64-musl@1.6.1':
|
||||
optional: true
|
||||
|
||||
'@swc/core-win32-arm64-msvc@1.6.1':
|
||||
optional: true
|
||||
|
||||
'@swc/core-win32-ia32-msvc@1.6.1':
|
||||
optional: true
|
||||
|
||||
'@swc/core-win32-x64-msvc@1.6.1':
|
||||
optional: true
|
||||
|
||||
'@swc/core@1.6.1':
|
||||
dependencies:
|
||||
'@swc/counter': 0.1.3
|
||||
'@swc/types': 0.1.8
|
||||
optionalDependencies:
|
||||
'@swc/core-darwin-arm64': 1.6.1
|
||||
'@swc/core-darwin-x64': 1.6.1
|
||||
'@swc/core-linux-arm-gnueabihf': 1.6.1
|
||||
'@swc/core-linux-arm64-gnu': 1.6.1
|
||||
'@swc/core-linux-arm64-musl': 1.6.1
|
||||
'@swc/core-linux-x64-gnu': 1.6.1
|
||||
'@swc/core-linux-x64-musl': 1.6.1
|
||||
'@swc/core-win32-arm64-msvc': 1.6.1
|
||||
'@swc/core-win32-ia32-msvc': 1.6.1
|
||||
'@swc/core-win32-x64-msvc': 1.6.1
|
||||
|
||||
'@swc/counter@0.1.3': {}
|
||||
|
||||
'@swc/types@0.1.8':
|
||||
dependencies:
|
||||
'@swc/counter': 0.1.3
|
||||
|
||||
'@szmarczak/http-timer@4.0.6':
|
||||
dependencies:
|
||||
defer-to-connect: 2.0.1
|
||||
@@ -6640,14 +6775,21 @@ snapshots:
|
||||
|
||||
'@ungap/structured-clone@1.2.0': {}
|
||||
|
||||
'@vitejs/plugin-react@4.3.1(vite@5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))':
|
||||
'@vitejs/plugin-react-swc@3.7.0(vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))':
|
||||
dependencies:
|
||||
'@swc/core': 1.6.1
|
||||
vite: 5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- '@swc/helpers'
|
||||
|
||||
'@vitejs/plugin-react@4.3.1(vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0))':
|
||||
dependencies:
|
||||
'@babel/core': 7.24.5
|
||||
'@babel/plugin-transform-react-jsx-self': 7.24.5(@babel/core@7.24.5)
|
||||
'@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.5)
|
||||
'@types/babel__core': 7.20.5
|
||||
react-refresh: 0.14.2
|
||||
vite: 5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
vite: 5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -7910,9 +8052,9 @@ snapshots:
|
||||
|
||||
functions-have-names@1.2.3: {}
|
||||
|
||||
generouted@1.19.5(vite@5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)):
|
||||
generouted@1.19.5(vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
vite: 5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
vite: 5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
|
||||
gensync@1.0.0-beta.2: {}
|
||||
|
||||
@@ -9352,15 +9494,15 @@ snapshots:
|
||||
react: 19.0.0-rc-9d4fba0788-20240530
|
||||
react-dom: 19.0.0-rc-9d4fba0788-20240530(react@19.0.0-rc-9d4fba0788-20240530)
|
||||
|
||||
react-hook-form-mui@7.0.0(vzgnxglunplyfvn2vosyka7udq):
|
||||
react-hook-form-mui@7.0.0(n2wpefg76qqlnn3amngg4fapru):
|
||||
dependencies:
|
||||
'@mui/material': 5.15.20(@emotion/react@11.11.4(react@19.0.0-rc-9d4fba0788-20240530)(types-react@19.0.0-rc.0))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-9d4fba0788-20240530)(types-react@19.0.0-rc.0))(react@19.0.0-rc-9d4fba0788-20240530)(types-react@19.0.0-rc.0))(react-dom@19.0.0-rc-9d4fba0788-20240530(react@19.0.0-rc-9d4fba0788-20240530))(react@19.0.0-rc-9d4fba0788-20240530)(types-react@19.0.0-rc.0)
|
||||
react: 19.0.0-rc-9d4fba0788-20240530
|
||||
react-hook-form: 7.51.5(react@19.0.0-rc-9d4fba0788-20240530)
|
||||
react-hook-form: 7.52.0(react@19.0.0-rc-9d4fba0788-20240530)
|
||||
optionalDependencies:
|
||||
'@mui/icons-material': 5.15.20(@mui/material@5.15.20(@emotion/react@11.11.4(react@19.0.0-rc-9d4fba0788-20240530)(types-react@19.0.0-rc.0))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-9d4fba0788-20240530)(types-react@19.0.0-rc.0))(react@19.0.0-rc-9d4fba0788-20240530)(types-react@19.0.0-rc.0))(react@19.0.0-rc-9d4fba0788-20240530)(types-react@19.0.0-rc.0))(react@19.0.0-rc-9d4fba0788-20240530)(types-react@19.0.0-rc.0)
|
||||
|
||||
react-hook-form@7.51.5(react@19.0.0-rc-9d4fba0788-20240530):
|
||||
react-hook-form@7.52.0(react@19.0.0-rc-9d4fba0788-20240530):
|
||||
dependencies:
|
||||
react: 19.0.0-rc-9d4fba0788-20240530
|
||||
|
||||
@@ -9645,9 +9787,9 @@ snapshots:
|
||||
|
||||
shell-quote@1.8.1: {}
|
||||
|
||||
shiki@1.6.4:
|
||||
shiki@1.6.5:
|
||||
dependencies:
|
||||
'@shikijs/core': 1.6.4
|
||||
'@shikijs/core': 1.6.5
|
||||
|
||||
side-channel@1.0.6:
|
||||
dependencies:
|
||||
@@ -10278,37 +10420,37 @@ snapshots:
|
||||
esbuild: 0.19.12
|
||||
monaco-editor: 0.49.0
|
||||
|
||||
vite-plugin-sass-dts@1.3.22(postcss@8.4.38)(prettier@3.3.2)(sass@1.77.5)(vite@5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)):
|
||||
vite-plugin-sass-dts@1.3.22(postcss@8.4.38)(prettier@3.3.2)(sass@1.77.5)(vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
postcss: 8.4.38
|
||||
postcss-js: 4.0.1(postcss@8.4.38)
|
||||
prettier: 3.3.2
|
||||
sass: 1.77.5
|
||||
vite: 5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
vite: 5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
|
||||
vite-plugin-svgr@4.2.0(rollup@4.17.2)(typescript@5.4.5)(vite@5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)):
|
||||
vite-plugin-svgr@4.2.0(rollup@4.17.2)(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.1.0(rollup@4.17.2)
|
||||
'@svgr/core': 8.1.0(typescript@5.4.5)
|
||||
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.4.5))
|
||||
vite: 5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
vite: 5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite-tsconfig-paths@4.3.2(typescript@5.4.5)(vite@5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)):
|
||||
vite-tsconfig-paths@4.3.2(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
globrex: 0.1.2
|
||||
tsconfck: 3.0.3(typescript@5.4.5)
|
||||
optionalDependencies:
|
||||
vite: 5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
vite: 5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite@5.3.0(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0):
|
||||
vite@5.3.1(@types/node@20.14.2)(less@4.2.0)(sass@1.77.5)(stylus@0.62.0):
|
||||
dependencies:
|
||||
esbuild: 0.21.4
|
||||
postcss: 8.4.38
|
||||
|
@@ -88,37 +88,16 @@ pub fn toggle_system_proxy() {
|
||||
pub fn toggle_tun_mode() {
|
||||
let enable = Config::verge().data().enable_tun_mode;
|
||||
let enable = enable.unwrap_or(false);
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
if !enable {
|
||||
if let Ok(res) = service::check_service().await {
|
||||
if res.code == 0 {
|
||||
match patch_verge(IVerge {
|
||||
enable_tun_mode: Some(!enable),
|
||||
..IVerge::default()
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(_) => handle::Handle::refresh_verge(),
|
||||
Err(err) => log::error!(target: "app", "{err}"),
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
tauri::api::dialog::message(
|
||||
None::<&tauri::Window>,
|
||||
"Please install and enable service mode",
|
||||
"Service mode is required for Tun mode",
|
||||
);
|
||||
} else {
|
||||
match patch_verge(IVerge {
|
||||
enable_tun_mode: Some(!enable),
|
||||
..IVerge::default()
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(_) => handle::Handle::refresh_verge(),
|
||||
Err(err) => log::error!(target: "app", "{err}"),
|
||||
}
|
||||
match patch_verge(IVerge {
|
||||
enable_tun_mode: Some(!enable),
|
||||
..IVerge::default()
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(_) => handle::Handle::refresh_verge(),
|
||||
Err(err) => log::error!(target: "app", "{err}"),
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -424,19 +403,3 @@ pub async fn test_delay(url: String) -> Result<u32> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_permission() -> Result<()> {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let hklm = winreg::RegKey::predef(winreg::enums::HKEY_LOCAL_MACHINE);
|
||||
|
||||
if let Ok(reg) = hklm.open_subkey_with_flags(
|
||||
"SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Run",
|
||||
winreg::enums::KEY_SET_VALUE,
|
||||
) {
|
||||
reg.delete_value("Clash Verge").unwrap_or_default();
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(anyhow::anyhow!("permission denied"))
|
||||
}
|
||||
|
@@ -19,16 +19,6 @@ fn main() -> std::io::Result<()> {
|
||||
println!("app exists");
|
||||
return Ok(());
|
||||
}
|
||||
// 权限检测
|
||||
if feat::check_permission().is_ok() {
|
||||
println!("please do not run with admin permission");
|
||||
tauri::api::dialog::blocking::message(
|
||||
None::<&tauri::Window>,
|
||||
"Please do not run with admin permission",
|
||||
"If you want to use Tun mode, please enable service mode instead",
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
|
||||
|
@@ -12,7 +12,7 @@ import { useLogSetup } from "./use-log-setup";
|
||||
import { useVisibility } from "@/hooks/use-visibility";
|
||||
import parseTraffic from "@/utils/parse-traffic";
|
||||
import useSWRSubscription from "swr/subscription";
|
||||
import Sockette from "sockette";
|
||||
import { createSockette } from "@/utils/websocket";
|
||||
|
||||
interface MemoryUsage {
|
||||
inuse: number;
|
||||
@@ -42,24 +42,17 @@ export const LayoutTraffic = () => {
|
||||
(_key, { next }) => {
|
||||
const { server = "", secret = "" } = clashInfo!;
|
||||
|
||||
let errorCount = 10;
|
||||
|
||||
const s = new Sockette(
|
||||
const s = createSockette(
|
||||
`ws://${server}/traffic?token=${encodeURIComponent(secret)}`,
|
||||
{
|
||||
onmessage(event) {
|
||||
errorCount = 0; // reset counter
|
||||
const data = JSON.parse(event.data) as ITrafficItem;
|
||||
trafficRef.current?.appendData(data);
|
||||
next(null, data);
|
||||
},
|
||||
onerror(event) {
|
||||
errorCount -= 1;
|
||||
|
||||
if (errorCount <= 0) {
|
||||
this.close();
|
||||
next(event, { up: 0, down: 0 });
|
||||
}
|
||||
this.close();
|
||||
next(event, { up: 0, down: 0 });
|
||||
},
|
||||
}
|
||||
);
|
||||
@@ -86,27 +79,23 @@ export const LayoutTraffic = () => {
|
||||
clashInfo && pageVisible && displayMemory ? "getRealtimeMemory" : null,
|
||||
(_key, { next }) => {
|
||||
const { server = "", secret = "" } = clashInfo!;
|
||||
const ws = new WebSocket(
|
||||
`ws://${server}/memory?token=${encodeURIComponent(secret)}`
|
||||
|
||||
const s = createSockette(
|
||||
`ws://${server}/memory?token=${encodeURIComponent(secret)}`,
|
||||
{
|
||||
onmessage(event) {
|
||||
const data = JSON.parse(event.data) as MemoryUsage;
|
||||
next(null, data);
|
||||
},
|
||||
onerror(event) {
|
||||
this.close();
|
||||
next(event, { inuse: 0 });
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let errorCount = 10;
|
||||
|
||||
ws.addEventListener("message", (event) => {
|
||||
errorCount = 0; // reset counter
|
||||
next(null, JSON.parse(event.data));
|
||||
});
|
||||
ws.addEventListener("error", (event) => {
|
||||
errorCount -= 1;
|
||||
|
||||
if (errorCount <= 0) {
|
||||
ws.close();
|
||||
next(event, { inuse: 0 });
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
ws.close();
|
||||
s.close();
|
||||
};
|
||||
},
|
||||
{
|
||||
|
@@ -24,7 +24,6 @@ export const StackModeSwitch = (props: Props) => {
|
||||
>
|
||||
gVisor
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant={value?.toLowerCase() === "mixed" ? "contained" : "outlined"}
|
||||
onClick={() => onChange?.("mixed")}
|
||||
|
@@ -22,15 +22,11 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
const { verge, mutateVerge, patchVerge } = useVerge();
|
||||
|
||||
// service mode
|
||||
const { data: serviceStatus, mutate: mutateCheck } = useSWR(
|
||||
"checkService",
|
||||
checkService,
|
||||
{
|
||||
revalidateIfStale: false,
|
||||
shouldRetryOnError: false,
|
||||
focusThrottleInterval: 36e5, // 1 hour
|
||||
}
|
||||
);
|
||||
const { data: serviceStatus } = useSWR("checkService", checkService, {
|
||||
revalidateIfStale: false,
|
||||
shouldRetryOnError: false,
|
||||
focusThrottleInterval: 36e5, // 1 hour
|
||||
});
|
||||
|
||||
const serviceRef = useRef<DialogRef>(null);
|
||||
const sysproxyRef = useRef<DialogRef>(null);
|
||||
@@ -88,7 +84,7 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
onChange={(e) => onChangeData({ enable_tun_mode: e })}
|
||||
onGuard={(e) => patchVerge({ enable_tun_mode: e })}
|
||||
>
|
||||
<Switch disabled={serviceStatus !== "active"} edge="end" />
|
||||
<Switch edge="end" />
|
||||
</GuardState>
|
||||
</SettingItem>
|
||||
|
||||
@@ -113,10 +109,7 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
onCatch={onError}
|
||||
onFormat={onSwitchFormat}
|
||||
onChange={(e) => onChangeData({ enable_service_mode: e })}
|
||||
onGuard={(e) => {
|
||||
setTimeout(() => mutateCheck(), 1000);
|
||||
return patchVerge({ enable_service_mode: e });
|
||||
}}
|
||||
onGuard={(e) => patchVerge({ enable_service_mode: e })}
|
||||
>
|
||||
<Switch
|
||||
edge="end"
|
||||
|
39
clash-verge-rev/src/utils/websocket.ts
Normal file
39
clash-verge-rev/src/utils/websocket.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import Sockette, { type SocketteOptions } from "sockette";
|
||||
|
||||
/**
|
||||
* A wrapper of Sockette that will automatically reconnect up to `maxError` before emitting an error event.
|
||||
*/
|
||||
export const createSockette = (
|
||||
url: string,
|
||||
opt: SocketteOptions,
|
||||
maxError = 10
|
||||
) => {
|
||||
let remainRetryCount = maxError;
|
||||
|
||||
return new Sockette(url, {
|
||||
...opt,
|
||||
// Sockette has a built-in reconnect when ECONNREFUSED feature
|
||||
// Use maxError if opt.maxAttempts is not specified
|
||||
maxAttempts: opt.maxAttempts ?? maxError,
|
||||
onmessage(this: Sockette, ev) {
|
||||
remainRetryCount = maxError; // reset counter
|
||||
opt.onmessage?.call(this, ev);
|
||||
},
|
||||
onerror(this: Sockette, ev) {
|
||||
remainRetryCount -= 1;
|
||||
|
||||
if (remainRetryCount >= 0) {
|
||||
this.close();
|
||||
this.reconnect();
|
||||
} else {
|
||||
opt.onerror?.call(this, ev);
|
||||
}
|
||||
},
|
||||
onmaximum(this: Sockette, ev) {
|
||||
opt.onmaximum?.call(this, ev);
|
||||
// onmaximum will be fired when Sockette reaches built-in reconnect limit,
|
||||
// We will also set remainRetryCount to 0 to prevent further reconnect.
|
||||
remainRetryCount = 0;
|
||||
},
|
||||
});
|
||||
};
|
@@ -152,8 +152,8 @@ func formatSpeed(bytes uint32, duration time.Duration, useBytes bool) string {
|
||||
speed *= 8
|
||||
}
|
||||
unitIndex := 0
|
||||
for speed > 1024 && unitIndex < len(units)-1 {
|
||||
speed /= 1024
|
||||
for speed > 1000 && unitIndex < len(units)-1 {
|
||||
speed /= 1000
|
||||
unitIndex++
|
||||
}
|
||||
return fmt.Sprintf("%.2f %s", speed, units[unitIndex])
|
||||
|
@@ -976,8 +976,8 @@ func formatSpeed(bw Bandwidth) string {
|
||||
bwf := float64(bw)
|
||||
units := []string{"bps", "Kbps", "Mbps", "Gbps"}
|
||||
unitIndex := 0
|
||||
for bwf > 1024 && unitIndex < len(units)-1 {
|
||||
bwf /= 1024
|
||||
for bwf > 1000 && unitIndex < len(units)-1 {
|
||||
bwf /= 1000
|
||||
unitIndex++
|
||||
}
|
||||
return fmt.Sprintf("%.2f %s", bwf, units[unitIndex])
|
||||
|
@@ -1,2 +1,2 @@
|
||||
LINUX_VERSION-5.15 = .160
|
||||
LINUX_KERNEL_HASH-5.15.160 = f41e718e33b88f269a6b6a7653e5e9824c4ba541f6ffe5bf26ecc37c540a1b05
|
||||
LINUX_VERSION-5.15 = .161
|
||||
LINUX_KERNEL_HASH-5.15.161 = d629f78680dc4b65e3d78b61406fb7757b960c83c206e63ad8c2606b3e3c474c
|
||||
|
@@ -1,2 +1,2 @@
|
||||
LINUX_VERSION-6.6 = .32
|
||||
LINUX_KERNEL_HASH-6.6.32 = aaa824eaf07f61911d22b75ff090a403c3dd0bd73e23933e0bba8b5971436ce1
|
||||
LINUX_VERSION-6.6 = .33
|
||||
LINUX_KERNEL_HASH-6.6.33 = a13ebc20dc2a75722699949af74aa86a4ce5d544d6daaa6a7de4e8c81b40de97
|
||||
|
@@ -25,7 +25,7 @@ Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
|
||||
--- a/drivers/mtd/mtdcore.c
|
||||
+++ b/drivers/mtd/mtdcore.c
|
||||
@@ -1175,6 +1175,34 @@ int __get_mtd_device(struct mtd_info *mt
|
||||
@@ -1177,6 +1177,34 @@ int __get_mtd_device(struct mtd_info *mt
|
||||
EXPORT_SYMBOL_GPL(__get_mtd_device);
|
||||
|
||||
/**
|
||||
|
@@ -17,7 +17,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -4087,13 +4087,13 @@ static int mtk_probe(struct platform_dev
|
||||
@@ -4089,13 +4089,13 @@ static int mtk_probe(struct platform_dev
|
||||
eth->soc->offload_version, i);
|
||||
if (!eth->ppe[i]) {
|
||||
err = -ENOMEM;
|
||||
|
@@ -21,7 +21,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -4087,13 +4087,13 @@ static int mtk_probe(struct platform_dev
|
||||
@@ -4089,13 +4089,13 @@ static int mtk_probe(struct platform_dev
|
||||
eth->soc->offload_version, i);
|
||||
if (!eth->ppe[i]) {
|
||||
err = -ENOMEM;
|
||||
@@ -37,7 +37,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
}
|
||||
|
||||
for (i = 0; i < MTK_MAX_DEVS; i++) {
|
||||
@@ -4103,7 +4103,7 @@ static int mtk_probe(struct platform_dev
|
||||
@@ -4105,7 +4105,7 @@ static int mtk_probe(struct platform_dev
|
||||
err = register_netdev(eth->netdev[i]);
|
||||
if (err) {
|
||||
dev_err(eth->dev, "error bringing up device\n");
|
||||
@@ -46,7 +46,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
} else
|
||||
netif_info(eth, probe, eth->netdev[i],
|
||||
"mediatek frame engine at 0x%08lx, irq %d\n",
|
||||
@@ -4123,7 +4123,8 @@ static int mtk_probe(struct platform_dev
|
||||
@@ -4125,7 +4125,8 @@ static int mtk_probe(struct platform_dev
|
||||
|
||||
return 0;
|
||||
|
||||
|
@@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -4423,7 +4423,7 @@ static const struct mtk_soc_data mt7621_
|
||||
@@ -4424,7 +4424,7 @@ static const struct mtk_soc_data mt7621_
|
||||
.hw_features = MTK_HW_FEATURES,
|
||||
.required_clks = MT7621_CLKS_BITMAP,
|
||||
.required_pctl = false,
|
||||
@@ -21,7 +21,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
.hash_offset = 2,
|
||||
.foe_entry_size = sizeof(struct mtk_foe_entry) - 16,
|
||||
.txrx = {
|
||||
@@ -4462,7 +4462,7 @@ static const struct mtk_soc_data mt7623_
|
||||
@@ -4463,7 +4463,7 @@ static const struct mtk_soc_data mt7623_
|
||||
.hw_features = MTK_HW_FEATURES,
|
||||
.required_clks = MT7623_CLKS_BITMAP,
|
||||
.required_pctl = true,
|
||||
|
@@ -34,7 +34,7 @@
|
||||
mtk_eth_path_name(path), __func__, updated);
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -4750,6 +4750,26 @@ static const struct mtk_soc_data mt7629_
|
||||
@@ -4751,6 +4751,26 @@ static const struct mtk_soc_data mt7629_
|
||||
},
|
||||
};
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
static const struct mtk_soc_data mt7986_data = {
|
||||
.reg_map = &mt7986_reg_map,
|
||||
.ana_rgc3 = 0x128,
|
||||
@@ -4792,6 +4812,7 @@ const struct of_device_id of_mtk_match[]
|
||||
@@ -4793,6 +4813,7 @@ const struct of_device_id of_mtk_match[]
|
||||
{ .compatible = "mediatek,mt7622-eth", .data = &mt7622_data},
|
||||
{ .compatible = "mediatek,mt7623-eth", .data = &mt7623_data},
|
||||
{ .compatible = "mediatek,mt7629-eth", .data = &mt7629_data},
|
||||
@@ -128,7 +128,7 @@
|
||||
|
||||
#define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \
|
||||
BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT)
|
||||
@@ -963,6 +987,11 @@ enum mkt_eth_capabilities {
|
||||
@@ -957,6 +981,11 @@ enum mkt_eth_capabilities {
|
||||
MTK_MUX_U3_GMAC2_TO_QPHY | \
|
||||
MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA)
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
#define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \
|
||||
MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
|
||||
MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1)
|
||||
@@ -1076,12 +1105,14 @@ struct mtk_soc_data {
|
||||
@@ -1070,12 +1099,14 @@ struct mtk_soc_data {
|
||||
* @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap
|
||||
* @interface: Currently configured interface mode
|
||||
* @pcs: Phylink PCS structure
|
||||
|
@@ -151,7 +151,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
}
|
||||
|
||||
if (eth->soc->offload_version) {
|
||||
@@ -4650,6 +4687,8 @@ err_deinit_hw:
|
||||
@@ -4651,6 +4688,8 @@ err_deinit_hw:
|
||||
mtk_hw_deinit(eth);
|
||||
err_wed_exit:
|
||||
mtk_wed_exit();
|
||||
@@ -228,7 +228,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
/* Infrasys subsystem config registers */
|
||||
#define INFRA_MISC2 0x70c
|
||||
#define CO_QPHY_SEL BIT(0)
|
||||
@@ -1105,31 +1046,6 @@ struct mtk_soc_data {
|
||||
@@ -1099,31 +1040,6 @@ struct mtk_soc_data {
|
||||
/* currently no SoC has more than 2 macs */
|
||||
#define MTK_MAX_DEVS 2
|
||||
|
||||
@@ -260,7 +260,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
/* struct mtk_eth - This is the main datasructure for holding the state
|
||||
* of the driver
|
||||
* @dev: The device pointer
|
||||
@@ -1149,6 +1065,7 @@ struct mtk_sgmii {
|
||||
@@ -1143,6 +1059,7 @@ struct mtk_sgmii {
|
||||
* MII modes
|
||||
* @infra: The register map pointing at the range used to setup
|
||||
* SGMII and GePHY path
|
||||
@@ -268,7 +268,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
* @pctl: The register map pointing at the range used to setup
|
||||
* GMAC port drive/slew values
|
||||
* @dma_refcnt: track how many netdevs are using the DMA engine
|
||||
@@ -1189,8 +1106,8 @@ struct mtk_eth {
|
||||
@@ -1183,8 +1100,8 @@ struct mtk_eth {
|
||||
u32 msg_enable;
|
||||
unsigned long sysclk;
|
||||
struct regmap *ethsys;
|
||||
@@ -279,7 +279,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
struct regmap *pctl;
|
||||
bool hwlro;
|
||||
refcount_t dma_refcnt;
|
||||
@@ -1352,10 +1269,6 @@ void mtk_stats_update_mac(struct mtk_mac
|
||||
@@ -1346,10 +1263,6 @@ void mtk_stats_update_mac(struct mtk_mac
|
||||
void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg);
|
||||
u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
|
||||
|
||||
|
@@ -53,7 +53,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -4635,8 +4635,8 @@ static int mtk_probe(struct platform_dev
|
||||
@@ -4637,8 +4637,8 @@ static int mtk_probe(struct platform_dev
|
||||
for (i = 0; i < num_ppe; i++) {
|
||||
u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400;
|
||||
|
||||
@@ -64,7 +64,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov
|
||||
if (!eth->ppe[i]) {
|
||||
err = -ENOMEM;
|
||||
goto err_deinit_ppe;
|
||||
@@ -4762,6 +4762,7 @@ static const struct mtk_soc_data mt7622_
|
||||
@@ -4764,6 +4764,7 @@ static const struct mtk_soc_data mt7622_
|
||||
.required_pctl = false,
|
||||
.offload_version = 2,
|
||||
.hash_offset = 2,
|
||||
@@ -72,7 +72,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov
|
||||
.foe_entry_size = sizeof(struct mtk_foe_entry) - 16,
|
||||
.txrx = {
|
||||
.txd_size = sizeof(struct mtk_tx_dma),
|
||||
@@ -4799,6 +4800,7 @@ static const struct mtk_soc_data mt7629_
|
||||
@@ -4801,6 +4802,7 @@ static const struct mtk_soc_data mt7629_
|
||||
.hw_features = MTK_HW_FEATURES,
|
||||
.required_clks = MT7629_CLKS_BITMAP,
|
||||
.required_pctl = false,
|
||||
@@ -80,7 +80,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov
|
||||
.txrx = {
|
||||
.txd_size = sizeof(struct mtk_tx_dma),
|
||||
.rxd_size = sizeof(struct mtk_rx_dma),
|
||||
@@ -4819,6 +4821,7 @@ static const struct mtk_soc_data mt7981_
|
||||
@@ -4821,6 +4823,7 @@ static const struct mtk_soc_data mt7981_
|
||||
.offload_version = 2,
|
||||
.hash_offset = 4,
|
||||
.foe_entry_size = sizeof(struct mtk_foe_entry),
|
||||
@@ -88,7 +88,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov
|
||||
.txrx = {
|
||||
.txd_size = sizeof(struct mtk_tx_dma_v2),
|
||||
.rxd_size = sizeof(struct mtk_rx_dma_v2),
|
||||
@@ -4839,6 +4842,7 @@ static const struct mtk_soc_data mt7986_
|
||||
@@ -4841,6 +4844,7 @@ static const struct mtk_soc_data mt7986_
|
||||
.offload_version = 2,
|
||||
.hash_offset = 4,
|
||||
.foe_entry_size = sizeof(struct mtk_foe_entry),
|
||||
|
@@ -17,7 +17,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -4711,7 +4711,7 @@ static const struct mtk_soc_data mt7621_
|
||||
@@ -4713,7 +4713,7 @@ static const struct mtk_soc_data mt7621_
|
||||
.required_pctl = false,
|
||||
.offload_version = 1,
|
||||
.hash_offset = 2,
|
||||
@@ -26,7 +26,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
.txrx = {
|
||||
.txd_size = sizeof(struct mtk_tx_dma),
|
||||
.rxd_size = sizeof(struct mtk_rx_dma),
|
||||
@@ -4732,7 +4732,7 @@ static const struct mtk_soc_data mt7622_
|
||||
@@ -4734,7 +4734,7 @@ static const struct mtk_soc_data mt7622_
|
||||
.offload_version = 2,
|
||||
.hash_offset = 2,
|
||||
.has_accounting = true,
|
||||
@@ -35,7 +35,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
.txrx = {
|
||||
.txd_size = sizeof(struct mtk_tx_dma),
|
||||
.rxd_size = sizeof(struct mtk_rx_dma),
|
||||
@@ -4751,7 +4751,7 @@ static const struct mtk_soc_data mt7623_
|
||||
@@ -4753,7 +4753,7 @@ static const struct mtk_soc_data mt7623_
|
||||
.required_pctl = true,
|
||||
.offload_version = 1,
|
||||
.hash_offset = 2,
|
||||
@@ -44,7 +44,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
.txrx = {
|
||||
.txd_size = sizeof(struct mtk_tx_dma),
|
||||
.rxd_size = sizeof(struct mtk_rx_dma),
|
||||
@@ -4789,8 +4789,8 @@ static const struct mtk_soc_data mt7981_
|
||||
@@ -4791,8 +4791,8 @@ static const struct mtk_soc_data mt7981_
|
||||
.required_pctl = false,
|
||||
.offload_version = 2,
|
||||
.hash_offset = 4,
|
||||
@@ -54,7 +54,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
.txrx = {
|
||||
.txd_size = sizeof(struct mtk_tx_dma_v2),
|
||||
.rxd_size = sizeof(struct mtk_rx_dma_v2),
|
||||
@@ -4810,8 +4810,8 @@ static const struct mtk_soc_data mt7986_
|
||||
@@ -4812,8 +4812,8 @@ static const struct mtk_soc_data mt7986_
|
||||
.required_pctl = false,
|
||||
.offload_version = 2,
|
||||
.hash_offset = 4,
|
||||
|
@@ -95,7 +95,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
/* mt7623_pad_clk_setup */
|
||||
for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
|
||||
@@ -4286,13 +4258,19 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
@@ -4288,13 +4260,19 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
mac->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
|
||||
MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD;
|
||||
|
||||
@@ -121,7 +121,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII) && !mac->id)
|
||||
__set_bit(PHY_INTERFACE_MODE_TRGMII,
|
||||
@@ -4752,6 +4730,7 @@ static const struct mtk_soc_data mt7623_
|
||||
@@ -4754,6 +4732,7 @@ static const struct mtk_soc_data mt7623_
|
||||
.offload_version = 1,
|
||||
.hash_offset = 2,
|
||||
.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
|
||||
|
@@ -23,7 +23,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -512,38 +512,6 @@ static int mtk_mac_finish(struct phylink
|
||||
@@ -511,38 +511,6 @@ static int mtk_mac_finish(struct phylink
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
@@ -666,7 +634,6 @@ static void mtk_mac_link_up(struct phyli
|
||||
@@ -665,7 +633,6 @@ static void mtk_mac_link_up(struct phyli
|
||||
static const struct phylink_mac_ops mtk_phylink_ops = {
|
||||
.validate = phylink_generic_validate,
|
||||
.mac_select_pcs = mtk_mac_select_pcs,
|
||||
@@ -70,7 +70,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
.mac_config = mtk_mac_config,
|
||||
.mac_finish = mtk_mac_finish,
|
||||
.mac_link_down = mtk_mac_link_down,
|
||||
@@ -4253,8 +4220,6 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
@@ -4255,8 +4222,6 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
|
||||
mac->phylink_config.dev = ð->netdev[id]->dev;
|
||||
mac->phylink_config.type = PHYLINK_NETDEV;
|
||||
|
@@ -23,7 +23,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -537,7 +537,7 @@ static void mtk_set_queue_speed(struct m
|
||||
@@ -536,7 +536,7 @@ static void mtk_set_queue_speed(struct m
|
||||
FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
|
||||
FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |
|
||||
MTK_QTX_SCH_LEAKY_BUCKET_SIZE;
|
||||
@@ -32,7 +32,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
val |= MTK_QTX_SCH_LEAKY_BUCKET_EN;
|
||||
|
||||
if (IS_ENABLED(CONFIG_SOC_MT7621)) {
|
||||
@@ -912,7 +912,7 @@ static bool mtk_rx_get_desc(struct mtk_e
|
||||
@@ -911,7 +911,7 @@ static bool mtk_rx_get_desc(struct mtk_e
|
||||
rxd->rxd1 = READ_ONCE(dma_rxd->rxd1);
|
||||
rxd->rxd3 = READ_ONCE(dma_rxd->rxd3);
|
||||
rxd->rxd4 = READ_ONCE(dma_rxd->rxd4);
|
||||
@@ -41,7 +41,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
rxd->rxd5 = READ_ONCE(dma_rxd->rxd5);
|
||||
rxd->rxd6 = READ_ONCE(dma_rxd->rxd6);
|
||||
}
|
||||
@@ -970,7 +970,7 @@ static int mtk_init_fq_dma(struct mtk_et
|
||||
@@ -969,7 +969,7 @@ static int mtk_init_fq_dma(struct mtk_et
|
||||
|
||||
txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE);
|
||||
txd->txd4 = 0;
|
||||
@@ -50,7 +50,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
txd->txd5 = 0;
|
||||
txd->txd6 = 0;
|
||||
txd->txd7 = 0;
|
||||
@@ -1159,7 +1159,7 @@ static void mtk_tx_set_dma_desc(struct n
|
||||
@@ -1158,7 +1158,7 @@ static void mtk_tx_set_dma_desc(struct n
|
||||
struct mtk_mac *mac = netdev_priv(dev);
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
|
||||
@@ -59,7 +59,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
mtk_tx_set_dma_desc_v2(dev, txd, info);
|
||||
else
|
||||
mtk_tx_set_dma_desc_v1(dev, txd, info);
|
||||
@@ -1466,7 +1466,7 @@ static void mtk_update_rx_cpu_idx(struct
|
||||
@@ -1465,7 +1465,7 @@ static void mtk_update_rx_cpu_idx(struct
|
||||
|
||||
static bool mtk_page_pool_enabled(struct mtk_eth *eth)
|
||||
{
|
||||
@@ -68,7 +68,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
}
|
||||
|
||||
static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth,
|
||||
@@ -1806,7 +1806,7 @@ static int mtk_poll_rx(struct napi_struc
|
||||
@@ -1805,7 +1805,7 @@ static int mtk_poll_rx(struct napi_struc
|
||||
break;
|
||||
|
||||
/* find out which mac the packet come from. values start at 1 */
|
||||
@@ -77,7 +77,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
mac = RX_DMA_GET_SPORT_V2(trxd.rxd5) - 1;
|
||||
else if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) &&
|
||||
!(trxd.rxd4 & RX_DMA_SPECIAL_TAG))
|
||||
@@ -1902,7 +1902,7 @@ static int mtk_poll_rx(struct napi_struc
|
||||
@@ -1901,7 +1901,7 @@ static int mtk_poll_rx(struct napi_struc
|
||||
skb->dev = netdev;
|
||||
bytes += skb->len;
|
||||
|
||||
@@ -86,7 +86,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON, trxd.rxd5);
|
||||
hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY;
|
||||
if (hash != MTK_RXD5_FOE_ENTRY)
|
||||
@@ -1927,8 +1927,8 @@ static int mtk_poll_rx(struct napi_struc
|
||||
@@ -1926,8 +1926,8 @@ static int mtk_poll_rx(struct napi_struc
|
||||
/* When using VLAN untagging in combination with DSA, the
|
||||
* hardware treats the MTK special tag as a VLAN and untags it.
|
||||
*/
|
||||
@@ -97,7 +97,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
unsigned int port = RX_DMA_VPID(trxd.rxd3) & GENMASK(2, 0);
|
||||
|
||||
if (port < ARRAY_SIZE(eth->dsa_meta) &&
|
||||
@@ -2232,7 +2232,7 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
@@ -2231,7 +2231,7 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
txd->txd2 = next_ptr;
|
||||
txd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU;
|
||||
txd->txd4 = 0;
|
||||
@@ -106,7 +106,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
txd->txd5 = 0;
|
||||
txd->txd6 = 0;
|
||||
txd->txd7 = 0;
|
||||
@@ -2285,14 +2285,14 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
@@ -2284,14 +2284,14 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
|
||||
FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |
|
||||
MTK_QTX_SCH_LEAKY_BUCKET_SIZE;
|
||||
@@ -123,7 +123,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
mtk_w32(eth, val, soc->reg_map->qdma.tx_sch_rate + 4);
|
||||
} else {
|
||||
mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0);
|
||||
@@ -2419,7 +2419,7 @@ static int mtk_rx_alloc(struct mtk_eth *
|
||||
@@ -2418,7 +2418,7 @@ static int mtk_rx_alloc(struct mtk_eth *
|
||||
|
||||
rxd->rxd3 = 0;
|
||||
rxd->rxd4 = 0;
|
||||
@@ -132,7 +132,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
rxd->rxd5 = 0;
|
||||
rxd->rxd6 = 0;
|
||||
rxd->rxd7 = 0;
|
||||
@@ -2967,7 +2967,7 @@ static int mtk_start_dma(struct mtk_eth
|
||||
@@ -2969,7 +2969,7 @@ static int mtk_start_dma(struct mtk_eth
|
||||
MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO |
|
||||
MTK_RX_2B_OFFSET | MTK_TX_WB_DDONE;
|
||||
|
||||
@@ -141,7 +141,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
val |= MTK_MUTLI_CNT | MTK_RESV_BUF |
|
||||
MTK_WCOMP_EN | MTK_DMAD_WR_WDONE |
|
||||
MTK_CHK_DDONE_EN | MTK_LEAKY_BUCKET_EN;
|
||||
@@ -3111,7 +3111,7 @@ static int mtk_open(struct net_device *d
|
||||
@@ -3113,7 +3113,7 @@ static int mtk_open(struct net_device *d
|
||||
phylink_start(mac->phylink);
|
||||
netif_tx_start_all_queues(dev);
|
||||
|
||||
@@ -150,7 +150,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
return 0;
|
||||
|
||||
if (mtk_uses_dsa(dev) && !eth->prog) {
|
||||
@@ -3376,7 +3376,7 @@ static void mtk_hw_reset(struct mtk_eth
|
||||
@@ -3378,7 +3378,7 @@ static void mtk_hw_reset(struct mtk_eth
|
||||
{
|
||||
u32 val;
|
||||
|
||||
@@ -159,7 +159,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, 0);
|
||||
val = RSTCTRL_PPE0_V2;
|
||||
} else {
|
||||
@@ -3388,7 +3388,7 @@ static void mtk_hw_reset(struct mtk_eth
|
||||
@@ -3390,7 +3390,7 @@ static void mtk_hw_reset(struct mtk_eth
|
||||
|
||||
ethsys_reset(eth, RSTCTRL_ETH | RSTCTRL_FE | val);
|
||||
|
||||
@@ -168,7 +168,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN,
|
||||
0x3ffffff);
|
||||
}
|
||||
@@ -3414,7 +3414,7 @@ static void mtk_hw_warm_reset(struct mtk
|
||||
@@ -3416,7 +3416,7 @@ static void mtk_hw_warm_reset(struct mtk
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
rst_mask = RSTCTRL_ETH | RSTCTRL_PPE0_V2;
|
||||
else
|
||||
rst_mask = RSTCTRL_ETH | RSTCTRL_PPE0;
|
||||
@@ -3584,7 +3584,7 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
@@ -3586,7 +3586,7 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
else
|
||||
mtk_hw_reset(eth);
|
||||
|
||||
@@ -186,7 +186,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
/* Set FE to PDMAv2 if necessary */
|
||||
val = mtk_r32(eth, MTK_FE_GLO_MISC);
|
||||
mtk_w32(eth, val | BIT(4), MTK_FE_GLO_MISC);
|
||||
@@ -3621,7 +3621,7 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
@@ -3623,7 +3623,7 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
*/
|
||||
val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
|
||||
mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
|
||||
@@ -195,7 +195,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
|
||||
mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
|
||||
|
||||
@@ -3643,7 +3643,7 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
@@ -3645,7 +3645,7 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask, reg_map->qdma.int_grp + 4);
|
||||
mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
|
||||
|
||||
@@ -204,7 +204,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
/* PSE should not drop port8 and port9 packets from WDMA Tx */
|
||||
mtk_w32(eth, 0x00000300, PSE_DROP_CFG);
|
||||
|
||||
@@ -4432,7 +4432,7 @@ static int mtk_probe(struct platform_dev
|
||||
@@ -4434,7 +4434,7 @@ static int mtk_probe(struct platform_dev
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
err = -EINVAL;
|
||||
@@ -4540,9 +4540,8 @@ static int mtk_probe(struct platform_dev
|
||||
@@ -4542,9 +4542,8 @@ static int mtk_probe(struct platform_dev
|
||||
}
|
||||
|
||||
if (eth->soc->offload_version) {
|
||||
@@ -224,7 +224,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
num_ppe = min_t(u32, ARRAY_SIZE(eth->ppe), num_ppe);
|
||||
for (i = 0; i < num_ppe; i++) {
|
||||
u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400;
|
||||
@@ -4636,6 +4635,7 @@ static const struct mtk_soc_data mt2701_
|
||||
@@ -4638,6 +4637,7 @@ static const struct mtk_soc_data mt2701_
|
||||
.hw_features = MTK_HW_FEATURES,
|
||||
.required_clks = MT7623_CLKS_BITMAP,
|
||||
.required_pctl = true,
|
||||
@@ -232,7 +232,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
.txrx = {
|
||||
.txd_size = sizeof(struct mtk_tx_dma),
|
||||
.rxd_size = sizeof(struct mtk_rx_dma),
|
||||
@@ -4652,6 +4652,7 @@ static const struct mtk_soc_data mt7621_
|
||||
@@ -4654,6 +4654,7 @@ static const struct mtk_soc_data mt7621_
|
||||
.hw_features = MTK_HW_FEATURES,
|
||||
.required_clks = MT7621_CLKS_BITMAP,
|
||||
.required_pctl = false,
|
||||
@@ -240,7 +240,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
.offload_version = 1,
|
||||
.hash_offset = 2,
|
||||
.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
|
||||
@@ -4672,6 +4673,7 @@ static const struct mtk_soc_data mt7622_
|
||||
@@ -4674,6 +4675,7 @@ static const struct mtk_soc_data mt7622_
|
||||
.hw_features = MTK_HW_FEATURES,
|
||||
.required_clks = MT7622_CLKS_BITMAP,
|
||||
.required_pctl = false,
|
||||
@@ -248,7 +248,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
.offload_version = 2,
|
||||
.hash_offset = 2,
|
||||
.has_accounting = true,
|
||||
@@ -4692,6 +4694,7 @@ static const struct mtk_soc_data mt7623_
|
||||
@@ -4694,6 +4696,7 @@ static const struct mtk_soc_data mt7623_
|
||||
.hw_features = MTK_HW_FEATURES,
|
||||
.required_clks = MT7623_CLKS_BITMAP,
|
||||
.required_pctl = true,
|
||||
@@ -256,7 +256,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
.offload_version = 1,
|
||||
.hash_offset = 2,
|
||||
.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
|
||||
@@ -4714,6 +4717,7 @@ static const struct mtk_soc_data mt7629_
|
||||
@@ -4716,6 +4719,7 @@ static const struct mtk_soc_data mt7629_
|
||||
.required_clks = MT7629_CLKS_BITMAP,
|
||||
.required_pctl = false,
|
||||
.has_accounting = true,
|
||||
@@ -264,7 +264,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
.txrx = {
|
||||
.txd_size = sizeof(struct mtk_tx_dma),
|
||||
.rxd_size = sizeof(struct mtk_rx_dma),
|
||||
@@ -4731,6 +4735,7 @@ static const struct mtk_soc_data mt7981_
|
||||
@@ -4733,6 +4737,7 @@ static const struct mtk_soc_data mt7981_
|
||||
.hw_features = MTK_HW_FEATURES,
|
||||
.required_clks = MT7981_CLKS_BITMAP,
|
||||
.required_pctl = false,
|
||||
@@ -272,7 +272,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
.offload_version = 2,
|
||||
.hash_offset = 4,
|
||||
.has_accounting = true,
|
||||
@@ -4752,6 +4757,7 @@ static const struct mtk_soc_data mt7986_
|
||||
@@ -4754,6 +4759,7 @@ static const struct mtk_soc_data mt7986_
|
||||
.hw_features = MTK_HW_FEATURES,
|
||||
.required_clks = MT7986_CLKS_BITMAP,
|
||||
.required_pctl = false,
|
||||
@@ -280,7 +280,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
.offload_version = 2,
|
||||
.hash_offset = 4,
|
||||
.has_accounting = true,
|
||||
@@ -4772,6 +4778,7 @@ static const struct mtk_soc_data rt5350_
|
||||
@@ -4774,6 +4780,7 @@ static const struct mtk_soc_data rt5350_
|
||||
.hw_features = MTK_HW_FEATURES_MT7628,
|
||||
.required_clks = MT7628_CLKS_BITMAP,
|
||||
.required_pctl = false,
|
||||
@@ -491,7 +491,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
else
|
||||
val = MTK_FOE_IB2_MIB_CNT;
|
||||
@@ -971,7 +971,7 @@ void mtk_ppe_start(struct mtk_ppe *ppe)
|
||||
MTK_PPE_SCAN_MODE_KEEPALIVE_AGE) |
|
||||
MTK_PPE_SCAN_MODE_CHECK_AGE) |
|
||||
FIELD_PREP(MTK_PPE_TB_CFG_ENTRY_NUM,
|
||||
MTK_PPE_ENTRIES_SHIFT);
|
||||
- if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2))
|
||||
|
@@ -17,7 +17,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -838,7 +838,7 @@ static void mtk_stats_update(struct mtk_
|
||||
@@ -837,7 +837,7 @@ static void mtk_stats_update(struct mtk_
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -26,7 +26,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
if (!eth->mac[i] || !eth->mac[i]->hw_stats)
|
||||
continue;
|
||||
if (spin_trylock(ð->mac[i]->hw_stats->stats_lock)) {
|
||||
@@ -1341,7 +1341,7 @@ static int mtk_queue_stopped(struct mtk_
|
||||
@@ -1340,7 +1340,7 @@ static int mtk_queue_stopped(struct mtk_
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -35,7 +35,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
if (!eth->netdev[i])
|
||||
continue;
|
||||
if (netif_queue_stopped(eth->netdev[i]))
|
||||
@@ -1355,7 +1355,7 @@ static void mtk_wake_queue(struct mtk_et
|
||||
@@ -1354,7 +1354,7 @@ static void mtk_wake_queue(struct mtk_et
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -44,7 +44,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
if (!eth->netdev[i])
|
||||
continue;
|
||||
netif_tx_wake_all_queues(eth->netdev[i]);
|
||||
@@ -1812,7 +1812,7 @@ static int mtk_poll_rx(struct napi_struc
|
||||
@@ -1811,7 +1811,7 @@ static int mtk_poll_rx(struct napi_struc
|
||||
!(trxd.rxd4 & RX_DMA_SPECIAL_TAG))
|
||||
mac = RX_DMA_GET_SPORT(trxd.rxd4) - 1;
|
||||
|
||||
@@ -53,7 +53,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
!eth->netdev[mac]))
|
||||
goto release_desc;
|
||||
|
||||
@@ -2841,7 +2841,7 @@ static void mtk_dma_free(struct mtk_eth
|
||||
@@ -2843,7 +2843,7 @@ static void mtk_dma_free(struct mtk_eth
|
||||
const struct mtk_soc_data *soc = eth->soc;
|
||||
int i;
|
||||
|
||||
@@ -62,7 +62,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
if (eth->netdev[i])
|
||||
netdev_reset_queue(eth->netdev[i]);
|
||||
if (eth->scratch_ring) {
|
||||
@@ -2995,8 +2995,13 @@ static void mtk_gdm_config(struct mtk_et
|
||||
@@ -2997,8 +2997,13 @@ static void mtk_gdm_config(struct mtk_et
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
|
||||
return;
|
||||
|
||||
@@ -78,7 +78,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
/* default setup the forward port to send frame to PDMA */
|
||||
val &= ~0xffff;
|
||||
@@ -3006,7 +3011,7 @@ static void mtk_gdm_config(struct mtk_et
|
||||
@@ -3008,7 +3013,7 @@ static void mtk_gdm_config(struct mtk_et
|
||||
|
||||
val |= config;
|
||||
|
||||
@@ -87,7 +87,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
val |= MTK_GDMA_SPECIAL_TAG;
|
||||
|
||||
mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i));
|
||||
@@ -3605,15 +3610,15 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
@@ -3607,15 +3612,15 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
* up with the more appropriate value when mtk_mac_config call is being
|
||||
* invoked.
|
||||
*/
|
||||
@@ -109,7 +109,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
}
|
||||
|
||||
/* Indicates CDM to parse the MTK special tag from CPU
|
||||
@@ -3793,7 +3798,7 @@ static void mtk_pending_work(struct work
|
||||
@@ -3795,7 +3800,7 @@ static void mtk_pending_work(struct work
|
||||
mtk_prepare_for_reset(eth);
|
||||
|
||||
/* stop all devices to make sure that dma is properly shut down */
|
||||
@@ -118,7 +118,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
if (!eth->netdev[i] || !netif_running(eth->netdev[i]))
|
||||
continue;
|
||||
|
||||
@@ -3809,8 +3814,8 @@ static void mtk_pending_work(struct work
|
||||
@@ -3811,8 +3816,8 @@ static void mtk_pending_work(struct work
|
||||
mtk_hw_init(eth, true);
|
||||
|
||||
/* restart DMA and enable IRQs */
|
||||
@@ -129,7 +129,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
continue;
|
||||
|
||||
if (mtk_open(eth->netdev[i])) {
|
||||
@@ -3837,7 +3842,7 @@ static int mtk_free_dev(struct mtk_eth *
|
||||
@@ -3839,7 +3844,7 @@ static int mtk_free_dev(struct mtk_eth *
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -138,7 +138,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
if (!eth->netdev[i])
|
||||
continue;
|
||||
free_netdev(eth->netdev[i]);
|
||||
@@ -3856,7 +3861,7 @@ static int mtk_unreg_dev(struct mtk_eth
|
||||
@@ -3858,7 +3863,7 @@ static int mtk_unreg_dev(struct mtk_eth
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -147,7 +147,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
struct mtk_mac *mac;
|
||||
if (!eth->netdev[i])
|
||||
continue;
|
||||
@@ -4157,7 +4162,7 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
@@ -4159,7 +4164,7 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
}
|
||||
|
||||
id = be32_to_cpup(_id);
|
||||
@@ -156,7 +156,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
dev_err(eth->dev, "%d is not a valid mac id\n", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -4302,7 +4307,7 @@ void mtk_eth_set_dma_device(struct mtk_e
|
||||
@@ -4304,7 +4309,7 @@ void mtk_eth_set_dma_device(struct mtk_e
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
@@ -165,7 +165,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
dev = eth->netdev[i];
|
||||
|
||||
if (!dev || !(dev->flags & IFF_UP))
|
||||
@@ -4610,7 +4615,7 @@ static int mtk_remove(struct platform_de
|
||||
@@ -4612,7 +4617,7 @@ static int mtk_remove(struct platform_de
|
||||
int i;
|
||||
|
||||
/* stop all devices to make sure that dma is properly shut down */
|
||||
|
@@ -18,7 +18,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -818,17 +818,32 @@ void mtk_stats_update_mac(struct mtk_mac
|
||||
@@ -817,17 +817,32 @@ void mtk_stats_update_mac(struct mtk_mac
|
||||
mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x20 + offs);
|
||||
hw_stats->rx_flow_control_packets +=
|
||||
mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x24 + offs);
|
||||
@@ -62,7 +62,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
}
|
||||
|
||||
u64_stats_update_end(&hw_stats->syncp);
|
||||
@@ -1130,7 +1145,10 @@ static void mtk_tx_set_dma_desc_v2(struc
|
||||
@@ -1129,7 +1144,10 @@ static void mtk_tx_set_dma_desc_v2(struc
|
||||
data |= TX_DMA_LS0;
|
||||
WRITE_ONCE(desc->txd3, data);
|
||||
|
||||
@@ -74,7 +74,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
data |= TX_DMA_SWC_V2 | QID_BITS_V2(info->qid);
|
||||
WRITE_ONCE(desc->txd4, data);
|
||||
|
||||
@@ -1141,6 +1159,8 @@ static void mtk_tx_set_dma_desc_v2(struc
|
||||
@@ -1140,6 +1158,8 @@ static void mtk_tx_set_dma_desc_v2(struc
|
||||
/* tx checksum offload */
|
||||
if (info->csum)
|
||||
data |= TX_DMA_CHKSUM_V2;
|
||||
@@ -83,7 +83,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
}
|
||||
WRITE_ONCE(desc->txd5, data);
|
||||
|
||||
@@ -1206,8 +1226,7 @@ static int mtk_tx_map(struct sk_buff *sk
|
||||
@@ -1205,8 +1225,7 @@ static int mtk_tx_map(struct sk_buff *sk
|
||||
mtk_tx_set_dma_desc(dev, itxd, &txd_info);
|
||||
|
||||
itx_buf->flags |= MTK_TX_FLAGS_SINGLE0;
|
||||
@@ -93,7 +93,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
setup_tx_buf(eth, itx_buf, itxd_pdma, txd_info.addr, txd_info.size,
|
||||
k++);
|
||||
|
||||
@@ -1255,8 +1274,7 @@ static int mtk_tx_map(struct sk_buff *sk
|
||||
@@ -1254,8 +1273,7 @@ static int mtk_tx_map(struct sk_buff *sk
|
||||
memset(tx_buf, 0, sizeof(*tx_buf));
|
||||
tx_buf->data = (void *)MTK_DMA_DUMMY_DESC;
|
||||
tx_buf->flags |= MTK_TX_FLAGS_PAGE0;
|
||||
@@ -103,7 +103,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr,
|
||||
txd_info.size, k++);
|
||||
@@ -1558,7 +1576,7 @@ static int mtk_xdp_frame_map(struct mtk_
|
||||
@@ -1557,7 +1575,7 @@ static int mtk_xdp_frame_map(struct mtk_
|
||||
}
|
||||
mtk_tx_set_dma_desc(dev, txd, txd_info);
|
||||
|
||||
@@ -112,7 +112,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX;
|
||||
tx_buf->data = (void *)MTK_DMA_DUMMY_DESC;
|
||||
|
||||
@@ -1806,11 +1824,24 @@ static int mtk_poll_rx(struct napi_struc
|
||||
@@ -1805,11 +1823,24 @@ static int mtk_poll_rx(struct napi_struc
|
||||
break;
|
||||
|
||||
/* find out which mac the packet come from. values start at 1 */
|
||||
@@ -141,7 +141,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
if (unlikely(mac < 0 || mac >= MTK_MAX_DEVS ||
|
||||
!eth->netdev[mac]))
|
||||
@@ -2030,7 +2061,6 @@ static int mtk_poll_tx_qdma(struct mtk_e
|
||||
@@ -2029,7 +2060,6 @@ static int mtk_poll_tx_qdma(struct mtk_e
|
||||
|
||||
while ((cpu != dma) && budget) {
|
||||
u32 next_cpu = desc->txd2;
|
||||
@@ -149,7 +149,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
desc = mtk_qdma_phys_to_virt(ring, desc->txd2);
|
||||
if ((desc->txd3 & TX_DMA_OWNER_CPU) == 0)
|
||||
@@ -2038,15 +2068,13 @@ static int mtk_poll_tx_qdma(struct mtk_e
|
||||
@@ -2037,15 +2067,13 @@ static int mtk_poll_tx_qdma(struct mtk_e
|
||||
|
||||
tx_buf = mtk_desc_to_tx_buf(ring, desc,
|
||||
eth->soc->txrx.txd_size);
|
||||
@@ -167,7 +167,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
budget--;
|
||||
}
|
||||
@@ -3648,7 +3676,24 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
@@ -3650,7 +3678,24 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask, reg_map->qdma.int_grp + 4);
|
||||
mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
|
||||
|
||||
@@ -193,7 +193,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
/* PSE should not drop port8 and port9 packets from WDMA Tx */
|
||||
mtk_w32(eth, 0x00000300, PSE_DROP_CFG);
|
||||
|
||||
@@ -4210,7 +4255,11 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
@@ -4212,7 +4257,11 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
}
|
||||
spin_lock_init(&mac->hw_stats->stats_lock);
|
||||
u64_stats_init(&mac->hw_stats->syncp);
|
||||
|
@@ -219,7 +219,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
return;
|
||||
|
||||
err_phy:
|
||||
@@ -682,11 +798,15 @@ static int mtk_mdio_init(struct mtk_eth
|
||||
@@ -681,11 +797,15 @@ static int mtk_mdio_init(struct mtk_eth
|
||||
}
|
||||
divider = min_t(unsigned int, DIV_ROUND_UP(MDC_MAX_FREQ, max_clk), 63);
|
||||
|
||||
@@ -239,7 +239,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
dev_dbg(eth->dev, "MDC is running on %d Hz\n", MDC_MAX_FREQ / divider);
|
||||
|
||||
@@ -1145,10 +1265,19 @@ static void mtk_tx_set_dma_desc_v2(struc
|
||||
@@ -1144,10 +1264,19 @@ static void mtk_tx_set_dma_desc_v2(struc
|
||||
data |= TX_DMA_LS0;
|
||||
WRITE_ONCE(desc->txd3, data);
|
||||
|
||||
@@ -263,7 +263,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
data |= TX_DMA_SWC_V2 | QID_BITS_V2(info->qid);
|
||||
WRITE_ONCE(desc->txd4, data);
|
||||
|
||||
@@ -4304,6 +4433,17 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
@@ -4306,6 +4435,17 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
mac->phylink_config.supported_interfaces);
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
phylink = phylink_create(&mac->phylink_config,
|
||||
of_fwnode_handle(mac->of_node),
|
||||
phy_mode, &mtk_phylink_ops);
|
||||
@@ -4826,6 +4966,24 @@ static const struct mtk_soc_data mt7986_
|
||||
@@ -4828,6 +4968,24 @@ static const struct mtk_soc_data mt7986_
|
||||
},
|
||||
};
|
||||
|
||||
@@ -306,7 +306,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
static const struct mtk_soc_data rt5350_data = {
|
||||
.reg_map = &mt7628_reg_map,
|
||||
.caps = MT7628_CAPS,
|
||||
@@ -4844,14 +5002,15 @@ static const struct mtk_soc_data rt5350_
|
||||
@@ -4846,14 +5004,15 @@ static const struct mtk_soc_data rt5350_
|
||||
};
|
||||
|
||||
const struct of_device_id of_mtk_match[] = {
|
||||
|
@@ -16,7 +16,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -1613,7 +1613,7 @@ static void mtk_update_rx_cpu_idx(struct
|
||||
@@ -1612,7 +1612,7 @@ static void mtk_update_rx_cpu_idx(struct
|
||||
|
||||
static bool mtk_page_pool_enabled(struct mtk_eth *eth)
|
||||
{
|
||||
|
@@ -18,7 +18,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -4974,6 +4974,9 @@ static const struct mtk_soc_data mt7988_
|
||||
@@ -4976,6 +4976,9 @@ static const struct mtk_soc_data mt7988_
|
||||
.required_clks = MT7988_CLKS_BITMAP,
|
||||
.required_pctl = false,
|
||||
.version = 3,
|
||||
|
@@ -20,7 +20,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -4976,6 +4976,7 @@ static const struct mtk_soc_data mt7988_
|
||||
@@ -4978,6 +4978,7 @@ static const struct mtk_soc_data mt7988_
|
||||
.version = 3,
|
||||
.offload_version = 2,
|
||||
.hash_offset = 4,
|
||||
|
@@ -16,7 +16,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -3538,19 +3538,34 @@ static void mtk_hw_reset(struct mtk_eth
|
||||
@@ -3540,19 +3540,34 @@ static void mtk_hw_reset(struct mtk_eth
|
||||
{
|
||||
u32 val;
|
||||
|
||||
@@ -56,7 +56,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN,
|
||||
0x3ffffff);
|
||||
}
|
||||
@@ -3576,13 +3591,21 @@ static void mtk_hw_warm_reset(struct mtk
|
||||
@@ -3578,13 +3593,21 @@ static void mtk_hw_warm_reset(struct mtk
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, rst_mask, rst_mask);
|
||||
|
||||
@@ -3934,11 +3957,17 @@ static void mtk_prepare_for_reset(struct
|
||||
@@ -3936,11 +3959,17 @@ static void mtk_prepare_for_reset(struct
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
@@ -106,7 +106,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
/* adjust PPE configurations to prepare for reset */
|
||||
for (i = 0; i < ARRAY_SIZE(eth->ppe); i++)
|
||||
@@ -3999,11 +4028,18 @@ static void mtk_pending_work(struct work
|
||||
@@ -4001,11 +4030,18 @@ static void mtk_pending_work(struct work
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -1075,10 +1075,13 @@ static int mtk_init_fq_dma(struct mtk_et
|
||||
@@ -1074,10 +1074,13 @@ static int mtk_init_fq_dma(struct mtk_et
|
||||
dma_addr_t dma_addr;
|
||||
int i;
|
||||
|
||||
@@ -38,7 +38,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
if (unlikely(!eth->scratch_ring))
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -2376,8 +2379,14 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
@@ -2375,8 +2378,14 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
if (!ring->buf)
|
||||
goto no_tx_mem;
|
||||
|
||||
@@ -55,7 +55,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
if (!ring->dma)
|
||||
goto no_tx_mem;
|
||||
|
||||
@@ -2476,8 +2485,7 @@ static void mtk_tx_clean(struct mtk_eth
|
||||
@@ -2475,8 +2484,7 @@ static void mtk_tx_clean(struct mtk_eth
|
||||
kfree(ring->buf);
|
||||
ring->buf = NULL;
|
||||
}
|
||||
@@ -65,7 +65,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
dma_free_coherent(eth->dma_dev,
|
||||
ring->dma_size * soc->txrx.txd_size,
|
||||
ring->dma, ring->phys);
|
||||
@@ -2496,9 +2504,14 @@ static int mtk_rx_alloc(struct mtk_eth *
|
||||
@@ -2495,9 +2503,14 @@ static int mtk_rx_alloc(struct mtk_eth *
|
||||
{
|
||||
const struct mtk_reg_map *reg_map = eth->soc->reg_map;
|
||||
struct mtk_rx_ring *ring;
|
||||
@@ -81,7 +81,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
if (rx_flag == MTK_RX_FLAGS_QDMA) {
|
||||
if (ring_no)
|
||||
return -EINVAL;
|
||||
@@ -2533,9 +2546,20 @@ static int mtk_rx_alloc(struct mtk_eth *
|
||||
@@ -2532,9 +2545,20 @@ static int mtk_rx_alloc(struct mtk_eth *
|
||||
ring->page_pool = pp;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
if (!ring->dma)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -2618,7 +2642,7 @@ static int mtk_rx_alloc(struct mtk_eth *
|
||||
@@ -2617,7 +2641,7 @@ static int mtk_rx_alloc(struct mtk_eth *
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -2641,7 +2665,7 @@ static void mtk_rx_clean(struct mtk_eth
|
||||
@@ -2640,7 +2664,7 @@ static void mtk_rx_clean(struct mtk_eth
|
||||
ring->data = NULL;
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
dma_free_coherent(eth->dma_dev,
|
||||
ring->dma_size * eth->soc->txrx.rxd_size,
|
||||
ring->dma, ring->phys);
|
||||
@@ -3001,7 +3025,7 @@ static void mtk_dma_free(struct mtk_eth
|
||||
@@ -3003,7 +3027,7 @@ static void mtk_dma_free(struct mtk_eth
|
||||
for (i = 0; i < MTK_MAX_DEVS; i++)
|
||||
if (eth->netdev[i])
|
||||
netdev_reset_queue(eth->netdev[i]);
|
||||
@@ -132,7 +132,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
dma_free_coherent(eth->dma_dev,
|
||||
MTK_QDMA_RING_SIZE * soc->txrx.txd_size,
|
||||
eth->scratch_ring, eth->phy_scratch_ring);
|
||||
@@ -3009,13 +3033,13 @@ static void mtk_dma_free(struct mtk_eth
|
||||
@@ -3011,13 +3035,13 @@ static void mtk_dma_free(struct mtk_eth
|
||||
eth->phy_scratch_ring = 0;
|
||||
}
|
||||
mtk_tx_clean(eth);
|
||||
@@ -149,7 +149,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
}
|
||||
|
||||
kfree(eth->scratch_head);
|
||||
@@ -4585,7 +4609,7 @@ static int mtk_sgmii_init(struct mtk_eth
|
||||
@@ -4587,7 +4611,7 @@ static int mtk_sgmii_init(struct mtk_eth
|
||||
|
||||
static int mtk_probe(struct platform_device *pdev)
|
||||
{
|
||||
@@ -158,7 +158,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
struct device_node *mac_np;
|
||||
struct mtk_eth *eth;
|
||||
int err, i;
|
||||
@@ -4605,6 +4629,20 @@ static int mtk_probe(struct platform_dev
|
||||
@@ -4607,6 +4631,20 @@ static int mtk_probe(struct platform_dev
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
|
||||
eth->ip_align = NET_IP_ALIGN;
|
||||
|
||||
@@ -179,7 +179,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
spin_lock_init(ð->page_lock);
|
||||
spin_lock_init(ð->tx_irq_lock);
|
||||
spin_lock_init(ð->rx_irq_lock);
|
||||
@@ -4668,6 +4706,18 @@ static int mtk_probe(struct platform_dev
|
||||
@@ -4670,6 +4708,18 @@ static int mtk_probe(struct platform_dev
|
||||
err = -EINVAL;
|
||||
goto err_destroy_sgmii;
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -1266,6 +1266,10 @@ static void mtk_tx_set_dma_desc_v2(struc
|
||||
@@ -1265,6 +1265,10 @@ static void mtk_tx_set_dma_desc_v2(struc
|
||||
data = TX_DMA_PLEN0(info->size);
|
||||
if (info->last)
|
||||
data |= TX_DMA_LS0;
|
||||
@@ -30,7 +30,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
WRITE_ONCE(desc->txd3, data);
|
||||
|
||||
/* set forward port */
|
||||
@@ -1933,6 +1937,7 @@ static int mtk_poll_rx(struct napi_struc
|
||||
@@ -1932,6 +1936,7 @@ static int mtk_poll_rx(struct napi_struc
|
||||
bool xdp_flush = false;
|
||||
int idx;
|
||||
struct sk_buff *skb;
|
||||
@@ -38,7 +38,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
u8 *data, *new_data;
|
||||
struct mtk_rx_dma_v2 *rxd, trxd;
|
||||
int done = 0, bytes = 0;
|
||||
@@ -2048,7 +2053,10 @@ static int mtk_poll_rx(struct napi_struc
|
||||
@@ -2047,7 +2052,10 @@ static int mtk_poll_rx(struct napi_struc
|
||||
goto release_desc;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
ring->buf_size, DMA_FROM_DEVICE);
|
||||
|
||||
skb = build_skb(data, ring->frag_size);
|
||||
@@ -2114,6 +2122,9 @@ release_desc:
|
||||
@@ -2113,6 +2121,9 @@ release_desc:
|
||||
else
|
||||
rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size);
|
||||
|
||||
@@ -60,7 +60,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
ring->calc_idx = idx;
|
||||
done++;
|
||||
}
|
||||
@@ -2598,6 +2609,9 @@ static int mtk_rx_alloc(struct mtk_eth *
|
||||
@@ -2597,6 +2608,9 @@ static int mtk_rx_alloc(struct mtk_eth *
|
||||
else
|
||||
rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size);
|
||||
|
||||
@@ -70,7 +70,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
rxd->rxd3 = 0;
|
||||
rxd->rxd4 = 0;
|
||||
if (mtk_is_netsys_v2_or_greater(eth)) {
|
||||
@@ -2644,6 +2658,7 @@ static int mtk_rx_alloc(struct mtk_eth *
|
||||
@@ -2643,6 +2657,7 @@ static int mtk_rx_alloc(struct mtk_eth *
|
||||
|
||||
static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_sram)
|
||||
{
|
||||
@@ -78,7 +78,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
int i;
|
||||
|
||||
if (ring->data && ring->dma) {
|
||||
@@ -2657,7 +2672,10 @@ static void mtk_rx_clean(struct mtk_eth
|
||||
@@ -2656,7 +2671,10 @@ static void mtk_rx_clean(struct mtk_eth
|
||||
if (!rxd->rxd1)
|
||||
continue;
|
||||
|
||||
@@ -90,7 +90,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
ring->buf_size, DMA_FROM_DEVICE);
|
||||
mtk_rx_put_buff(ring, ring->data[i], false);
|
||||
}
|
||||
@@ -4643,6 +4661,14 @@ static int mtk_probe(struct platform_dev
|
||||
@@ -4645,6 +4663,14 @@ static int mtk_probe(struct platform_dev
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,28 @@
|
||||
From c3664d913dc115cab4a5fdb5634df4887048000e Mon Sep 17 00:00:00 2001
|
||||
From: Dan Carpenter <dan.carpenter@oracle.com>
|
||||
Date: Fri, 4 Feb 2022 13:03:36 +0300
|
||||
Subject: [PATCH 1/1] net: dsa: qca8k: check correct variable in
|
||||
qca8k_phy_eth_command()
|
||||
|
||||
This is a copy and paste bug. It was supposed to check "clear_skb"
|
||||
instead of "write_skb".
|
||||
|
||||
Fixes: 2cd548566384 ("net: dsa: qca8k: add support for phy read/write with mgmt Ethernet")
|
||||
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1018,7 +1018,7 @@ qca8k_phy_eth_command(struct qca8k_priv
|
||||
|
||||
clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val,
|
||||
QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val));
|
||||
- if (!write_skb) {
|
||||
+ if (!clear_skb) {
|
||||
ret = -ENOMEM;
|
||||
goto err_clear_skb;
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
From 4f5e483b8c7a644733db941a1ae00173baa7b463 Mon Sep 17 00:00:00 2001
|
||||
From: kernel test robot <lkp@intel.com>
|
||||
Date: Thu, 10 Feb 2022 06:13:04 +0800
|
||||
Subject: [PATCH 1/1] net: dsa: qca8k: fix noderef.cocci warnings
|
||||
|
||||
drivers/net/dsa/qca8k.c:422:37-43: ERROR: application of sizeof to pointer
|
||||
|
||||
sizeof when applied to a pointer typed expression gives the size of
|
||||
the pointer
|
||||
|
||||
Generated by: scripts/coccinelle/misc/noderef.cocci
|
||||
|
||||
Fixes: 90386223f44e ("net: dsa: qca8k: add support for larger read/write size with mgmt Ethernet")
|
||||
CC: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reported-by: kernel test robot <lkp@intel.com>
|
||||
Signed-off-by: kernel test robot <lkp@intel.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Link: https://lore.kernel.org/r/20220209221304.GA17529@d2214a582157
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -456,7 +456,7 @@ qca8k_regmap_read(void *ctx, uint32_t re
|
||||
u16 r1, r2, page;
|
||||
int ret;
|
||||
|
||||
- if (!qca8k_read_eth(priv, reg, val, sizeof(val)))
|
||||
+ if (!qca8k_read_eth(priv, reg, val, sizeof(*val)))
|
||||
return 0;
|
||||
|
||||
qca8k_split_addr(reg, &r1, &r2, &page);
|
@@ -0,0 +1,79 @@
|
||||
From 69fd055957a02309ffdc23d887a01988b6e5bab1 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Sat, 16 Apr 2022 01:30:12 +0200
|
||||
Subject: [PATCH 1/6] net: dsa: qca8k: drop MTU tracking from qca8k_priv
|
||||
|
||||
DSA set the CPU port based on the largest MTU of all the slave ports.
|
||||
Based on this we can drop the MTU array from qca8k_priv and set the
|
||||
port_change_mtu logic on DSA changing MTU of the CPU port as the switch
|
||||
have a global MTU settingfor each port.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 26 +++++++++-----------------
|
||||
drivers/net/dsa/qca8k.h | 1 -
|
||||
2 files changed, 9 insertions(+), 18 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1803,16 +1803,6 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
QCA8K_PORT_HOL_CTRL1_WRED_EN,
|
||||
mask);
|
||||
}
|
||||
-
|
||||
- /* Set initial MTU for every port.
|
||||
- * We have only have a general MTU setting. So track
|
||||
- * every port and set the max across all port.
|
||||
- * Set per port MTU to 1500 as the MTU change function
|
||||
- * will add the overhead and if its set to 1518 then it
|
||||
- * will apply the overhead again and we will end up with
|
||||
- * MTU of 1536 instead of 1518
|
||||
- */
|
||||
- priv->port_mtu[i] = ETH_DATA_LEN;
|
||||
}
|
||||
|
||||
/* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */
|
||||
@@ -2525,13 +2515,16 @@ static int
|
||||
qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
|
||||
{
|
||||
struct qca8k_priv *priv = ds->priv;
|
||||
- int ret, i, mtu = 0;
|
||||
-
|
||||
- priv->port_mtu[port] = new_mtu;
|
||||
+ int ret;
|
||||
|
||||
- for (i = 0; i < QCA8K_NUM_PORTS; i++)
|
||||
- if (priv->port_mtu[i] > mtu)
|
||||
- mtu = priv->port_mtu[i];
|
||||
+ /* We have only have a general MTU setting.
|
||||
+ * DSA always set the CPU port's MTU to the largest MTU of the slave
|
||||
+ * ports.
|
||||
+ * Setting MTU just for the CPU port is sufficient to correctly set a
|
||||
+ * value for every port.
|
||||
+ */
|
||||
+ if (!dsa_is_cpu_port(ds, port))
|
||||
+ return 0;
|
||||
|
||||
/* To change the MAX_FRAME_SIZE the cpu ports must be off or
|
||||
* the switch panics.
|
||||
@@ -2545,7 +2538,7 @@ qca8k_port_change_mtu(struct dsa_switch
|
||||
qca8k_port_set_status(priv, 6, 0);
|
||||
|
||||
/* Include L2 header / FCS length */
|
||||
- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, mtu + ETH_HLEN + ETH_FCS_LEN);
|
||||
+ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN);
|
||||
|
||||
if (priv->port_sts[0].enabled)
|
||||
qca8k_port_set_status(priv, 0, 1);
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -392,7 +392,6 @@ struct qca8k_priv {
|
||||
struct device *dev;
|
||||
struct dsa_switch_ops ops;
|
||||
struct gpio_desc *reset_gpio;
|
||||
- unsigned int port_mtu[QCA8K_NUM_PORTS];
|
||||
struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */
|
||||
struct qca8k_mgmt_eth_data mgmt_eth_data;
|
||||
struct qca8k_mib_eth_data mib_eth_data;
|
@@ -0,0 +1,116 @@
|
||||
From 2b8fd87af7f156942971789abac8ee2bb60c03bc Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Sat, 16 Apr 2022 01:30:13 +0200
|
||||
Subject: [PATCH 2/6] net: dsa: qca8k: drop port_sts from qca8k_priv
|
||||
|
||||
Port_sts is a thing of the past for this driver. It was something
|
||||
present on the initial implementation of this driver and parts of the
|
||||
original struct were dropped over time. Using an array of int to store if
|
||||
a port is enabled or not to handle PM operation seems overkill. Switch
|
||||
and use a simple u8 to store the port status where each bit correspond
|
||||
to a port. (bit is set port is enabled, bit is not set, port is disabled)
|
||||
Also add some comments to better describe why we need to track port
|
||||
status.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 15 +++++++++------
|
||||
drivers/net/dsa/qca8k.h | 9 ++++-----
|
||||
2 files changed, 13 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -2494,7 +2494,7 @@ qca8k_port_enable(struct dsa_switch *ds,
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
|
||||
qca8k_port_set_status(priv, port, 1);
|
||||
- priv->port_sts[port].enabled = 1;
|
||||
+ priv->port_enabled_map |= BIT(port);
|
||||
|
||||
if (dsa_is_user_port(ds, port))
|
||||
phy_support_asym_pause(phy);
|
||||
@@ -2508,7 +2508,7 @@ qca8k_port_disable(struct dsa_switch *ds
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
|
||||
qca8k_port_set_status(priv, port, 0);
|
||||
- priv->port_sts[port].enabled = 0;
|
||||
+ priv->port_enabled_map &= ~BIT(port);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -2531,19 +2531,19 @@ qca8k_port_change_mtu(struct dsa_switch
|
||||
* Turn off both cpu ports before applying the new value to prevent
|
||||
* this.
|
||||
*/
|
||||
- if (priv->port_sts[0].enabled)
|
||||
+ if (priv->port_enabled_map & BIT(0))
|
||||
qca8k_port_set_status(priv, 0, 0);
|
||||
|
||||
- if (priv->port_sts[6].enabled)
|
||||
+ if (priv->port_enabled_map & BIT(6))
|
||||
qca8k_port_set_status(priv, 6, 0);
|
||||
|
||||
/* Include L2 header / FCS length */
|
||||
ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN);
|
||||
|
||||
- if (priv->port_sts[0].enabled)
|
||||
+ if (priv->port_enabled_map & BIT(0))
|
||||
qca8k_port_set_status(priv, 0, 1);
|
||||
|
||||
- if (priv->port_sts[6].enabled)
|
||||
+ if (priv->port_enabled_map & BIT(6))
|
||||
qca8k_port_set_status(priv, 6, 1);
|
||||
|
||||
return ret;
|
||||
@@ -3199,13 +3199,16 @@ static void qca8k_sw_shutdown(struct mdi
|
||||
static void
|
||||
qca8k_set_pm(struct qca8k_priv *priv, int enable)
|
||||
{
|
||||
- int i;
|
||||
+ int port;
|
||||
|
||||
- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
- if (!priv->port_sts[i].enabled)
|
||||
+ for (port = 0; port < QCA8K_NUM_PORTS; port++) {
|
||||
+ /* Do not enable on resume if the port was
|
||||
+ * disabled before.
|
||||
+ */
|
||||
+ if (!(priv->port_enabled_map & BIT(port)))
|
||||
continue;
|
||||
|
||||
- qca8k_port_set_status(priv, i, enable);
|
||||
+ qca8k_port_set_status(priv, port, enable);
|
||||
}
|
||||
}
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -324,10 +324,6 @@ enum qca8k_mid_cmd {
|
||||
QCA8K_MIB_CAST = 3,
|
||||
};
|
||||
|
||||
-struct ar8xxx_port_status {
|
||||
- int enabled;
|
||||
-};
|
||||
-
|
||||
struct qca8k_match_data {
|
||||
u8 id;
|
||||
bool reduced_package;
|
||||
@@ -382,11 +378,14 @@ struct qca8k_priv {
|
||||
u8 mirror_rx;
|
||||
u8 mirror_tx;
|
||||
u8 lag_hash_mode;
|
||||
+ /* Each bit correspond to a port. This switch can support a max of 7 port.
|
||||
+ * Bit 1: port enabled. Bit 0: port disabled.
|
||||
+ */
|
||||
+ u8 port_enabled_map;
|
||||
bool legacy_phy_port_mapping;
|
||||
struct qca8k_ports_config ports_config;
|
||||
struct regmap *regmap;
|
||||
struct mii_bus *bus;
|
||||
- struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS];
|
||||
struct dsa_switch *ds;
|
||||
struct mutex reg_mutex;
|
||||
struct device *dev;
|
@@ -0,0 +1,173 @@
|
||||
From 8255212e4130bd2dc1463286a3dddb74797bbdc1 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Sat, 16 Apr 2022 01:30:14 +0200
|
||||
Subject: [PATCH 3/6] net: dsa: qca8k: rework and simplify mdiobus logic
|
||||
|
||||
In an attempt to reduce qca8k_priv space, rework and simplify mdiobus
|
||||
logic.
|
||||
We now declare a mdiobus instead of relying on DSA phy_read/write even
|
||||
if a mdio node is not present. This is all to make the qca8k ops static
|
||||
and not switch specific. With a legacy implementation where port doesn't
|
||||
have a phy map declared in the dts with a mdio node, we declare a
|
||||
'qca8k-legacy' mdiobus. The conversion logic is used as legacy read and
|
||||
write ops are used instead of the internal one.
|
||||
Also drop the legacy_phy_port_mapping as we now declare mdiobus with ops
|
||||
that already address the workaround.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 95 +++++++++++++----------------------------
|
||||
drivers/net/dsa/qca8k.h | 1 -
|
||||
2 files changed, 29 insertions(+), 67 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1291,83 +1291,63 @@ qca8k_internal_mdio_read(struct mii_bus
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_phy_write(struct dsa_switch *ds, int port, int regnum, u16 data)
|
||||
+qca8k_legacy_mdio_write(struct mii_bus *slave_bus, int port, int regnum, u16 data)
|
||||
{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
- int ret;
|
||||
+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
|
||||
|
||||
- /* Check if the legacy mapping should be used and the
|
||||
- * port is not correctly mapped to the right PHY in the
|
||||
- * devicetree
|
||||
- */
|
||||
- if (priv->legacy_phy_port_mapping)
|
||||
- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
|
||||
-
|
||||
- /* Use mdio Ethernet when available, fallback to legacy one on error */
|
||||
- ret = qca8k_phy_eth_command(priv, false, port, regnum, 0);
|
||||
- if (!ret)
|
||||
- return ret;
|
||||
-
|
||||
- return qca8k_mdio_write(priv, port, regnum, data);
|
||||
+ return qca8k_internal_mdio_write(slave_bus, port, regnum, data);
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_phy_read(struct dsa_switch *ds, int port, int regnum)
|
||||
+qca8k_legacy_mdio_read(struct mii_bus *slave_bus, int port, int regnum)
|
||||
{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
- int ret;
|
||||
-
|
||||
- /* Check if the legacy mapping should be used and the
|
||||
- * port is not correctly mapped to the right PHY in the
|
||||
- * devicetree
|
||||
- */
|
||||
- if (priv->legacy_phy_port_mapping)
|
||||
- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
|
||||
-
|
||||
- /* Use mdio Ethernet when available, fallback to legacy one on error */
|
||||
- ret = qca8k_phy_eth_command(priv, true, port, regnum, 0);
|
||||
- if (ret >= 0)
|
||||
- return ret;
|
||||
-
|
||||
- ret = qca8k_mdio_read(priv, port, regnum);
|
||||
-
|
||||
- if (ret < 0)
|
||||
- return 0xffff;
|
||||
+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
|
||||
|
||||
- return ret;
|
||||
+ return qca8k_internal_mdio_read(slave_bus, port, regnum);
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_mdio_register(struct qca8k_priv *priv, struct device_node *mdio)
|
||||
+qca8k_mdio_register(struct qca8k_priv *priv)
|
||||
{
|
||||
struct dsa_switch *ds = priv->ds;
|
||||
+ struct device_node *mdio;
|
||||
struct mii_bus *bus;
|
||||
|
||||
bus = devm_mdiobus_alloc(ds->dev);
|
||||
-
|
||||
if (!bus)
|
||||
return -ENOMEM;
|
||||
|
||||
bus->priv = (void *)priv;
|
||||
- bus->name = "qca8k slave mii";
|
||||
- bus->read = qca8k_internal_mdio_read;
|
||||
- bus->write = qca8k_internal_mdio_write;
|
||||
- snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d",
|
||||
- ds->index);
|
||||
-
|
||||
bus->parent = ds->dev;
|
||||
bus->phy_mask = ~ds->phys_mii_mask;
|
||||
-
|
||||
ds->slave_mii_bus = bus;
|
||||
|
||||
- return devm_of_mdiobus_register(priv->dev, bus, mdio);
|
||||
+ /* Check if the devicetree declare the port:phy mapping */
|
||||
+ mdio = of_get_child_by_name(priv->dev->of_node, "mdio");
|
||||
+ if (of_device_is_available(mdio)) {
|
||||
+ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d", ds->index);
|
||||
+ bus->name = "qca8k slave mii";
|
||||
+ bus->read = qca8k_internal_mdio_read;
|
||||
+ bus->write = qca8k_internal_mdio_write;
|
||||
+ return devm_of_mdiobus_register(priv->dev, bus, mdio);
|
||||
+ }
|
||||
+
|
||||
+ /* If a mapping can't be found the legacy mapping is used,
|
||||
+ * using the qca8k_port_to_phy function
|
||||
+ */
|
||||
+ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d",
|
||||
+ ds->dst->index, ds->index);
|
||||
+ bus->name = "qca8k-legacy slave mii";
|
||||
+ bus->read = qca8k_legacy_mdio_read;
|
||||
+ bus->write = qca8k_legacy_mdio_write;
|
||||
+ return devm_mdiobus_register(priv->dev, bus);
|
||||
}
|
||||
|
||||
static int
|
||||
qca8k_setup_mdio_bus(struct qca8k_priv *priv)
|
||||
{
|
||||
u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg;
|
||||
- struct device_node *ports, *port, *mdio;
|
||||
+ struct device_node *ports, *port;
|
||||
phy_interface_t mode;
|
||||
int err;
|
||||
|
||||
@@ -1429,24 +1409,7 @@ qca8k_setup_mdio_bus(struct qca8k_priv *
|
||||
QCA8K_MDIO_MASTER_EN);
|
||||
}
|
||||
|
||||
- /* Check if the devicetree declare the port:phy mapping */
|
||||
- mdio = of_get_child_by_name(priv->dev->of_node, "mdio");
|
||||
- if (of_device_is_available(mdio)) {
|
||||
- err = qca8k_mdio_register(priv, mdio);
|
||||
- if (err)
|
||||
- of_node_put(mdio);
|
||||
-
|
||||
- return err;
|
||||
- }
|
||||
-
|
||||
- /* If a mapping can't be found the legacy mapping is used,
|
||||
- * using the qca8k_port_to_phy function
|
||||
- */
|
||||
- priv->legacy_phy_port_mapping = true;
|
||||
- priv->ops.phy_read = qca8k_phy_read;
|
||||
- priv->ops.phy_write = qca8k_phy_write;
|
||||
-
|
||||
- return 0;
|
||||
+ return qca8k_mdio_register(priv);
|
||||
}
|
||||
|
||||
static int
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -382,7 +382,6 @@ struct qca8k_priv {
|
||||
* Bit 1: port enabled. Bit 0: port disabled.
|
||||
*/
|
||||
u8 port_enabled_map;
|
||||
- bool legacy_phy_port_mapping;
|
||||
struct qca8k_ports_config ports_config;
|
||||
struct regmap *regmap;
|
||||
struct mii_bus *bus;
|
@@ -0,0 +1,39 @@
|
||||
From 2349b83a2486c55b9dd225326f0172a84a43c5e4 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Sat, 16 Apr 2022 01:30:15 +0200
|
||||
Subject: [PATCH 4/6] net: dsa: qca8k: drop dsa_switch_ops from qca8k_priv
|
||||
|
||||
Now that dsa_switch_ops is not switch specific anymore, we can drop it
|
||||
from qca8k_priv and use the static ops directly for the dsa_switch
|
||||
pointer.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 3 +--
|
||||
drivers/net/dsa/qca8k.h | 1 -
|
||||
2 files changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -3121,8 +3121,7 @@ qca8k_sw_probe(struct mdio_device *mdiod
|
||||
priv->ds->dev = &mdiodev->dev;
|
||||
priv->ds->num_ports = QCA8K_NUM_PORTS;
|
||||
priv->ds->priv = priv;
|
||||
- priv->ops = qca8k_switch_ops;
|
||||
- priv->ds->ops = &priv->ops;
|
||||
+ priv->ds->ops = &qca8k_switch_ops;
|
||||
mutex_init(&priv->reg_mutex);
|
||||
dev_set_drvdata(&mdiodev->dev, priv);
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -388,7 +388,6 @@ struct qca8k_priv {
|
||||
struct dsa_switch *ds;
|
||||
struct mutex reg_mutex;
|
||||
struct device *dev;
|
||||
- struct dsa_switch_ops ops;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */
|
||||
struct qca8k_mgmt_eth_data mgmt_eth_data;
|
@@ -0,0 +1,33 @@
|
||||
From 6cfc03b602200c5cbbd8d906fd905547814e83df Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Sat, 16 Apr 2022 01:30:16 +0200
|
||||
Subject: [PATCH 5/6] net: dsa: qca8k: correctly handle mdio read error
|
||||
|
||||
Restore original way to handle mdio read error by returning 0xffff.
|
||||
This was wrongly changed when the internal_mdio_read was introduced,
|
||||
now that both legacy and internal use the same function, make sure that
|
||||
they behave the same way.
|
||||
|
||||
Fixes: ce062a0adbfe ("net: dsa: qca8k: fix kernel panic with legacy mdio mapping")
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1287,7 +1287,12 @@ qca8k_internal_mdio_read(struct mii_bus
|
||||
if (ret >= 0)
|
||||
return ret;
|
||||
|
||||
- return qca8k_mdio_read(priv, phy, regnum);
|
||||
+ ret = qca8k_mdio_read(priv, phy, regnum);
|
||||
+
|
||||
+ if (ret < 0)
|
||||
+ return 0xffff;
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static int
|
@@ -0,0 +1,44 @@
|
||||
From 8d1af50842bf2774f4edc57054206e909117469b Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Sat, 16 Apr 2022 01:30:17 +0200
|
||||
Subject: [PATCH 6/6] net: dsa: qca8k: unify bus id naming with legacy and OF
|
||||
mdio bus
|
||||
|
||||
Add support for multiple switch with OF mdio bus declaration.
|
||||
Unify the bus id naming and use the same logic for both legacy and OF
|
||||
mdio bus.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 5 ++---
|
||||
1 file changed, 2 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1323,6 +1323,8 @@ qca8k_mdio_register(struct qca8k_priv *p
|
||||
return -ENOMEM;
|
||||
|
||||
bus->priv = (void *)priv;
|
||||
+ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d",
|
||||
+ ds->dst->index, ds->index);
|
||||
bus->parent = ds->dev;
|
||||
bus->phy_mask = ~ds->phys_mii_mask;
|
||||
ds->slave_mii_bus = bus;
|
||||
@@ -1330,7 +1332,6 @@ qca8k_mdio_register(struct qca8k_priv *p
|
||||
/* Check if the devicetree declare the port:phy mapping */
|
||||
mdio = of_get_child_by_name(priv->dev->of_node, "mdio");
|
||||
if (of_device_is_available(mdio)) {
|
||||
- snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d", ds->index);
|
||||
bus->name = "qca8k slave mii";
|
||||
bus->read = qca8k_internal_mdio_read;
|
||||
bus->write = qca8k_internal_mdio_write;
|
||||
@@ -1340,8 +1341,6 @@ qca8k_mdio_register(struct qca8k_priv *p
|
||||
/* If a mapping can't be found the legacy mapping is used,
|
||||
* using the qca8k_port_to_phy function
|
||||
*/
|
||||
- snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d",
|
||||
- ds->dst->index, ds->index);
|
||||
bus->name = "qca8k-legacy slave mii";
|
||||
bus->read = qca8k_legacy_mdio_read;
|
||||
bus->write = qca8k_legacy_mdio_write;
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,157 @@
|
||||
From 3bb0844e7bcd0fb0bcfab6202b5edd349ef5250a Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 27 Jul 2022 13:35:10 +0200
|
||||
Subject: [PATCH 01/14] net: dsa: qca8k: cache match data to speed up access
|
||||
|
||||
Using of_device_get_match_data is expensive. Cache match data to speed
|
||||
up access and rework user of match data to use the new cached value.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k.c | 35 +++++++++++------------------------
|
||||
drivers/net/dsa/qca/qca8k.h | 1 +
|
||||
2 files changed, 12 insertions(+), 24 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k.c
|
||||
@@ -1462,8 +1462,8 @@ static int qca8k_find_cpu_port(struct ds
|
||||
static int
|
||||
qca8k_setup_of_pws_reg(struct qca8k_priv *priv)
|
||||
{
|
||||
+ const struct qca8k_match_data *data = priv->info;
|
||||
struct device_node *node = priv->dev->of_node;
|
||||
- const struct qca8k_match_data *data;
|
||||
u32 val = 0;
|
||||
int ret;
|
||||
|
||||
@@ -1472,8 +1472,6 @@ qca8k_setup_of_pws_reg(struct qca8k_priv
|
||||
* Should be applied by default but we set this just to make sure.
|
||||
*/
|
||||
if (priv->switch_id == QCA8K_ID_QCA8327) {
|
||||
- data = of_device_get_match_data(priv->dev);
|
||||
-
|
||||
/* Set the correct package of 148 pin for QCA8327 */
|
||||
if (data->reduced_package)
|
||||
val |= QCA8327_PWS_PACKAGE148_EN;
|
||||
@@ -2146,23 +2144,19 @@ qca8k_phylink_mac_link_up(struct dsa_swi
|
||||
static void
|
||||
qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data)
|
||||
{
|
||||
- const struct qca8k_match_data *match_data;
|
||||
struct qca8k_priv *priv = ds->priv;
|
||||
int i;
|
||||
|
||||
if (stringset != ETH_SS_STATS)
|
||||
return;
|
||||
|
||||
- match_data = of_device_get_match_data(priv->dev);
|
||||
-
|
||||
- for (i = 0; i < match_data->mib_count; i++)
|
||||
+ for (i = 0; i < priv->info->mib_count; i++)
|
||||
strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name,
|
||||
ETH_GSTRING_LEN);
|
||||
}
|
||||
|
||||
static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb)
|
||||
{
|
||||
- const struct qca8k_match_data *match_data;
|
||||
struct qca8k_mib_eth_data *mib_eth_data;
|
||||
struct qca8k_priv *priv = ds->priv;
|
||||
const struct qca8k_mib_desc *mib;
|
||||
@@ -2181,10 +2175,9 @@ static void qca8k_mib_autocast_handler(s
|
||||
if (port != mib_eth_data->req_port)
|
||||
goto exit;
|
||||
|
||||
- match_data = device_get_match_data(priv->dev);
|
||||
data = mib_eth_data->data;
|
||||
|
||||
- for (i = 0; i < match_data->mib_count; i++) {
|
||||
+ for (i = 0; i < priv->info->mib_count; i++) {
|
||||
mib = &ar8327_mib[i];
|
||||
|
||||
/* First 3 mib are present in the skb head */
|
||||
@@ -2256,7 +2249,6 @@ qca8k_get_ethtool_stats(struct dsa_switc
|
||||
uint64_t *data)
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
- const struct qca8k_match_data *match_data;
|
||||
const struct qca8k_mib_desc *mib;
|
||||
u32 reg, i, val;
|
||||
u32 hi = 0;
|
||||
@@ -2266,9 +2258,7 @@ qca8k_get_ethtool_stats(struct dsa_switc
|
||||
qca8k_get_ethtool_stats_eth(ds, port, data) > 0)
|
||||
return;
|
||||
|
||||
- match_data = of_device_get_match_data(priv->dev);
|
||||
-
|
||||
- for (i = 0; i < match_data->mib_count; i++) {
|
||||
+ for (i = 0; i < priv->info->mib_count; i++) {
|
||||
mib = &ar8327_mib[i];
|
||||
reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset;
|
||||
|
||||
@@ -2291,15 +2281,12 @@ qca8k_get_ethtool_stats(struct dsa_switc
|
||||
static int
|
||||
qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset)
|
||||
{
|
||||
- const struct qca8k_match_data *match_data;
|
||||
struct qca8k_priv *priv = ds->priv;
|
||||
|
||||
if (sset != ETH_SS_STATS)
|
||||
return 0;
|
||||
|
||||
- match_data = of_device_get_match_data(priv->dev);
|
||||
-
|
||||
- return match_data->mib_count;
|
||||
+ return priv->info->mib_count;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -3037,14 +3024,11 @@ static const struct dsa_switch_ops qca8k
|
||||
|
||||
static int qca8k_read_switch_id(struct qca8k_priv *priv)
|
||||
{
|
||||
- const struct qca8k_match_data *data;
|
||||
u32 val;
|
||||
u8 id;
|
||||
int ret;
|
||||
|
||||
- /* get the switches ID from the compatible */
|
||||
- data = of_device_get_match_data(priv->dev);
|
||||
- if (!data)
|
||||
+ if (!priv->info)
|
||||
return -ENODEV;
|
||||
|
||||
ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val);
|
||||
@@ -3052,8 +3036,10 @@ static int qca8k_read_switch_id(struct q
|
||||
return -ENODEV;
|
||||
|
||||
id = QCA8K_MASK_CTRL_DEVICE_ID(val);
|
||||
- if (id != data->id) {
|
||||
- dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id);
|
||||
+ if (id != priv->info->id) {
|
||||
+ dev_err(priv->dev,
|
||||
+ "Switch id detected %x but expected %x",
|
||||
+ id, priv->info->id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -3078,6 +3064,7 @@ qca8k_sw_probe(struct mdio_device *mdiod
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
+ priv->info = of_device_get_match_data(priv->dev);
|
||||
priv->bus = mdiodev->bus;
|
||||
priv->dev = &mdiodev->dev;
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -393,6 +393,7 @@ struct qca8k_priv {
|
||||
struct qca8k_mgmt_eth_data mgmt_eth_data;
|
||||
struct qca8k_mib_eth_data mib_eth_data;
|
||||
struct qca8k_mdio_cache mdio_cache;
|
||||
+ const struct qca8k_match_data *info;
|
||||
};
|
||||
|
||||
struct qca8k_mib_desc {
|
@@ -0,0 +1,77 @@
|
||||
From 533c64bca62a8654f00698bc893f639013e38c7b Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 27 Jul 2022 13:35:11 +0200
|
||||
Subject: [PATCH 02/14] net: dsa: qca8k: make mib autocast feature optional
|
||||
|
||||
Some switch may not support mib autocast feature and require the legacy
|
||||
way of reading the regs directly.
|
||||
Make the mib autocast feature optional and permit to declare support for
|
||||
it using match_data struct in a dedicated qca8k_info_ops struct.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k.c | 11 +++++++++--
|
||||
drivers/net/dsa/qca/qca8k.h | 5 +++++
|
||||
2 files changed, 14 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k.c
|
||||
@@ -2254,8 +2254,8 @@ qca8k_get_ethtool_stats(struct dsa_switc
|
||||
u32 hi = 0;
|
||||
int ret;
|
||||
|
||||
- if (priv->mgmt_master &&
|
||||
- qca8k_get_ethtool_stats_eth(ds, port, data) > 0)
|
||||
+ if (priv->mgmt_master && priv->info->ops->autocast_mib &&
|
||||
+ priv->info->ops->autocast_mib(ds, port, data) > 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < priv->info->mib_count; i++) {
|
||||
@@ -3187,20 +3187,27 @@ static int qca8k_resume(struct device *d
|
||||
static SIMPLE_DEV_PM_OPS(qca8k_pm_ops,
|
||||
qca8k_suspend, qca8k_resume);
|
||||
|
||||
+static const struct qca8k_info_ops qca8xxx_ops = {
|
||||
+ .autocast_mib = qca8k_get_ethtool_stats_eth,
|
||||
+};
|
||||
+
|
||||
static const struct qca8k_match_data qca8327 = {
|
||||
.id = QCA8K_ID_QCA8327,
|
||||
.reduced_package = true,
|
||||
.mib_count = QCA8K_QCA832X_MIB_COUNT,
|
||||
+ .ops = &qca8xxx_ops,
|
||||
};
|
||||
|
||||
static const struct qca8k_match_data qca8328 = {
|
||||
.id = QCA8K_ID_QCA8327,
|
||||
.mib_count = QCA8K_QCA832X_MIB_COUNT,
|
||||
+ .ops = &qca8xxx_ops,
|
||||
};
|
||||
|
||||
static const struct qca8k_match_data qca833x = {
|
||||
.id = QCA8K_ID_QCA8337,
|
||||
.mib_count = QCA8K_QCA833X_MIB_COUNT,
|
||||
+ .ops = &qca8xxx_ops,
|
||||
};
|
||||
|
||||
static const struct of_device_id qca8k_of_match[] = {
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -324,10 +324,15 @@ enum qca8k_mid_cmd {
|
||||
QCA8K_MIB_CAST = 3,
|
||||
};
|
||||
|
||||
+struct qca8k_info_ops {
|
||||
+ int (*autocast_mib)(struct dsa_switch *ds, int port, u64 *data);
|
||||
+};
|
||||
+
|
||||
struct qca8k_match_data {
|
||||
u8 id;
|
||||
bool reduced_package;
|
||||
u8 mib_count;
|
||||
+ const struct qca8k_info_ops *ops;
|
||||
};
|
||||
|
||||
enum {
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,135 @@
|
||||
From d5f901eab2e9dfed1095995dfc98f231f4fd2971 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 27 Jul 2022 13:35:13 +0200
|
||||
Subject: [PATCH 04/14] net: dsa: qca8k: move qca8k read/write/rmw and reg
|
||||
table to common code
|
||||
|
||||
The same reg table and read/write/rmw function are used by drivers
|
||||
based on qca8k family switch.
|
||||
Move them to common code to make it accessible also by other drivers.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 42 ------------------------------
|
||||
drivers/net/dsa/qca/qca8k-common.c | 38 +++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca/qca8k.h | 6 +++++
|
||||
3 files changed, 44 insertions(+), 42 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -133,24 +133,6 @@ qca8k_set_page(struct qca8k_priv *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int
|
||||
-qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val)
|
||||
-{
|
||||
- return regmap_read(priv->regmap, reg, val);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val)
|
||||
-{
|
||||
- return regmap_write(priv->regmap, reg, val);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val)
|
||||
-{
|
||||
- return regmap_update_bits(priv->regmap, reg, mask, write_val);
|
||||
-}
|
||||
-
|
||||
static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb)
|
||||
{
|
||||
struct qca8k_mgmt_eth_data *mgmt_eth_data;
|
||||
@@ -483,30 +465,6 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static const struct regmap_range qca8k_readable_ranges[] = {
|
||||
- regmap_reg_range(0x0000, 0x00e4), /* Global control */
|
||||
- regmap_reg_range(0x0100, 0x0168), /* EEE control */
|
||||
- regmap_reg_range(0x0200, 0x0270), /* Parser control */
|
||||
- regmap_reg_range(0x0400, 0x0454), /* ACL */
|
||||
- regmap_reg_range(0x0600, 0x0718), /* Lookup */
|
||||
- regmap_reg_range(0x0800, 0x0b70), /* QM */
|
||||
- regmap_reg_range(0x0c00, 0x0c80), /* PKT */
|
||||
- regmap_reg_range(0x0e00, 0x0e98), /* L3 */
|
||||
- regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */
|
||||
- regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */
|
||||
- regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */
|
||||
- regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */
|
||||
- regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */
|
||||
- regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */
|
||||
- regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */
|
||||
-
|
||||
-};
|
||||
-
|
||||
-static const struct regmap_access_table qca8k_readable_table = {
|
||||
- .yes_ranges = qca8k_readable_ranges,
|
||||
- .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges),
|
||||
-};
|
||||
-
|
||||
static struct regmap_config qca8k_regmap_config = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 32,
|
||||
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||||
@@ -61,3 +61,41 @@ const struct qca8k_mib_desc ar8327_mib[]
|
||||
MIB_DESC(1, 0xa8, "RXUnicast"),
|
||||
MIB_DESC(1, 0xac, "TXUnicast"),
|
||||
};
|
||||
+
|
||||
+int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val)
|
||||
+{
|
||||
+ return regmap_read(priv->regmap, reg, val);
|
||||
+}
|
||||
+
|
||||
+int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val)
|
||||
+{
|
||||
+ return regmap_write(priv->regmap, reg, val);
|
||||
+}
|
||||
+
|
||||
+int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val)
|
||||
+{
|
||||
+ return regmap_update_bits(priv->regmap, reg, mask, write_val);
|
||||
+}
|
||||
+
|
||||
+static const struct regmap_range qca8k_readable_ranges[] = {
|
||||
+ regmap_reg_range(0x0000, 0x00e4), /* Global control */
|
||||
+ regmap_reg_range(0x0100, 0x0168), /* EEE control */
|
||||
+ regmap_reg_range(0x0200, 0x0270), /* Parser control */
|
||||
+ regmap_reg_range(0x0400, 0x0454), /* ACL */
|
||||
+ regmap_reg_range(0x0600, 0x0718), /* Lookup */
|
||||
+ regmap_reg_range(0x0800, 0x0b70), /* QM */
|
||||
+ regmap_reg_range(0x0c00, 0x0c80), /* PKT */
|
||||
+ regmap_reg_range(0x0e00, 0x0e98), /* L3 */
|
||||
+ regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */
|
||||
+ regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */
|
||||
+ regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */
|
||||
+ regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */
|
||||
+ regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */
|
||||
+ regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */
|
||||
+ regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */
|
||||
+};
|
||||
+
|
||||
+const struct regmap_access_table qca8k_readable_table = {
|
||||
+ .yes_ranges = qca8k_readable_ranges,
|
||||
+ .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges),
|
||||
+};
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -416,5 +416,11 @@ struct qca8k_fdb {
|
||||
|
||||
/* Common setup function */
|
||||
extern const struct qca8k_mib_desc ar8327_mib[];
|
||||
+extern const struct regmap_access_table qca8k_readable_table;
|
||||
+
|
||||
+/* Common read/write/rmw function */
|
||||
+int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val);
|
||||
+int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val);
|
||||
+int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val);
|
||||
|
||||
#endif /* __QCA8K_H */
|
@@ -0,0 +1,145 @@
|
||||
From 910746444313dc463396cd63024cdf54ef04ef39 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 27 Jul 2022 13:35:14 +0200
|
||||
Subject: [PATCH 05/14] net: dsa: qca8k: move qca8k bulk read/write helper to
|
||||
common code
|
||||
|
||||
The same ATU function are used by drivers based on qca8k family switch.
|
||||
Move the bulk read/write helper to common code to declare these shared
|
||||
ATU functions in common code.
|
||||
These helper will be dropped when regmap correctly support bulk
|
||||
read/write.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 39 ++----------------------------
|
||||
drivers/net/dsa/qca/qca8k-common.c | 39 ++++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca/qca8k.h | 8 ++++++
|
||||
3 files changed, 49 insertions(+), 37 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -343,43 +343,6 @@ qca8k_regmap_update_bits_eth(struct qca8
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
|
||||
-{
|
||||
- int i, count = len / sizeof(u32), ret;
|
||||
-
|
||||
- if (priv->mgmt_master && !qca8k_read_eth(priv, reg, val, len))
|
||||
- return 0;
|
||||
-
|
||||
- for (i = 0; i < count; i++) {
|
||||
- ret = regmap_read(priv->regmap, reg + (i * 4), val + i);
|
||||
- if (ret < 0)
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
|
||||
-{
|
||||
- int i, count = len / sizeof(u32), ret;
|
||||
- u32 tmp;
|
||||
-
|
||||
- if (priv->mgmt_master && !qca8k_write_eth(priv, reg, val, len))
|
||||
- return 0;
|
||||
-
|
||||
- for (i = 0; i < count; i++) {
|
||||
- tmp = val[i];
|
||||
-
|
||||
- ret = regmap_write(priv->regmap, reg + (i * 4), tmp);
|
||||
- if (ret < 0)
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val)
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
|
||||
@@ -3096,6 +3059,8 @@ static SIMPLE_DEV_PM_OPS(qca8k_pm_ops,
|
||||
|
||||
static const struct qca8k_info_ops qca8xxx_ops = {
|
||||
.autocast_mib = qca8k_get_ethtool_stats_eth,
|
||||
+ .read_eth = qca8k_read_eth,
|
||||
+ .write_eth = qca8k_write_eth,
|
||||
};
|
||||
|
||||
static const struct qca8k_match_data qca8327 = {
|
||||
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||||
@@ -99,3 +99,42 @@ const struct regmap_access_table qca8k_r
|
||||
.yes_ranges = qca8k_readable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges),
|
||||
};
|
||||
+
|
||||
+/* TODO: remove these extra ops when we can support regmap bulk read/write */
|
||||
+int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
|
||||
+{
|
||||
+ int i, count = len / sizeof(u32), ret;
|
||||
+
|
||||
+ if (priv->mgmt_master && priv->info->ops->read_eth &&
|
||||
+ !priv->info->ops->read_eth(priv, reg, val, len))
|
||||
+ return 0;
|
||||
+
|
||||
+ for (i = 0; i < count; i++) {
|
||||
+ ret = regmap_read(priv->regmap, reg + (i * 4), val + i);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* TODO: remove these extra ops when we can support regmap bulk read/write */
|
||||
+int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
|
||||
+{
|
||||
+ int i, count = len / sizeof(u32), ret;
|
||||
+ u32 tmp;
|
||||
+
|
||||
+ if (priv->mgmt_master && priv->info->ops->write_eth &&
|
||||
+ !priv->info->ops->write_eth(priv, reg, val, len))
|
||||
+ return 0;
|
||||
+
|
||||
+ for (i = 0; i < count; i++) {
|
||||
+ tmp = val[i];
|
||||
+
|
||||
+ ret = regmap_write(priv->regmap, reg + (i * 4), tmp);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -324,8 +324,13 @@ enum qca8k_mid_cmd {
|
||||
QCA8K_MIB_CAST = 3,
|
||||
};
|
||||
|
||||
+struct qca8k_priv;
|
||||
+
|
||||
struct qca8k_info_ops {
|
||||
int (*autocast_mib)(struct dsa_switch *ds, int port, u64 *data);
|
||||
+ /* TODO: remove these extra ops when we can support regmap bulk read/write */
|
||||
+ int (*read_eth)(struct qca8k_priv *priv, u32 reg, u32 *val, int len);
|
||||
+ int (*write_eth)(struct qca8k_priv *priv, u32 reg, u32 *val, int len);
|
||||
};
|
||||
|
||||
struct qca8k_match_data {
|
||||
@@ -423,4 +428,7 @@ int qca8k_read(struct qca8k_priv *priv,
|
||||
int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val);
|
||||
int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val);
|
||||
|
||||
+int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len);
|
||||
+int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len);
|
||||
+
|
||||
#endif /* __QCA8K_H */
|
@@ -0,0 +1,137 @@
|
||||
From fce1ec0c4e2d03d9c62ffc615a42bdba78eb4c14 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 27 Jul 2022 13:35:15 +0200
|
||||
Subject: [PATCH 06/14] net: dsa: qca8k: move mib init function to common code
|
||||
|
||||
The same mib function is used by drivers based on qca8k family switch.
|
||||
Move it to common code to make it accessible also by other drivers.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 37 ------------------------------
|
||||
drivers/net/dsa/qca/qca8k-common.c | 35 ++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca/qca8k.h | 4 ++++
|
||||
3 files changed, 39 insertions(+), 37 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -442,15 +442,6 @@ static struct regmap_config qca8k_regmap
|
||||
};
|
||||
|
||||
static int
|
||||
-qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
|
||||
-{
|
||||
- u32 val;
|
||||
-
|
||||
- return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0,
|
||||
- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb)
|
||||
{
|
||||
u32 reg[3];
|
||||
@@ -777,34 +768,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int
|
||||
-qca8k_mib_init(struct qca8k_priv *priv)
|
||||
-{
|
||||
- int ret;
|
||||
-
|
||||
- mutex_lock(&priv->reg_mutex);
|
||||
- ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB,
|
||||
- QCA8K_MIB_FUNC | QCA8K_MIB_BUSY,
|
||||
- FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) |
|
||||
- QCA8K_MIB_BUSY);
|
||||
- if (ret)
|
||||
- goto exit;
|
||||
-
|
||||
- ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY);
|
||||
- if (ret)
|
||||
- goto exit;
|
||||
-
|
||||
- ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP);
|
||||
- if (ret)
|
||||
- goto exit;
|
||||
-
|
||||
- ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB);
|
||||
-
|
||||
-exit:
|
||||
- mutex_unlock(&priv->reg_mutex);
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
static void
|
||||
qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable)
|
||||
{
|
||||
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
+#include <linux/bitfield.h>
|
||||
#include <net/dsa.h>
|
||||
|
||||
#include "qca8k.h"
|
||||
@@ -138,3 +139,38 @@ int qca8k_bulk_write(struct qca8k_priv *
|
||||
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
|
||||
+{
|
||||
+ u32 val;
|
||||
+
|
||||
+ return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0,
|
||||
+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC);
|
||||
+}
|
||||
+
|
||||
+int qca8k_mib_init(struct qca8k_priv *priv)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB,
|
||||
+ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY,
|
||||
+ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) |
|
||||
+ QCA8K_MIB_BUSY);
|
||||
+ if (ret)
|
||||
+ goto exit;
|
||||
+
|
||||
+ ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY);
|
||||
+ if (ret)
|
||||
+ goto exit;
|
||||
+
|
||||
+ ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP);
|
||||
+ if (ret)
|
||||
+ goto exit;
|
||||
+
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB);
|
||||
+
|
||||
+exit:
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+ return ret;
|
||||
+}
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -422,6 +422,7 @@ struct qca8k_fdb {
|
||||
/* Common setup function */
|
||||
extern const struct qca8k_mib_desc ar8327_mib[];
|
||||
extern const struct regmap_access_table qca8k_readable_table;
|
||||
+int qca8k_mib_init(struct qca8k_priv *priv);
|
||||
|
||||
/* Common read/write/rmw function */
|
||||
int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val);
|
||||
@@ -431,4 +432,7 @@ int qca8k_rmw(struct qca8k_priv *priv, u
|
||||
int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len);
|
||||
int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len);
|
||||
|
||||
+/* Common ops function */
|
||||
+int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask);
|
||||
+
|
||||
#endif /* __QCA8K_H */
|
@@ -0,0 +1,281 @@
|
||||
From 472fcea160f27a5d9b7526093d9d8d89ba0b6137 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 27 Jul 2022 13:35:16 +0200
|
||||
Subject: [PATCH 07/14] net: dsa: qca8k: move port set status/eee/ethtool stats
|
||||
function to common code
|
||||
|
||||
The same logic to disable/enable port, set eee and get ethtool stats is
|
||||
used by drivers based on qca8k family switch.
|
||||
Move it to common code to make it accessible also by other drivers.
|
||||
While at it also drop unnecessary qca8k_priv cast for void pointers.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 105 -----------------------------
|
||||
drivers/net/dsa/qca/qca8k-common.c | 102 ++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca/qca8k.h | 11 +++
|
||||
3 files changed, 113 insertions(+), 105 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -768,21 +768,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static void
|
||||
-qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable)
|
||||
-{
|
||||
- u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC;
|
||||
-
|
||||
- /* Port 0 and 6 have no internal PHY */
|
||||
- if (port > 0 && port < 6)
|
||||
- mask |= QCA8K_PORT_STATUS_LINK_AUTO;
|
||||
-
|
||||
- if (enable)
|
||||
- regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask);
|
||||
- else
|
||||
- regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask);
|
||||
-}
|
||||
-
|
||||
static int
|
||||
qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data,
|
||||
struct sk_buff *read_skb, u32 *val)
|
||||
@@ -1974,20 +1959,6 @@ qca8k_phylink_mac_link_up(struct dsa_swi
|
||||
qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg);
|
||||
}
|
||||
|
||||
-static void
|
||||
-qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data)
|
||||
-{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
- int i;
|
||||
-
|
||||
- if (stringset != ETH_SS_STATS)
|
||||
- return;
|
||||
-
|
||||
- for (i = 0; i < priv->info->mib_count; i++)
|
||||
- strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name,
|
||||
- ETH_GSTRING_LEN);
|
||||
-}
|
||||
-
|
||||
static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb)
|
||||
{
|
||||
struct qca8k_mib_eth_data *mib_eth_data;
|
||||
@@ -2078,82 +2049,6 @@ exit:
|
||||
}
|
||||
|
||||
static void
|
||||
-qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
|
||||
- uint64_t *data)
|
||||
-{
|
||||
- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
- const struct qca8k_mib_desc *mib;
|
||||
- u32 reg, i, val;
|
||||
- u32 hi = 0;
|
||||
- int ret;
|
||||
-
|
||||
- if (priv->mgmt_master && priv->info->ops->autocast_mib &&
|
||||
- priv->info->ops->autocast_mib(ds, port, data) > 0)
|
||||
- return;
|
||||
-
|
||||
- for (i = 0; i < priv->info->mib_count; i++) {
|
||||
- mib = &ar8327_mib[i];
|
||||
- reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset;
|
||||
-
|
||||
- ret = qca8k_read(priv, reg, &val);
|
||||
- if (ret < 0)
|
||||
- continue;
|
||||
-
|
||||
- if (mib->size == 2) {
|
||||
- ret = qca8k_read(priv, reg + 4, &hi);
|
||||
- if (ret < 0)
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- data[i] = val;
|
||||
- if (mib->size == 2)
|
||||
- data[i] |= (u64)hi << 32;
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset)
|
||||
-{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
-
|
||||
- if (sset != ETH_SS_STATS)
|
||||
- return 0;
|
||||
-
|
||||
- return priv->info->mib_count;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee)
|
||||
-{
|
||||
- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
- u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port);
|
||||
- u32 reg;
|
||||
- int ret;
|
||||
-
|
||||
- mutex_lock(&priv->reg_mutex);
|
||||
- ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®);
|
||||
- if (ret < 0)
|
||||
- goto exit;
|
||||
-
|
||||
- if (eee->eee_enabled)
|
||||
- reg |= lpi_en;
|
||||
- else
|
||||
- reg &= ~lpi_en;
|
||||
- ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg);
|
||||
-
|
||||
-exit:
|
||||
- mutex_unlock(&priv->reg_mutex);
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
|
||||
-{
|
||||
- /* Nothing to do on the port's MAC */
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static void
|
||||
qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||||
@@ -174,3 +174,105 @@ exit:
|
||||
mutex_unlock(&priv->reg_mutex);
|
||||
return ret;
|
||||
}
|
||||
+
|
||||
+void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable)
|
||||
+{
|
||||
+ u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC;
|
||||
+
|
||||
+ /* Port 0 and 6 have no internal PHY */
|
||||
+ if (port > 0 && port < 6)
|
||||
+ mask |= QCA8K_PORT_STATUS_LINK_AUTO;
|
||||
+
|
||||
+ if (enable)
|
||||
+ regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask);
|
||||
+ else
|
||||
+ regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask);
|
||||
+}
|
||||
+
|
||||
+void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset,
|
||||
+ uint8_t *data)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ int i;
|
||||
+
|
||||
+ if (stringset != ETH_SS_STATS)
|
||||
+ return;
|
||||
+
|
||||
+ for (i = 0; i < priv->info->mib_count; i++)
|
||||
+ strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name,
|
||||
+ ETH_GSTRING_LEN);
|
||||
+}
|
||||
+
|
||||
+void qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
|
||||
+ uint64_t *data)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ const struct qca8k_mib_desc *mib;
|
||||
+ u32 reg, i, val;
|
||||
+ u32 hi = 0;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (priv->mgmt_master && priv->info->ops->autocast_mib &&
|
||||
+ priv->info->ops->autocast_mib(ds, port, data) > 0)
|
||||
+ return;
|
||||
+
|
||||
+ for (i = 0; i < priv->info->mib_count; i++) {
|
||||
+ mib = &ar8327_mib[i];
|
||||
+ reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset;
|
||||
+
|
||||
+ ret = qca8k_read(priv, reg, &val);
|
||||
+ if (ret < 0)
|
||||
+ continue;
|
||||
+
|
||||
+ if (mib->size == 2) {
|
||||
+ ret = qca8k_read(priv, reg + 4, &hi);
|
||||
+ if (ret < 0)
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ data[i] = val;
|
||||
+ if (mib->size == 2)
|
||||
+ data[i] |= (u64)hi << 32;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+int qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+
|
||||
+ if (sset != ETH_SS_STATS)
|
||||
+ return 0;
|
||||
+
|
||||
+ return priv->info->mib_count;
|
||||
+}
|
||||
+
|
||||
+int qca8k_set_mac_eee(struct dsa_switch *ds, int port,
|
||||
+ struct ethtool_eee *eee)
|
||||
+{
|
||||
+ u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port);
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ u32 reg;
|
||||
+ int ret;
|
||||
+
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+ ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®);
|
||||
+ if (ret < 0)
|
||||
+ goto exit;
|
||||
+
|
||||
+ if (eee->eee_enabled)
|
||||
+ reg |= lpi_en;
|
||||
+ else
|
||||
+ reg &= ~lpi_en;
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg);
|
||||
+
|
||||
+exit:
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+int qca8k_get_mac_eee(struct dsa_switch *ds, int port,
|
||||
+ struct ethtool_eee *e)
|
||||
+{
|
||||
+ /* Nothing to do on the port's MAC */
|
||||
+ return 0;
|
||||
+}
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -423,6 +423,7 @@ struct qca8k_fdb {
|
||||
extern const struct qca8k_mib_desc ar8327_mib[];
|
||||
extern const struct regmap_access_table qca8k_readable_table;
|
||||
int qca8k_mib_init(struct qca8k_priv *priv);
|
||||
+void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable);
|
||||
|
||||
/* Common read/write/rmw function */
|
||||
int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val);
|
||||
@@ -435,4 +436,14 @@ int qca8k_bulk_write(struct qca8k_priv *
|
||||
/* Common ops function */
|
||||
int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask);
|
||||
|
||||
+/* Common ethtool stats function */
|
||||
+void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data);
|
||||
+void qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
|
||||
+ uint64_t *data);
|
||||
+int qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset);
|
||||
+
|
||||
+/* Common eee function */
|
||||
+int qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee);
|
||||
+int qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e);
|
||||
+
|
||||
#endif /* __QCA8K_H */
|
@@ -0,0 +1,237 @@
|
||||
From fd3cae2f3ac190d06e48f43739237e02f9dc51ff Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 27 Jul 2022 13:35:17 +0200
|
||||
Subject: [PATCH 08/14] net: dsa: qca8k: move bridge functions to common code
|
||||
|
||||
The same bridge functions are used by drivers based on qca8k family
|
||||
switch. Move them to common code to make them accessible also by other
|
||||
drivers.
|
||||
While at it also drop unnecessary qca8k_priv cast for void pointers.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 93 ------------------------------
|
||||
drivers/net/dsa/qca/qca8k-common.c | 93 ++++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca/qca8k.h | 9 +++
|
||||
3 files changed, 102 insertions(+), 93 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -2049,97 +2049,6 @@ exit:
|
||||
}
|
||||
|
||||
static void
|
||||
-qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
|
||||
-{
|
||||
- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
- u32 stp_state;
|
||||
-
|
||||
- switch (state) {
|
||||
- case BR_STATE_DISABLED:
|
||||
- stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED;
|
||||
- break;
|
||||
- case BR_STATE_BLOCKING:
|
||||
- stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING;
|
||||
- break;
|
||||
- case BR_STATE_LISTENING:
|
||||
- stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING;
|
||||
- break;
|
||||
- case BR_STATE_LEARNING:
|
||||
- stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING;
|
||||
- break;
|
||||
- case BR_STATE_FORWARDING:
|
||||
- default:
|
||||
- stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD;
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
- QCA8K_PORT_LOOKUP_STATE_MASK, stp_state);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br)
|
||||
-{
|
||||
- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
- int port_mask, cpu_port;
|
||||
- int i, ret;
|
||||
-
|
||||
- cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
|
||||
- port_mask = BIT(cpu_port);
|
||||
-
|
||||
- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
- if (dsa_is_cpu_port(ds, i))
|
||||
- continue;
|
||||
- if (dsa_to_port(ds, i)->bridge_dev != br)
|
||||
- continue;
|
||||
- /* Add this port to the portvlan mask of the other ports
|
||||
- * in the bridge
|
||||
- */
|
||||
- ret = regmap_set_bits(priv->regmap,
|
||||
- QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
- BIT(port));
|
||||
- if (ret)
|
||||
- return ret;
|
||||
- if (i != port)
|
||||
- port_mask |= BIT(i);
|
||||
- }
|
||||
-
|
||||
- /* Add all other ports to this ports portvlan mask */
|
||||
- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
- QCA8K_PORT_LOOKUP_MEMBER, port_mask);
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static void
|
||||
-qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br)
|
||||
-{
|
||||
- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
- int cpu_port, i;
|
||||
-
|
||||
- cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
|
||||
-
|
||||
- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
- if (dsa_is_cpu_port(ds, i))
|
||||
- continue;
|
||||
- if (dsa_to_port(ds, i)->bridge_dev != br)
|
||||
- continue;
|
||||
- /* Remove this port to the portvlan mask of the other ports
|
||||
- * in the bridge
|
||||
- */
|
||||
- regmap_clear_bits(priv->regmap,
|
||||
- QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
- BIT(port));
|
||||
- }
|
||||
-
|
||||
- /* Set the cpu port to be the only one in the portvlan mask of
|
||||
- * this port
|
||||
- */
|
||||
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
- QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));
|
||||
-}
|
||||
-
|
||||
-static void
|
||||
qca8k_port_fast_age(struct dsa_switch *ds, int port)
|
||||
{
|
||||
struct qca8k_priv *priv = ds->priv;
|
||||
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <net/dsa.h>
|
||||
+#include <linux/if_bridge.h>
|
||||
|
||||
#include "qca8k.h"
|
||||
|
||||
@@ -276,3 +277,93 @@ int qca8k_get_mac_eee(struct dsa_switch
|
||||
/* Nothing to do on the port's MAC */
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ u32 stp_state;
|
||||
+
|
||||
+ switch (state) {
|
||||
+ case BR_STATE_DISABLED:
|
||||
+ stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED;
|
||||
+ break;
|
||||
+ case BR_STATE_BLOCKING:
|
||||
+ stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING;
|
||||
+ break;
|
||||
+ case BR_STATE_LISTENING:
|
||||
+ stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING;
|
||||
+ break;
|
||||
+ case BR_STATE_LEARNING:
|
||||
+ stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING;
|
||||
+ break;
|
||||
+ case BR_STATE_FORWARDING:
|
||||
+ default:
|
||||
+ stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
+ QCA8K_PORT_LOOKUP_STATE_MASK, stp_state);
|
||||
+}
|
||||
+
|
||||
+int qca8k_port_bridge_join(struct dsa_switch *ds, int port,
|
||||
+ struct net_device *br)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ int port_mask, cpu_port;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
|
||||
+ port_mask = BIT(cpu_port);
|
||||
+
|
||||
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
+ if (dsa_is_cpu_port(ds, i))
|
||||
+ continue;
|
||||
+ if (dsa_to_port(ds, i)->bridge_dev != br)
|
||||
+ continue;
|
||||
+ /* Add this port to the portvlan mask of the other ports
|
||||
+ * in the bridge
|
||||
+ */
|
||||
+ ret = regmap_set_bits(priv->regmap,
|
||||
+ QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
+ BIT(port));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ if (i != port)
|
||||
+ port_mask |= BIT(i);
|
||||
+ }
|
||||
+
|
||||
+ /* Add all other ports to this ports portvlan mask */
|
||||
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
+ QCA8K_PORT_LOOKUP_MEMBER, port_mask);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+void qca8k_port_bridge_leave(struct dsa_switch *ds, int port,
|
||||
+ struct net_device *br)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ int cpu_port, i;
|
||||
+
|
||||
+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
|
||||
+
|
||||
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
+ if (dsa_is_cpu_port(ds, i))
|
||||
+ continue;
|
||||
+ if (dsa_to_port(ds, i)->bridge_dev != br)
|
||||
+ continue;
|
||||
+ /* Remove this port to the portvlan mask of the other ports
|
||||
+ * in the bridge
|
||||
+ */
|
||||
+ regmap_clear_bits(priv->regmap,
|
||||
+ QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
+ BIT(port));
|
||||
+ }
|
||||
+
|
||||
+ /* Set the cpu port to be the only one in the portvlan mask of
|
||||
+ * this port
|
||||
+ */
|
||||
+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
+ QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));
|
||||
+}
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -446,4 +446,11 @@ int qca8k_get_sset_count(struct dsa_swit
|
||||
int qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee);
|
||||
int qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e);
|
||||
|
||||
+/* Common bridge function */
|
||||
+void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state);
|
||||
+int qca8k_port_bridge_join(struct dsa_switch *ds, int port,
|
||||
+ struct net_device *br);
|
||||
+void qca8k_port_bridge_leave(struct dsa_switch *ds, int port,
|
||||
+ struct net_device *br);
|
||||
+
|
||||
#endif /* __QCA8K_H */
|
@@ -0,0 +1,227 @@
|
||||
From b3a302b171f73425b41de8d3357fae3fa7057322 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 27 Jul 2022 13:35:18 +0200
|
||||
Subject: [PATCH 09/14] net: dsa: qca8k: move set age/MTU/port enable/disable
|
||||
functions to common code
|
||||
|
||||
The same set age, MTU and port enable/disable function are used by
|
||||
driver based on qca8k family switch.
|
||||
Move them to common code to make them accessible also by other drivers.
|
||||
While at it also drop unnecessary qca8k_priv cast for void pointers.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 88 ------------------------------
|
||||
drivers/net/dsa/qca/qca8k-common.c | 85 +++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca/qca8k.h | 12 ++++
|
||||
3 files changed, 97 insertions(+), 88 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -2059,94 +2059,6 @@ qca8k_port_fast_age(struct dsa_switch *d
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
|
||||
-{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
- unsigned int secs = msecs / 1000;
|
||||
- u32 val;
|
||||
-
|
||||
- /* AGE_TIME reg is set in 7s step */
|
||||
- val = secs / 7;
|
||||
-
|
||||
- /* Handle case with 0 as val to NOT disable
|
||||
- * learning
|
||||
- */
|
||||
- if (!val)
|
||||
- val = 1;
|
||||
-
|
||||
- return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK,
|
||||
- QCA8K_ATU_AGE_TIME(val));
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_enable(struct dsa_switch *ds, int port,
|
||||
- struct phy_device *phy)
|
||||
-{
|
||||
- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
-
|
||||
- qca8k_port_set_status(priv, port, 1);
|
||||
- priv->port_enabled_map |= BIT(port);
|
||||
-
|
||||
- if (dsa_is_user_port(ds, port))
|
||||
- phy_support_asym_pause(phy);
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static void
|
||||
-qca8k_port_disable(struct dsa_switch *ds, int port)
|
||||
-{
|
||||
- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
-
|
||||
- qca8k_port_set_status(priv, port, 0);
|
||||
- priv->port_enabled_map &= ~BIT(port);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
|
||||
-{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
- int ret;
|
||||
-
|
||||
- /* We have only have a general MTU setting.
|
||||
- * DSA always set the CPU port's MTU to the largest MTU of the slave
|
||||
- * ports.
|
||||
- * Setting MTU just for the CPU port is sufficient to correctly set a
|
||||
- * value for every port.
|
||||
- */
|
||||
- if (!dsa_is_cpu_port(ds, port))
|
||||
- return 0;
|
||||
-
|
||||
- /* To change the MAX_FRAME_SIZE the cpu ports must be off or
|
||||
- * the switch panics.
|
||||
- * Turn off both cpu ports before applying the new value to prevent
|
||||
- * this.
|
||||
- */
|
||||
- if (priv->port_enabled_map & BIT(0))
|
||||
- qca8k_port_set_status(priv, 0, 0);
|
||||
-
|
||||
- if (priv->port_enabled_map & BIT(6))
|
||||
- qca8k_port_set_status(priv, 6, 0);
|
||||
-
|
||||
- /* Include L2 header / FCS length */
|
||||
- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN);
|
||||
-
|
||||
- if (priv->port_enabled_map & BIT(0))
|
||||
- qca8k_port_set_status(priv, 0, 1);
|
||||
-
|
||||
- if (priv->port_enabled_map & BIT(6))
|
||||
- qca8k_port_set_status(priv, 6, 1);
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_max_mtu(struct dsa_switch *ds, int port)
|
||||
-{
|
||||
- return QCA8K_MAX_MTU;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr,
|
||||
u16 port_mask, u16 vid)
|
||||
{
|
||||
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||||
@@ -367,3 +367,88 @@ void qca8k_port_bridge_leave(struct dsa_
|
||||
qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));
|
||||
}
|
||||
+
|
||||
+int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ unsigned int secs = msecs / 1000;
|
||||
+ u32 val;
|
||||
+
|
||||
+ /* AGE_TIME reg is set in 7s step */
|
||||
+ val = secs / 7;
|
||||
+
|
||||
+ /* Handle case with 0 as val to NOT disable
|
||||
+ * learning
|
||||
+ */
|
||||
+ if (!val)
|
||||
+ val = 1;
|
||||
+
|
||||
+ return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL,
|
||||
+ QCA8K_ATU_AGE_TIME_MASK,
|
||||
+ QCA8K_ATU_AGE_TIME(val));
|
||||
+}
|
||||
+
|
||||
+int qca8k_port_enable(struct dsa_switch *ds, int port,
|
||||
+ struct phy_device *phy)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+
|
||||
+ qca8k_port_set_status(priv, port, 1);
|
||||
+ priv->port_enabled_map |= BIT(port);
|
||||
+
|
||||
+ if (dsa_is_user_port(ds, port))
|
||||
+ phy_support_asym_pause(phy);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void qca8k_port_disable(struct dsa_switch *ds, int port)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+
|
||||
+ qca8k_port_set_status(priv, port, 0);
|
||||
+ priv->port_enabled_map &= ~BIT(port);
|
||||
+}
|
||||
+
|
||||
+int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* We have only have a general MTU setting.
|
||||
+ * DSA always set the CPU port's MTU to the largest MTU of the slave
|
||||
+ * ports.
|
||||
+ * Setting MTU just for the CPU port is sufficient to correctly set a
|
||||
+ * value for every port.
|
||||
+ */
|
||||
+ if (!dsa_is_cpu_port(ds, port))
|
||||
+ return 0;
|
||||
+
|
||||
+ /* To change the MAX_FRAME_SIZE the cpu ports must be off or
|
||||
+ * the switch panics.
|
||||
+ * Turn off both cpu ports before applying the new value to prevent
|
||||
+ * this.
|
||||
+ */
|
||||
+ if (priv->port_enabled_map & BIT(0))
|
||||
+ qca8k_port_set_status(priv, 0, 0);
|
||||
+
|
||||
+ if (priv->port_enabled_map & BIT(6))
|
||||
+ qca8k_port_set_status(priv, 6, 0);
|
||||
+
|
||||
+ /* Include L2 header / FCS length */
|
||||
+ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu +
|
||||
+ ETH_HLEN + ETH_FCS_LEN);
|
||||
+
|
||||
+ if (priv->port_enabled_map & BIT(0))
|
||||
+ qca8k_port_set_status(priv, 0, 1);
|
||||
+
|
||||
+ if (priv->port_enabled_map & BIT(6))
|
||||
+ qca8k_port_set_status(priv, 6, 1);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+int qca8k_port_max_mtu(struct dsa_switch *ds, int port)
|
||||
+{
|
||||
+ return QCA8K_MAX_MTU;
|
||||
+}
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -453,4 +453,16 @@ int qca8k_port_bridge_join(struct dsa_sw
|
||||
void qca8k_port_bridge_leave(struct dsa_switch *ds, int port,
|
||||
struct net_device *br);
|
||||
|
||||
+/* Common port enable/disable function */
|
||||
+int qca8k_port_enable(struct dsa_switch *ds, int port,
|
||||
+ struct phy_device *phy);
|
||||
+void qca8k_port_disable(struct dsa_switch *ds, int port);
|
||||
+
|
||||
+/* Common MTU function */
|
||||
+int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu);
|
||||
+int qca8k_port_max_mtu(struct dsa_switch *ds, int port);
|
||||
+
|
||||
+/* Common fast age function */
|
||||
+int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs);
|
||||
+
|
||||
#endif /* __QCA8K_H */
|
@@ -0,0 +1,704 @@
|
||||
From 2e5bd96eea86a246b4de3bf756f7a11b43e6187d Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 27 Jul 2022 13:35:19 +0200
|
||||
Subject: [PATCH 10/14] net: dsa: qca8k: move port FDB/MDB function to common
|
||||
code
|
||||
|
||||
The same port FDB/MDB function are used by drivers based on qca8k family
|
||||
switch. Move them to common code to make them accessible also by other
|
||||
drivers.
|
||||
Also drop bulk read/write functions and make them static
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 306 -----------------------------
|
||||
drivers/net/dsa/qca/qca8k-common.c | 297 +++++++++++++++++++++++++++-
|
||||
drivers/net/dsa/qca/qca8k.h | 25 ++-
|
||||
3 files changed, 317 insertions(+), 311 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -442,217 +442,6 @@ static struct regmap_config qca8k_regmap
|
||||
};
|
||||
|
||||
static int
|
||||
-qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb)
|
||||
-{
|
||||
- u32 reg[3];
|
||||
- int ret;
|
||||
-
|
||||
- /* load the ARL table into an array */
|
||||
- ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg));
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- /* vid - 83:72 */
|
||||
- fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]);
|
||||
- /* aging - 67:64 */
|
||||
- fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]);
|
||||
- /* portmask - 54:48 */
|
||||
- fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]);
|
||||
- /* mac - 47:0 */
|
||||
- fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]);
|
||||
- fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]);
|
||||
- fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]);
|
||||
- fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]);
|
||||
- fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]);
|
||||
- fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]);
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static void
|
||||
-qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac,
|
||||
- u8 aging)
|
||||
-{
|
||||
- u32 reg[3] = { 0 };
|
||||
-
|
||||
- /* vid - 83:72 */
|
||||
- reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid);
|
||||
- /* aging - 67:64 */
|
||||
- reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging);
|
||||
- /* portmask - 54:48 */
|
||||
- reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask);
|
||||
- /* mac - 47:0 */
|
||||
- reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]);
|
||||
- reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]);
|
||||
- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]);
|
||||
- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]);
|
||||
- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]);
|
||||
- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]);
|
||||
-
|
||||
- /* load the array into the ARL table */
|
||||
- qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg));
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port)
|
||||
-{
|
||||
- u32 reg;
|
||||
- int ret;
|
||||
-
|
||||
- /* Set the command and FDB index */
|
||||
- reg = QCA8K_ATU_FUNC_BUSY;
|
||||
- reg |= cmd;
|
||||
- if (port >= 0) {
|
||||
- reg |= QCA8K_ATU_FUNC_PORT_EN;
|
||||
- reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port);
|
||||
- }
|
||||
-
|
||||
- /* Write the function register triggering the table access */
|
||||
- ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- /* wait for completion */
|
||||
- ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- /* Check for table full violation when adding an entry */
|
||||
- if (cmd == QCA8K_FDB_LOAD) {
|
||||
- ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®);
|
||||
- if (ret < 0)
|
||||
- return ret;
|
||||
- if (reg & QCA8K_ATU_FUNC_FULL)
|
||||
- return -1;
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port)
|
||||
-{
|
||||
- int ret;
|
||||
-
|
||||
- qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging);
|
||||
- ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port);
|
||||
- if (ret < 0)
|
||||
- return ret;
|
||||
-
|
||||
- return qca8k_fdb_read(priv, fdb);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, u16 port_mask,
|
||||
- u16 vid, u8 aging)
|
||||
-{
|
||||
- int ret;
|
||||
-
|
||||
- mutex_lock(&priv->reg_mutex);
|
||||
- qca8k_fdb_write(priv, vid, port_mask, mac, aging);
|
||||
- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
|
||||
- mutex_unlock(&priv->reg_mutex);
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, u16 vid)
|
||||
-{
|
||||
- int ret;
|
||||
-
|
||||
- mutex_lock(&priv->reg_mutex);
|
||||
- qca8k_fdb_write(priv, vid, port_mask, mac, 0);
|
||||
- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
|
||||
- mutex_unlock(&priv->reg_mutex);
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static void
|
||||
-qca8k_fdb_flush(struct qca8k_priv *priv)
|
||||
-{
|
||||
- mutex_lock(&priv->reg_mutex);
|
||||
- qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1);
|
||||
- mutex_unlock(&priv->reg_mutex);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask,
|
||||
- const u8 *mac, u16 vid)
|
||||
-{
|
||||
- struct qca8k_fdb fdb = { 0 };
|
||||
- int ret;
|
||||
-
|
||||
- mutex_lock(&priv->reg_mutex);
|
||||
-
|
||||
- qca8k_fdb_write(priv, vid, 0, mac, 0);
|
||||
- ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1);
|
||||
- if (ret < 0)
|
||||
- goto exit;
|
||||
-
|
||||
- ret = qca8k_fdb_read(priv, &fdb);
|
||||
- if (ret < 0)
|
||||
- goto exit;
|
||||
-
|
||||
- /* Rule exist. Delete first */
|
||||
- if (!fdb.aging) {
|
||||
- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
|
||||
- if (ret)
|
||||
- goto exit;
|
||||
- }
|
||||
-
|
||||
- /* Add port to fdb portmask */
|
||||
- fdb.port_mask |= port_mask;
|
||||
-
|
||||
- qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging);
|
||||
- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
|
||||
-
|
||||
-exit:
|
||||
- mutex_unlock(&priv->reg_mutex);
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask,
|
||||
- const u8 *mac, u16 vid)
|
||||
-{
|
||||
- struct qca8k_fdb fdb = { 0 };
|
||||
- int ret;
|
||||
-
|
||||
- mutex_lock(&priv->reg_mutex);
|
||||
-
|
||||
- qca8k_fdb_write(priv, vid, 0, mac, 0);
|
||||
- ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1);
|
||||
- if (ret < 0)
|
||||
- goto exit;
|
||||
-
|
||||
- /* Rule doesn't exist. Why delete? */
|
||||
- if (!fdb.aging) {
|
||||
- ret = -EINVAL;
|
||||
- goto exit;
|
||||
- }
|
||||
-
|
||||
- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
|
||||
- if (ret)
|
||||
- goto exit;
|
||||
-
|
||||
- /* Only port in the rule is this port. Don't re insert */
|
||||
- if (fdb.port_mask == port_mask)
|
||||
- goto exit;
|
||||
-
|
||||
- /* Remove port from port mask */
|
||||
- fdb.port_mask &= ~port_mask;
|
||||
-
|
||||
- qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging);
|
||||
- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
|
||||
-
|
||||
-exit:
|
||||
- mutex_unlock(&priv->reg_mutex);
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid)
|
||||
{
|
||||
u32 reg;
|
||||
@@ -2048,97 +1837,6 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static void
|
||||
-qca8k_port_fast_age(struct dsa_switch *ds, int port)
|
||||
-{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
-
|
||||
- mutex_lock(&priv->reg_mutex);
|
||||
- qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port);
|
||||
- mutex_unlock(&priv->reg_mutex);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr,
|
||||
- u16 port_mask, u16 vid)
|
||||
-{
|
||||
- /* Set the vid to the port vlan id if no vid is set */
|
||||
- if (!vid)
|
||||
- vid = QCA8K_PORT_VID_DEF;
|
||||
-
|
||||
- return qca8k_fdb_add(priv, addr, port_mask, vid,
|
||||
- QCA8K_ATU_STATUS_STATIC);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_fdb_add(struct dsa_switch *ds, int port,
|
||||
- const unsigned char *addr, u16 vid)
|
||||
-{
|
||||
- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
- u16 port_mask = BIT(port);
|
||||
-
|
||||
- return qca8k_port_fdb_insert(priv, addr, port_mask, vid);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_fdb_del(struct dsa_switch *ds, int port,
|
||||
- const unsigned char *addr, u16 vid)
|
||||
-{
|
||||
- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
- u16 port_mask = BIT(port);
|
||||
-
|
||||
- if (!vid)
|
||||
- vid = QCA8K_PORT_VID_DEF;
|
||||
-
|
||||
- return qca8k_fdb_del(priv, addr, port_mask, vid);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
|
||||
- dsa_fdb_dump_cb_t *cb, void *data)
|
||||
-{
|
||||
- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
- struct qca8k_fdb _fdb = { 0 };
|
||||
- int cnt = QCA8K_NUM_FDB_RECORDS;
|
||||
- bool is_static;
|
||||
- int ret = 0;
|
||||
-
|
||||
- mutex_lock(&priv->reg_mutex);
|
||||
- while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) {
|
||||
- if (!_fdb.aging)
|
||||
- break;
|
||||
- is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC);
|
||||
- ret = cb(_fdb.mac, _fdb.vid, is_static, data);
|
||||
- if (ret)
|
||||
- break;
|
||||
- }
|
||||
- mutex_unlock(&priv->reg_mutex);
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_mdb_add(struct dsa_switch *ds, int port,
|
||||
- const struct switchdev_obj_port_mdb *mdb)
|
||||
-{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
- const u8 *addr = mdb->addr;
|
||||
- u16 vid = mdb->vid;
|
||||
-
|
||||
- return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_mdb_del(struct dsa_switch *ds, int port,
|
||||
- const struct switchdev_obj_port_mdb *mdb)
|
||||
-{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
- const u8 *addr = mdb->addr;
|
||||
- u16 vid = mdb->vid;
|
||||
-
|
||||
- return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid);
|
||||
-}
|
||||
-
|
||||
static int
|
||||
qca8k_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror,
|
||||
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||||
@@ -103,7 +103,7 @@ const struct regmap_access_table qca8k_r
|
||||
};
|
||||
|
||||
/* TODO: remove these extra ops when we can support regmap bulk read/write */
|
||||
-int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
|
||||
+static int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
|
||||
{
|
||||
int i, count = len / sizeof(u32), ret;
|
||||
|
||||
@@ -121,7 +121,7 @@ int qca8k_bulk_read(struct qca8k_priv *p
|
||||
}
|
||||
|
||||
/* TODO: remove these extra ops when we can support regmap bulk read/write */
|
||||
-int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
|
||||
+static int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
|
||||
{
|
||||
int i, count = len / sizeof(u32), ret;
|
||||
u32 tmp;
|
||||
@@ -149,6 +149,211 @@ int qca8k_busy_wait(struct qca8k_priv *p
|
||||
QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC);
|
||||
}
|
||||
|
||||
+static int qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb)
|
||||
+{
|
||||
+ u32 reg[3];
|
||||
+ int ret;
|
||||
+
|
||||
+ /* load the ARL table into an array */
|
||||
+ ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* vid - 83:72 */
|
||||
+ fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]);
|
||||
+ /* aging - 67:64 */
|
||||
+ fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]);
|
||||
+ /* portmask - 54:48 */
|
||||
+ fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]);
|
||||
+ /* mac - 47:0 */
|
||||
+ fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]);
|
||||
+ fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]);
|
||||
+ fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]);
|
||||
+ fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]);
|
||||
+ fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]);
|
||||
+ fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask,
|
||||
+ const u8 *mac, u8 aging)
|
||||
+{
|
||||
+ u32 reg[3] = { 0 };
|
||||
+
|
||||
+ /* vid - 83:72 */
|
||||
+ reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid);
|
||||
+ /* aging - 67:64 */
|
||||
+ reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging);
|
||||
+ /* portmask - 54:48 */
|
||||
+ reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask);
|
||||
+ /* mac - 47:0 */
|
||||
+ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]);
|
||||
+ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]);
|
||||
+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]);
|
||||
+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]);
|
||||
+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]);
|
||||
+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]);
|
||||
+
|
||||
+ /* load the array into the ARL table */
|
||||
+ qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg));
|
||||
+}
|
||||
+
|
||||
+static int qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd,
|
||||
+ int port)
|
||||
+{
|
||||
+ u32 reg;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Set the command and FDB index */
|
||||
+ reg = QCA8K_ATU_FUNC_BUSY;
|
||||
+ reg |= cmd;
|
||||
+ if (port >= 0) {
|
||||
+ reg |= QCA8K_ATU_FUNC_PORT_EN;
|
||||
+ reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port);
|
||||
+ }
|
||||
+
|
||||
+ /* Write the function register triggering the table access */
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* wait for completion */
|
||||
+ ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Check for table full violation when adding an entry */
|
||||
+ if (cmd == QCA8K_FDB_LOAD) {
|
||||
+ ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ if (reg & QCA8K_ATU_FUNC_FULL)
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb,
|
||||
+ int port)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging);
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ return qca8k_fdb_read(priv, fdb);
|
||||
+}
|
||||
+
|
||||
+static int qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac,
|
||||
+ u16 port_mask, u16 vid, u8 aging)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+ qca8k_fdb_write(priv, vid, port_mask, mac, aging);
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac,
|
||||
+ u16 port_mask, u16 vid)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+ qca8k_fdb_write(priv, vid, port_mask, mac, 0);
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+void qca8k_fdb_flush(struct qca8k_priv *priv)
|
||||
+{
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1);
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+}
|
||||
+
|
||||
+static int qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask,
|
||||
+ const u8 *mac, u16 vid)
|
||||
+{
|
||||
+ struct qca8k_fdb fdb = { 0 };
|
||||
+ int ret;
|
||||
+
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+
|
||||
+ qca8k_fdb_write(priv, vid, 0, mac, 0);
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1);
|
||||
+ if (ret < 0)
|
||||
+ goto exit;
|
||||
+
|
||||
+ ret = qca8k_fdb_read(priv, &fdb);
|
||||
+ if (ret < 0)
|
||||
+ goto exit;
|
||||
+
|
||||
+ /* Rule exist. Delete first */
|
||||
+ if (!fdb.aging) {
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
|
||||
+ if (ret)
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ /* Add port to fdb portmask */
|
||||
+ fdb.port_mask |= port_mask;
|
||||
+
|
||||
+ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging);
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
|
||||
+
|
||||
+exit:
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask,
|
||||
+ const u8 *mac, u16 vid)
|
||||
+{
|
||||
+ struct qca8k_fdb fdb = { 0 };
|
||||
+ int ret;
|
||||
+
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+
|
||||
+ qca8k_fdb_write(priv, vid, 0, mac, 0);
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1);
|
||||
+ if (ret < 0)
|
||||
+ goto exit;
|
||||
+
|
||||
+ /* Rule doesn't exist. Why delete? */
|
||||
+ if (!fdb.aging) {
|
||||
+ ret = -EINVAL;
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
|
||||
+ if (ret)
|
||||
+ goto exit;
|
||||
+
|
||||
+ /* Only port in the rule is this port. Don't re insert */
|
||||
+ if (fdb.port_mask == port_mask)
|
||||
+ goto exit;
|
||||
+
|
||||
+ /* Remove port from port mask */
|
||||
+ fdb.port_mask &= ~port_mask;
|
||||
+
|
||||
+ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging);
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
|
||||
+
|
||||
+exit:
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
int qca8k_mib_init(struct qca8k_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
@@ -368,6 +573,15 @@ void qca8k_port_bridge_leave(struct dsa_
|
||||
QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));
|
||||
}
|
||||
|
||||
+void qca8k_port_fast_age(struct dsa_switch *ds, int port)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port);
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+}
|
||||
+
|
||||
int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
|
||||
{
|
||||
struct qca8k_priv *priv = ds->priv;
|
||||
@@ -452,3 +666,78 @@ int qca8k_port_max_mtu(struct dsa_switch
|
||||
{
|
||||
return QCA8K_MAX_MTU;
|
||||
}
|
||||
+
|
||||
+int qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr,
|
||||
+ u16 port_mask, u16 vid)
|
||||
+{
|
||||
+ /* Set the vid to the port vlan id if no vid is set */
|
||||
+ if (!vid)
|
||||
+ vid = QCA8K_PORT_VID_DEF;
|
||||
+
|
||||
+ return qca8k_fdb_add(priv, addr, port_mask, vid,
|
||||
+ QCA8K_ATU_STATUS_STATIC);
|
||||
+}
|
||||
+
|
||||
+int qca8k_port_fdb_add(struct dsa_switch *ds, int port,
|
||||
+ const unsigned char *addr, u16 vid)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
+ u16 port_mask = BIT(port);
|
||||
+
|
||||
+ return qca8k_port_fdb_insert(priv, addr, port_mask, vid);
|
||||
+}
|
||||
+
|
||||
+int qca8k_port_fdb_del(struct dsa_switch *ds, int port,
|
||||
+ const unsigned char *addr, u16 vid)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
+ u16 port_mask = BIT(port);
|
||||
+
|
||||
+ if (!vid)
|
||||
+ vid = QCA8K_PORT_VID_DEF;
|
||||
+
|
||||
+ return qca8k_fdb_del(priv, addr, port_mask, vid);
|
||||
+}
|
||||
+
|
||||
+int qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
|
||||
+ dsa_fdb_dump_cb_t *cb, void *data)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
+ struct qca8k_fdb _fdb = { 0 };
|
||||
+ int cnt = QCA8K_NUM_FDB_RECORDS;
|
||||
+ bool is_static;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+ while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) {
|
||||
+ if (!_fdb.aging)
|
||||
+ break;
|
||||
+ is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC);
|
||||
+ ret = cb(_fdb.mac, _fdb.vid, is_static, data);
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+ }
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int qca8k_port_mdb_add(struct dsa_switch *ds, int port,
|
||||
+ const struct switchdev_obj_port_mdb *mdb)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ const u8 *addr = mdb->addr;
|
||||
+ u16 vid = mdb->vid;
|
||||
+
|
||||
+ return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid);
|
||||
+}
|
||||
+
|
||||
+int qca8k_port_mdb_del(struct dsa_switch *ds, int port,
|
||||
+ const struct switchdev_obj_port_mdb *mdb)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ const u8 *addr = mdb->addr;
|
||||
+ u16 vid = mdb->vid;
|
||||
+
|
||||
+ return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid);
|
||||
+}
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -430,11 +430,9 @@ int qca8k_read(struct qca8k_priv *priv,
|
||||
int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val);
|
||||
int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val);
|
||||
|
||||
-int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len);
|
||||
-int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len);
|
||||
-
|
||||
/* Common ops function */
|
||||
int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask);
|
||||
+void qca8k_fdb_flush(struct qca8k_priv *priv);
|
||||
|
||||
/* Common ethtool stats function */
|
||||
void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data);
|
||||
@@ -463,6 +461,23 @@ int qca8k_port_change_mtu(struct dsa_swi
|
||||
int qca8k_port_max_mtu(struct dsa_switch *ds, int port);
|
||||
|
||||
/* Common fast age function */
|
||||
+void qca8k_port_fast_age(struct dsa_switch *ds, int port);
|
||||
int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs);
|
||||
|
||||
+/* Common FDB function */
|
||||
+int qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr,
|
||||
+ u16 port_mask, u16 vid);
|
||||
+int qca8k_port_fdb_add(struct dsa_switch *ds, int port,
|
||||
+ const unsigned char *addr, u16 vid);
|
||||
+int qca8k_port_fdb_del(struct dsa_switch *ds, int port,
|
||||
+ const unsigned char *addr, u16 vid);
|
||||
+int qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
|
||||
+ dsa_fdb_dump_cb_t *cb, void *data);
|
||||
+
|
||||
+/* Common MDB function */
|
||||
+int qca8k_port_mdb_add(struct dsa_switch *ds, int port,
|
||||
+ const struct switchdev_obj_port_mdb *mdb);
|
||||
+int qca8k_port_mdb_del(struct dsa_switch *ds, int port,
|
||||
+ const struct switchdev_obj_port_mdb *mdb);
|
||||
+
|
||||
#endif /* __QCA8K_H */
|
@@ -0,0 +1,232 @@
|
||||
From 742d37a84d3f7bb60d9b2d9ada9ad4e599f65ebf Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 27 Jul 2022 13:35:20 +0200
|
||||
Subject: [PATCH 11/14] net: dsa: qca8k: move port mirror functions to common
|
||||
code
|
||||
|
||||
The same port mirror functions are used by drivers based on qca8k family
|
||||
switch. Move them to common code to make them accessible also by other
|
||||
drivers.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 93 ------------------------------
|
||||
drivers/net/dsa/qca/qca8k-common.c | 91 +++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca/qca8k.h | 7 +++
|
||||
3 files changed, 98 insertions(+), 93 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -1838,99 +1838,6 @@ exit:
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
- struct dsa_mall_mirror_tc_entry *mirror,
|
||||
- bool ingress)
|
||||
-{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
- int monitor_port, ret;
|
||||
- u32 reg, val;
|
||||
-
|
||||
- /* Check for existent entry */
|
||||
- if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
|
||||
- return -EEXIST;
|
||||
-
|
||||
- ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- /* QCA83xx can have only one port set to mirror mode.
|
||||
- * Check that the correct port is requested and return error otherwise.
|
||||
- * When no mirror port is set, the values is set to 0xF
|
||||
- */
|
||||
- monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
|
||||
- if (monitor_port != 0xF && monitor_port != mirror->to_local_port)
|
||||
- return -EEXIST;
|
||||
-
|
||||
- /* Set the monitor port */
|
||||
- val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM,
|
||||
- mirror->to_local_port);
|
||||
- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
|
||||
- QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- if (ingress) {
|
||||
- reg = QCA8K_PORT_LOOKUP_CTRL(port);
|
||||
- val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN;
|
||||
- } else {
|
||||
- reg = QCA8K_REG_PORT_HOL_CTRL1(port);
|
||||
- val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN;
|
||||
- }
|
||||
-
|
||||
- ret = regmap_update_bits(priv->regmap, reg, val, val);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- /* Track mirror port for tx and rx to decide when the
|
||||
- * mirror port has to be disabled.
|
||||
- */
|
||||
- if (ingress)
|
||||
- priv->mirror_rx |= BIT(port);
|
||||
- else
|
||||
- priv->mirror_tx |= BIT(port);
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static void
|
||||
-qca8k_port_mirror_del(struct dsa_switch *ds, int port,
|
||||
- struct dsa_mall_mirror_tc_entry *mirror)
|
||||
-{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
- u32 reg, val;
|
||||
- int ret;
|
||||
-
|
||||
- if (mirror->ingress) {
|
||||
- reg = QCA8K_PORT_LOOKUP_CTRL(port);
|
||||
- val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN;
|
||||
- } else {
|
||||
- reg = QCA8K_REG_PORT_HOL_CTRL1(port);
|
||||
- val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN;
|
||||
- }
|
||||
-
|
||||
- ret = regmap_clear_bits(priv->regmap, reg, val);
|
||||
- if (ret)
|
||||
- goto err;
|
||||
-
|
||||
- if (mirror->ingress)
|
||||
- priv->mirror_rx &= ~BIT(port);
|
||||
- else
|
||||
- priv->mirror_tx &= ~BIT(port);
|
||||
-
|
||||
- /* No port set to send packet to mirror port. Disable mirror port */
|
||||
- if (!priv->mirror_rx && !priv->mirror_tx) {
|
||||
- val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF);
|
||||
- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
|
||||
- QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
|
||||
- if (ret)
|
||||
- goto err;
|
||||
- }
|
||||
-err:
|
||||
- dev_err(priv->dev, "Failed to del mirror port from %d", port);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||||
@@ -741,3 +741,94 @@ int qca8k_port_mdb_del(struct dsa_switch
|
||||
|
||||
return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid);
|
||||
}
|
||||
+
|
||||
+int qca8k_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
+ struct dsa_mall_mirror_tc_entry *mirror,
|
||||
+ bool ingress)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ int monitor_port, ret;
|
||||
+ u32 reg, val;
|
||||
+
|
||||
+ /* Check for existent entry */
|
||||
+ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
|
||||
+ return -EEXIST;
|
||||
+
|
||||
+ ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* QCA83xx can have only one port set to mirror mode.
|
||||
+ * Check that the correct port is requested and return error otherwise.
|
||||
+ * When no mirror port is set, the values is set to 0xF
|
||||
+ */
|
||||
+ monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
|
||||
+ if (monitor_port != 0xF && monitor_port != mirror->to_local_port)
|
||||
+ return -EEXIST;
|
||||
+
|
||||
+ /* Set the monitor port */
|
||||
+ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM,
|
||||
+ mirror->to_local_port);
|
||||
+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
|
||||
+ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (ingress) {
|
||||
+ reg = QCA8K_PORT_LOOKUP_CTRL(port);
|
||||
+ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN;
|
||||
+ } else {
|
||||
+ reg = QCA8K_REG_PORT_HOL_CTRL1(port);
|
||||
+ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN;
|
||||
+ }
|
||||
+
|
||||
+ ret = regmap_update_bits(priv->regmap, reg, val, val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Track mirror port for tx and rx to decide when the
|
||||
+ * mirror port has to be disabled.
|
||||
+ */
|
||||
+ if (ingress)
|
||||
+ priv->mirror_rx |= BIT(port);
|
||||
+ else
|
||||
+ priv->mirror_tx |= BIT(port);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void qca8k_port_mirror_del(struct dsa_switch *ds, int port,
|
||||
+ struct dsa_mall_mirror_tc_entry *mirror)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ u32 reg, val;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (mirror->ingress) {
|
||||
+ reg = QCA8K_PORT_LOOKUP_CTRL(port);
|
||||
+ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN;
|
||||
+ } else {
|
||||
+ reg = QCA8K_REG_PORT_HOL_CTRL1(port);
|
||||
+ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN;
|
||||
+ }
|
||||
+
|
||||
+ ret = regmap_clear_bits(priv->regmap, reg, val);
|
||||
+ if (ret)
|
||||
+ goto err;
|
||||
+
|
||||
+ if (mirror->ingress)
|
||||
+ priv->mirror_rx &= ~BIT(port);
|
||||
+ else
|
||||
+ priv->mirror_tx &= ~BIT(port);
|
||||
+
|
||||
+ /* No port set to send packet to mirror port. Disable mirror port */
|
||||
+ if (!priv->mirror_rx && !priv->mirror_tx) {
|
||||
+ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF);
|
||||
+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
|
||||
+ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
|
||||
+ if (ret)
|
||||
+ goto err;
|
||||
+ }
|
||||
+err:
|
||||
+ dev_err(priv->dev, "Failed to del mirror port from %d", port);
|
||||
+}
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -480,4 +480,11 @@ int qca8k_port_mdb_add(struct dsa_switch
|
||||
int qca8k_port_mdb_del(struct dsa_switch *ds, int port,
|
||||
const struct switchdev_obj_port_mdb *mdb);
|
||||
|
||||
+/* Common port mirror function */
|
||||
+int qca8k_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
+ struct dsa_mall_mirror_tc_entry *mirror,
|
||||
+ bool ingress);
|
||||
+void qca8k_port_mirror_del(struct dsa_switch *ds, int port,
|
||||
+ struct dsa_mall_mirror_tc_entry *mirror);
|
||||
+
|
||||
#endif /* __QCA8K_H */
|
@@ -0,0 +1,448 @@
|
||||
From c5290f636624b98e76a82bd63ffec0a8a9daa620 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 27 Jul 2022 13:35:21 +0200
|
||||
Subject: [PATCH 12/14] net: dsa: qca8k: move port VLAN functions to common
|
||||
code
|
||||
|
||||
The same port VLAN functions are used by drivers based on qca8k family
|
||||
switch. Move them to common code to make them accessible also by other
|
||||
drivers.
|
||||
Also drop exposing busy_wait and make it static.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 182 -----------------------------
|
||||
drivers/net/dsa/qca/qca8k-common.c | 179 +++++++++++++++++++++++++++-
|
||||
drivers/net/dsa/qca/qca8k.h | 10 +-
|
||||
3 files changed, 187 insertions(+), 184 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/of_mdio.h>
|
||||
#include <linux/of_platform.h>
|
||||
-#include <linux/if_bridge.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
@@ -442,122 +441,6 @@ static struct regmap_config qca8k_regmap
|
||||
};
|
||||
|
||||
static int
|
||||
-qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid)
|
||||
-{
|
||||
- u32 reg;
|
||||
- int ret;
|
||||
-
|
||||
- /* Set the command and VLAN index */
|
||||
- reg = QCA8K_VTU_FUNC1_BUSY;
|
||||
- reg |= cmd;
|
||||
- reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid);
|
||||
-
|
||||
- /* Write the function register triggering the table access */
|
||||
- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- /* wait for completion */
|
||||
- ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- /* Check for table full violation when adding an entry */
|
||||
- if (cmd == QCA8K_VLAN_LOAD) {
|
||||
- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®);
|
||||
- if (ret < 0)
|
||||
- return ret;
|
||||
- if (reg & QCA8K_VTU_FUNC1_FULL)
|
||||
- return -ENOMEM;
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged)
|
||||
-{
|
||||
- u32 reg;
|
||||
- int ret;
|
||||
-
|
||||
- /*
|
||||
- We do the right thing with VLAN 0 and treat it as untagged while
|
||||
- preserving the tag on egress.
|
||||
- */
|
||||
- if (vid == 0)
|
||||
- return 0;
|
||||
-
|
||||
- mutex_lock(&priv->reg_mutex);
|
||||
- ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid);
|
||||
- if (ret < 0)
|
||||
- goto out;
|
||||
-
|
||||
- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®);
|
||||
- if (ret < 0)
|
||||
- goto out;
|
||||
- reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN;
|
||||
- reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port);
|
||||
- if (untagged)
|
||||
- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port);
|
||||
- else
|
||||
- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port);
|
||||
-
|
||||
- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
|
||||
- if (ret)
|
||||
- goto out;
|
||||
- ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid);
|
||||
-
|
||||
-out:
|
||||
- mutex_unlock(&priv->reg_mutex);
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid)
|
||||
-{
|
||||
- u32 reg, mask;
|
||||
- int ret, i;
|
||||
- bool del;
|
||||
-
|
||||
- mutex_lock(&priv->reg_mutex);
|
||||
- ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid);
|
||||
- if (ret < 0)
|
||||
- goto out;
|
||||
-
|
||||
- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®);
|
||||
- if (ret < 0)
|
||||
- goto out;
|
||||
- reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port);
|
||||
- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port);
|
||||
-
|
||||
- /* Check if we're the last member to be removed */
|
||||
- del = true;
|
||||
- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
- mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i);
|
||||
-
|
||||
- if ((reg & mask) != mask) {
|
||||
- del = false;
|
||||
- break;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (del) {
|
||||
- ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid);
|
||||
- } else {
|
||||
- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
|
||||
- if (ret)
|
||||
- goto out;
|
||||
- ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid);
|
||||
- }
|
||||
-
|
||||
-out:
|
||||
- mutex_unlock(&priv->reg_mutex);
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data,
|
||||
struct sk_buff *read_skb, u32 *val)
|
||||
{
|
||||
@@ -1836,71 +1719,6 @@ exit:
|
||||
|
||||
return ret;
|
||||
}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
|
||||
- struct netlink_ext_ack *extack)
|
||||
-{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
- int ret;
|
||||
-
|
||||
- if (vlan_filtering) {
|
||||
- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
- QCA8K_PORT_LOOKUP_VLAN_MODE_MASK,
|
||||
- QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE);
|
||||
- } else {
|
||||
- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
- QCA8K_PORT_LOOKUP_VLAN_MODE_MASK,
|
||||
- QCA8K_PORT_LOOKUP_VLAN_MODE_NONE);
|
||||
- }
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_vlan_add(struct dsa_switch *ds, int port,
|
||||
- const struct switchdev_obj_port_vlan *vlan,
|
||||
- struct netlink_ext_ack *extack)
|
||||
-{
|
||||
- bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
|
||||
- bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
- int ret;
|
||||
-
|
||||
- ret = qca8k_vlan_add(priv, port, vlan->vid, untagged);
|
||||
- if (ret) {
|
||||
- dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret);
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- if (pvid) {
|
||||
- ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port),
|
||||
- QCA8K_EGREES_VLAN_PORT_MASK(port),
|
||||
- QCA8K_EGREES_VLAN_PORT(port, vlan->vid));
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port),
|
||||
- QCA8K_PORT_VLAN_CVID(vlan->vid) |
|
||||
- QCA8K_PORT_VLAN_SVID(vlan->vid));
|
||||
- }
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_vlan_del(struct dsa_switch *ds, int port,
|
||||
- const struct switchdev_obj_port_vlan *vlan)
|
||||
-{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
- int ret;
|
||||
-
|
||||
- ret = qca8k_vlan_del(priv, port, vlan->vid);
|
||||
- if (ret)
|
||||
- dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret);
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
|
||||
static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port)
|
||||
{
|
||||
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||||
@@ -141,7 +141,7 @@ static int qca8k_bulk_write(struct qca8k
|
||||
return 0;
|
||||
}
|
||||
|
||||
-int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
|
||||
+static int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
@@ -354,6 +354,120 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int qca8k_vlan_access(struct qca8k_priv *priv,
|
||||
+ enum qca8k_vlan_cmd cmd, u16 vid)
|
||||
+{
|
||||
+ u32 reg;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Set the command and VLAN index */
|
||||
+ reg = QCA8K_VTU_FUNC1_BUSY;
|
||||
+ reg |= cmd;
|
||||
+ reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid);
|
||||
+
|
||||
+ /* Write the function register triggering the table access */
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* wait for completion */
|
||||
+ ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Check for table full violation when adding an entry */
|
||||
+ if (cmd == QCA8K_VLAN_LOAD) {
|
||||
+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ if (reg & QCA8K_VTU_FUNC1_FULL)
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid,
|
||||
+ bool untagged)
|
||||
+{
|
||||
+ u32 reg;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* We do the right thing with VLAN 0 and treat it as untagged while
|
||||
+ * preserving the tag on egress.
|
||||
+ */
|
||||
+ if (vid == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid);
|
||||
+ if (ret < 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®);
|
||||
+ if (ret < 0)
|
||||
+ goto out;
|
||||
+ reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN;
|
||||
+ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port);
|
||||
+ if (untagged)
|
||||
+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port);
|
||||
+ else
|
||||
+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port);
|
||||
+
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
|
||||
+ if (ret)
|
||||
+ goto out;
|
||||
+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid);
|
||||
+
|
||||
+out:
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid)
|
||||
+{
|
||||
+ u32 reg, mask;
|
||||
+ int ret, i;
|
||||
+ bool del;
|
||||
+
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid);
|
||||
+ if (ret < 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®);
|
||||
+ if (ret < 0)
|
||||
+ goto out;
|
||||
+ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port);
|
||||
+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port);
|
||||
+
|
||||
+ /* Check if we're the last member to be removed */
|
||||
+ del = true;
|
||||
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
+ mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i);
|
||||
+
|
||||
+ if ((reg & mask) != mask) {
|
||||
+ del = false;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (del) {
|
||||
+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid);
|
||||
+ } else {
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
|
||||
+ if (ret)
|
||||
+ goto out;
|
||||
+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid);
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
int qca8k_mib_init(struct qca8k_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
@@ -832,3 +946,66 @@ void qca8k_port_mirror_del(struct dsa_sw
|
||||
err:
|
||||
dev_err(priv->dev, "Failed to del mirror port from %d", port);
|
||||
}
|
||||
+
|
||||
+int qca8k_port_vlan_filtering(struct dsa_switch *ds, int port,
|
||||
+ bool vlan_filtering,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (vlan_filtering) {
|
||||
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
+ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK,
|
||||
+ QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE);
|
||||
+ } else {
|
||||
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
+ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK,
|
||||
+ QCA8K_PORT_LOOKUP_VLAN_MODE_NONE);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+int qca8k_port_vlan_add(struct dsa_switch *ds, int port,
|
||||
+ const struct switchdev_obj_port_vlan *vlan,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
|
||||
+ bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = qca8k_vlan_add(priv, port, vlan->vid, untagged);
|
||||
+ if (ret) {
|
||||
+ dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (pvid) {
|
||||
+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port),
|
||||
+ QCA8K_EGREES_VLAN_PORT_MASK(port),
|
||||
+ QCA8K_EGREES_VLAN_PORT(port, vlan->vid));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port),
|
||||
+ QCA8K_PORT_VLAN_CVID(vlan->vid) |
|
||||
+ QCA8K_PORT_VLAN_SVID(vlan->vid));
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+int qca8k_port_vlan_del(struct dsa_switch *ds, int port,
|
||||
+ const struct switchdev_obj_port_vlan *vlan)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = qca8k_vlan_del(priv, port, vlan->vid);
|
||||
+ if (ret)
|
||||
+ dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -431,7 +431,6 @@ int qca8k_write(struct qca8k_priv *priv,
|
||||
int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val);
|
||||
|
||||
/* Common ops function */
|
||||
-int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask);
|
||||
void qca8k_fdb_flush(struct qca8k_priv *priv);
|
||||
|
||||
/* Common ethtool stats function */
|
||||
@@ -487,4 +486,13 @@ int qca8k_port_mirror_add(struct dsa_swi
|
||||
void qca8k_port_mirror_del(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror);
|
||||
|
||||
+/* Common port VLAN function */
|
||||
+int qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
|
||||
+ struct netlink_ext_ack *extack);
|
||||
+int qca8k_port_vlan_add(struct dsa_switch *ds, int port,
|
||||
+ const struct switchdev_obj_port_vlan *vlan,
|
||||
+ struct netlink_ext_ack *extack);
|
||||
+int qca8k_port_vlan_del(struct dsa_switch *ds, int port,
|
||||
+ const struct switchdev_obj_port_vlan *vlan);
|
||||
+
|
||||
#endif /* __QCA8K_H */
|
@@ -0,0 +1,384 @@
|
||||
From e9bbf019af44b204b71ef8edf224002550aab641 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 27 Jul 2022 13:35:22 +0200
|
||||
Subject: [PATCH 13/14] net: dsa: qca8k: move port LAG functions to common code
|
||||
|
||||
The same port LAG functions are used by drivers based on qca8k family
|
||||
switch. Move them to common code to make them accessible also by other
|
||||
drivers.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 168 -----------------------------
|
||||
drivers/net/dsa/qca/qca8k-common.c | 165 ++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca/qca8k.h | 6 ++
|
||||
3 files changed, 171 insertions(+), 168 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -1743,178 +1743,6 @@ qca8k_get_tag_protocol(struct dsa_switch
|
||||
return DSA_TAG_PROTO_QCA;
|
||||
}
|
||||
|
||||
-static bool
|
||||
-qca8k_lag_can_offload(struct dsa_switch *ds,
|
||||
- struct net_device *lag,
|
||||
- struct netdev_lag_upper_info *info)
|
||||
-{
|
||||
- struct dsa_port *dp;
|
||||
- int id, members = 0;
|
||||
-
|
||||
- id = dsa_lag_id(ds->dst, lag);
|
||||
- if (id < 0 || id >= ds->num_lag_ids)
|
||||
- return false;
|
||||
-
|
||||
- dsa_lag_foreach_port(dp, ds->dst, lag)
|
||||
- /* Includes the port joining the LAG */
|
||||
- members++;
|
||||
-
|
||||
- if (members > QCA8K_NUM_PORTS_FOR_LAG)
|
||||
- return false;
|
||||
-
|
||||
- if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH)
|
||||
- return false;
|
||||
-
|
||||
- if (info->hash_type != NETDEV_LAG_HASH_L2 &&
|
||||
- info->hash_type != NETDEV_LAG_HASH_L23)
|
||||
- return false;
|
||||
-
|
||||
- return true;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_lag_setup_hash(struct dsa_switch *ds,
|
||||
- struct net_device *lag,
|
||||
- struct netdev_lag_upper_info *info)
|
||||
-{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
- bool unique_lag = true;
|
||||
- u32 hash = 0;
|
||||
- int i, id;
|
||||
-
|
||||
- id = dsa_lag_id(ds->dst, lag);
|
||||
-
|
||||
- switch (info->hash_type) {
|
||||
- case NETDEV_LAG_HASH_L23:
|
||||
- hash |= QCA8K_TRUNK_HASH_SIP_EN;
|
||||
- hash |= QCA8K_TRUNK_HASH_DIP_EN;
|
||||
- fallthrough;
|
||||
- case NETDEV_LAG_HASH_L2:
|
||||
- hash |= QCA8K_TRUNK_HASH_SA_EN;
|
||||
- hash |= QCA8K_TRUNK_HASH_DA_EN;
|
||||
- break;
|
||||
- default: /* We should NEVER reach this */
|
||||
- return -EOPNOTSUPP;
|
||||
- }
|
||||
-
|
||||
- /* Check if we are the unique configured LAG */
|
||||
- dsa_lags_foreach_id(i, ds->dst)
|
||||
- if (i != id && dsa_lag_dev(ds->dst, i)) {
|
||||
- unique_lag = false;
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- /* Hash Mode is global. Make sure the same Hash Mode
|
||||
- * is set to all the 4 possible lag.
|
||||
- * If we are the unique LAG we can set whatever hash
|
||||
- * mode we want.
|
||||
- * To change hash mode it's needed to remove all LAG
|
||||
- * and change the mode with the latest.
|
||||
- */
|
||||
- if (unique_lag) {
|
||||
- priv->lag_hash_mode = hash;
|
||||
- } else if (priv->lag_hash_mode != hash) {
|
||||
- netdev_err(lag, "Error: Mismateched Hash Mode across different lag is not supported\n");
|
||||
- return -EOPNOTSUPP;
|
||||
- }
|
||||
-
|
||||
- return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL,
|
||||
- QCA8K_TRUNK_HASH_MASK, hash);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port,
|
||||
- struct net_device *lag, bool delete)
|
||||
-{
|
||||
- struct qca8k_priv *priv = ds->priv;
|
||||
- int ret, id, i;
|
||||
- u32 val;
|
||||
-
|
||||
- id = dsa_lag_id(ds->dst, lag);
|
||||
-
|
||||
- /* Read current port member */
|
||||
- ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- /* Shift val to the correct trunk */
|
||||
- val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id);
|
||||
- val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK;
|
||||
- if (delete)
|
||||
- val &= ~BIT(port);
|
||||
- else
|
||||
- val |= BIT(port);
|
||||
-
|
||||
- /* Update port member. With empty portmap disable trunk */
|
||||
- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0,
|
||||
- QCA8K_REG_GOL_TRUNK_MEMBER(id) |
|
||||
- QCA8K_REG_GOL_TRUNK_EN(id),
|
||||
- !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) |
|
||||
- val << QCA8K_REG_GOL_TRUNK_SHIFT(id));
|
||||
-
|
||||
- /* Search empty member if adding or port on deleting */
|
||||
- for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) {
|
||||
- ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i);
|
||||
- val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK;
|
||||
-
|
||||
- if (delete) {
|
||||
- /* If port flagged to be disabled assume this member is
|
||||
- * empty
|
||||
- */
|
||||
- if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK)
|
||||
- continue;
|
||||
-
|
||||
- val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK;
|
||||
- if (val != port)
|
||||
- continue;
|
||||
- } else {
|
||||
- /* If port flagged to be enabled assume this member is
|
||||
- * already set
|
||||
- */
|
||||
- if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK)
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- /* We have found the member to add/remove */
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- /* Set port in the correct port mask or disable port if in delete mode */
|
||||
- return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id),
|
||||
- QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) |
|
||||
- QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i),
|
||||
- !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) |
|
||||
- port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i));
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_lag_join(struct dsa_switch *ds, int port,
|
||||
- struct net_device *lag,
|
||||
- struct netdev_lag_upper_info *info)
|
||||
-{
|
||||
- int ret;
|
||||
-
|
||||
- if (!qca8k_lag_can_offload(ds, lag, info))
|
||||
- return -EOPNOTSUPP;
|
||||
-
|
||||
- ret = qca8k_lag_setup_hash(ds, lag, info);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- return qca8k_lag_refresh_portmap(ds, port, lag, false);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_port_lag_leave(struct dsa_switch *ds, int port,
|
||||
- struct net_device *lag)
|
||||
-{
|
||||
- return qca8k_lag_refresh_portmap(ds, port, lag, true);
|
||||
-}
|
||||
-
|
||||
static void
|
||||
qca8k_master_change(struct dsa_switch *ds, const struct net_device *master,
|
||||
bool operational)
|
||||
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||||
@@ -1009,3 +1009,169 @@ int qca8k_port_vlan_del(struct dsa_switc
|
||||
|
||||
return ret;
|
||||
}
|
||||
+
|
||||
+static bool qca8k_lag_can_offload(struct dsa_switch *ds,
|
||||
+ struct net_device *lag,
|
||||
+ struct netdev_lag_upper_info *info)
|
||||
+{
|
||||
+ struct dsa_port *dp;
|
||||
+ int id, members = 0;
|
||||
+
|
||||
+ id = dsa_lag_id(ds->dst, lag);
|
||||
+ if (id < 0 || id >= ds->num_lag_ids)
|
||||
+ return false;
|
||||
+
|
||||
+ dsa_lag_foreach_port(dp, ds->dst, lag)
|
||||
+ /* Includes the port joining the LAG */
|
||||
+ members++;
|
||||
+
|
||||
+ if (members > QCA8K_NUM_PORTS_FOR_LAG)
|
||||
+ return false;
|
||||
+
|
||||
+ if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH)
|
||||
+ return false;
|
||||
+
|
||||
+ if (info->hash_type != NETDEV_LAG_HASH_L2 &&
|
||||
+ info->hash_type != NETDEV_LAG_HASH_L23)
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static int qca8k_lag_setup_hash(struct dsa_switch *ds,
|
||||
+ struct net_device *lag,
|
||||
+ struct netdev_lag_upper_info *info)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ bool unique_lag = true;
|
||||
+ u32 hash = 0;
|
||||
+ int i, id;
|
||||
+
|
||||
+ id = dsa_lag_id(ds->dst, lag);
|
||||
+
|
||||
+ switch (info->hash_type) {
|
||||
+ case NETDEV_LAG_HASH_L23:
|
||||
+ hash |= QCA8K_TRUNK_HASH_SIP_EN;
|
||||
+ hash |= QCA8K_TRUNK_HASH_DIP_EN;
|
||||
+ fallthrough;
|
||||
+ case NETDEV_LAG_HASH_L2:
|
||||
+ hash |= QCA8K_TRUNK_HASH_SA_EN;
|
||||
+ hash |= QCA8K_TRUNK_HASH_DA_EN;
|
||||
+ break;
|
||||
+ default: /* We should NEVER reach this */
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
+
|
||||
+ /* Check if we are the unique configured LAG */
|
||||
+ dsa_lags_foreach_id(i, ds->dst)
|
||||
+ if (i != id && dsa_lag_dev(ds->dst, i)) {
|
||||
+ unique_lag = false;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* Hash Mode is global. Make sure the same Hash Mode
|
||||
+ * is set to all the 4 possible lag.
|
||||
+ * If we are the unique LAG we can set whatever hash
|
||||
+ * mode we want.
|
||||
+ * To change hash mode it's needed to remove all LAG
|
||||
+ * and change the mode with the latest.
|
||||
+ */
|
||||
+ if (unique_lag) {
|
||||
+ priv->lag_hash_mode = hash;
|
||||
+ } else if (priv->lag_hash_mode != hash) {
|
||||
+ netdev_err(lag, "Error: Mismatched Hash Mode across different lag is not supported\n");
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
+
|
||||
+ return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL,
|
||||
+ QCA8K_TRUNK_HASH_MASK, hash);
|
||||
+}
|
||||
+
|
||||
+static int qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port,
|
||||
+ struct net_device *lag, bool delete)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ int ret, id, i;
|
||||
+ u32 val;
|
||||
+
|
||||
+ id = dsa_lag_id(ds->dst, lag);
|
||||
+
|
||||
+ /* Read current port member */
|
||||
+ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Shift val to the correct trunk */
|
||||
+ val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id);
|
||||
+ val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK;
|
||||
+ if (delete)
|
||||
+ val &= ~BIT(port);
|
||||
+ else
|
||||
+ val |= BIT(port);
|
||||
+
|
||||
+ /* Update port member. With empty portmap disable trunk */
|
||||
+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0,
|
||||
+ QCA8K_REG_GOL_TRUNK_MEMBER(id) |
|
||||
+ QCA8K_REG_GOL_TRUNK_EN(id),
|
||||
+ !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) |
|
||||
+ val << QCA8K_REG_GOL_TRUNK_SHIFT(id));
|
||||
+
|
||||
+ /* Search empty member if adding or port on deleting */
|
||||
+ for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) {
|
||||
+ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i);
|
||||
+ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK;
|
||||
+
|
||||
+ if (delete) {
|
||||
+ /* If port flagged to be disabled assume this member is
|
||||
+ * empty
|
||||
+ */
|
||||
+ if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK)
|
||||
+ continue;
|
||||
+
|
||||
+ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK;
|
||||
+ if (val != port)
|
||||
+ continue;
|
||||
+ } else {
|
||||
+ /* If port flagged to be enabled assume this member is
|
||||
+ * already set
|
||||
+ */
|
||||
+ if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK)
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* We have found the member to add/remove */
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* Set port in the correct port mask or disable port if in delete mode */
|
||||
+ return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id),
|
||||
+ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) |
|
||||
+ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i),
|
||||
+ !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) |
|
||||
+ port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i));
|
||||
+}
|
||||
+
|
||||
+int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct net_device *lag,
|
||||
+ struct netdev_lag_upper_info *info)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!qca8k_lag_can_offload(ds, lag, info))
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
+ ret = qca8k_lag_setup_hash(ds, lag, info);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return qca8k_lag_refresh_portmap(ds, port, lag, false);
|
||||
+}
|
||||
+
|
||||
+int qca8k_port_lag_leave(struct dsa_switch *ds, int port,
|
||||
+ struct net_device *lag)
|
||||
+{
|
||||
+ return qca8k_lag_refresh_portmap(ds, port, lag, true);
|
||||
+}
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -495,4 +495,10 @@ int qca8k_port_vlan_add(struct dsa_switc
|
||||
int qca8k_port_vlan_del(struct dsa_switch *ds, int port,
|
||||
const struct switchdev_obj_port_vlan *vlan);
|
||||
|
||||
+/* Common port LAG function */
|
||||
+int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct net_device *lag,
|
||||
+ struct netdev_lag_upper_info *info);
|
||||
+int qca8k_port_lag_leave(struct dsa_switch *ds, int port,
|
||||
+ struct net_device *lag);
|
||||
+
|
||||
#endif /* __QCA8K_H */
|
@@ -0,0 +1,102 @@
|
||||
From 9d1bcb1f293f1391302a109c9819c3705c804700 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 27 Jul 2022 13:35:23 +0200
|
||||
Subject: [PATCH 14/14] net: dsa: qca8k: move read_switch_id function to common
|
||||
code
|
||||
|
||||
The same function to read the switch id is used by drivers based on
|
||||
qca8k family switch. Move them to common code to make them accessible
|
||||
also by other drivers.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 29 -----------------------------
|
||||
drivers/net/dsa/qca/qca8k-common.c | 29 +++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca/qca8k.h | 1 +
|
||||
3 files changed, 30 insertions(+), 29 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -1822,35 +1822,6 @@ static const struct dsa_switch_ops qca8k
|
||||
.connect_tag_protocol = qca8k_connect_tag_protocol,
|
||||
};
|
||||
|
||||
-static int qca8k_read_switch_id(struct qca8k_priv *priv)
|
||||
-{
|
||||
- u32 val;
|
||||
- u8 id;
|
||||
- int ret;
|
||||
-
|
||||
- if (!priv->info)
|
||||
- return -ENODEV;
|
||||
-
|
||||
- ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val);
|
||||
- if (ret < 0)
|
||||
- return -ENODEV;
|
||||
-
|
||||
- id = QCA8K_MASK_CTRL_DEVICE_ID(val);
|
||||
- if (id != priv->info->id) {
|
||||
- dev_err(priv->dev,
|
||||
- "Switch id detected %x but expected %x",
|
||||
- id, priv->info->id);
|
||||
- return -ENODEV;
|
||||
- }
|
||||
-
|
||||
- priv->switch_id = id;
|
||||
-
|
||||
- /* Save revision to communicate to the internal PHY driver */
|
||||
- priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val);
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
static int
|
||||
qca8k_sw_probe(struct mdio_device *mdiodev)
|
||||
{
|
||||
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||||
@@ -1175,3 +1175,32 @@ int qca8k_port_lag_leave(struct dsa_swit
|
||||
{
|
||||
return qca8k_lag_refresh_portmap(ds, port, lag, true);
|
||||
}
|
||||
+
|
||||
+int qca8k_read_switch_id(struct qca8k_priv *priv)
|
||||
+{
|
||||
+ u32 val;
|
||||
+ u8 id;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!priv->info)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val);
|
||||
+ if (ret < 0)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ id = QCA8K_MASK_CTRL_DEVICE_ID(val);
|
||||
+ if (id != priv->info->id) {
|
||||
+ dev_err(priv->dev,
|
||||
+ "Switch id detected %x but expected %x",
|
||||
+ id, priv->info->id);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ priv->switch_id = id;
|
||||
+
|
||||
+ /* Save revision to communicate to the internal PHY driver */
|
||||
+ priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -424,6 +424,7 @@ extern const struct qca8k_mib_desc ar832
|
||||
extern const struct regmap_access_table qca8k_readable_table;
|
||||
int qca8k_mib_init(struct qca8k_priv *priv);
|
||||
void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable);
|
||||
+int qca8k_read_switch_id(struct qca8k_priv *priv);
|
||||
|
||||
/* Common read/write/rmw function */
|
||||
int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val);
|
@@ -0,0 +1,29 @@
|
||||
From 057bcf15db8e625276ddf02b2b7c668a3cb43f81 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Sun, 4 Sep 2022 23:46:24 +0200
|
||||
Subject: [net PATCH] net: dsa: qca8k: fix NULL pointer dereference for
|
||||
of_device_get_match_data
|
||||
|
||||
of_device_get_match_data is called on priv->dev before priv->dev is
|
||||
actually set. Move of_device_get_match_data after priv->dev is correctly
|
||||
set to fix this kernel panic.
|
||||
|
||||
Fixes: 3bb0844e7bcd ("net: dsa: qca8k: cache match data to speed up access")
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -1835,9 +1835,9 @@ qca8k_sw_probe(struct mdio_device *mdiod
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
- priv->info = of_device_get_match_data(priv->dev);
|
||||
priv->bus = mdiodev->bus;
|
||||
priv->dev = &mdiodev->dev;
|
||||
+ priv->info = of_device_get_match_data(priv->dev);
|
||||
|
||||
priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset",
|
||||
GPIOD_ASIS);
|
@@ -68,8 +68,8 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o
|
||||
+obj-$(CONFIG_NET_DSA_MT7530_MDIO) += mt7530-mdio.o
|
||||
obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
|
||||
obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o
|
||||
obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o
|
||||
realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/dsa/mt7530-mdio.c
|
||||
@@ -0,0 +1,271 @@
|
||||
|
@@ -76,8 +76,8 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
obj-$(CONFIG_NET_DSA_MT7530_MDIO) += mt7530-mdio.o
|
||||
+obj-$(CONFIG_NET_DSA_MT7530_MMIO) += mt7530-mmio.o
|
||||
obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
|
||||
obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o
|
||||
obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o
|
||||
realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/dsa/mt7530-mmio.c
|
||||
@@ -0,0 +1,101 @@
|
||||
|
@@ -17,7 +17,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -756,6 +756,18 @@ static void phylink_resolve_flow(struct
|
||||
@@ -767,6 +767,18 @@ static void phylink_resolve_flow(struct
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
static void phylink_mac_config(struct phylink *pl,
|
||||
const struct phylink_link_state *state)
|
||||
{
|
||||
@@ -787,6 +799,7 @@ static void phylink_major_config(struct
|
||||
@@ -798,6 +810,7 @@ static void phylink_major_config(struct
|
||||
const struct phylink_link_state *state)
|
||||
{
|
||||
struct phylink_pcs *pcs = NULL;
|
||||
@@ -44,7 +44,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
int err;
|
||||
|
||||
phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
|
||||
@@ -799,8 +812,12 @@ static void phylink_major_config(struct
|
||||
@@ -810,8 +823,12 @@ static void phylink_major_config(struct
|
||||
pcs);
|
||||
return;
|
||||
}
|
||||
@@ -57,7 +57,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
if (pl->mac_ops->mac_prepare) {
|
||||
err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode,
|
||||
state->interface);
|
||||
@@ -814,8 +831,10 @@ static void phylink_major_config(struct
|
||||
@@ -825,8 +842,10 @@ static void phylink_major_config(struct
|
||||
/* If we have a new PCS, switch to the new PCS after preparing the MAC
|
||||
* for the change.
|
||||
*/
|
||||
@@ -70,7 +70,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
phylink_mac_config(pl, state);
|
||||
|
||||
@@ -841,6 +860,8 @@ static void phylink_major_config(struct
|
||||
@@ -852,6 +871,8 @@ static void phylink_major_config(struct
|
||||
phylink_err(pl, "mac_finish failed: %pe\n",
|
||||
ERR_PTR(err));
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -764,7 +764,7 @@ static void phylink_pcs_poll_stop(struct
|
||||
@@ -775,7 +775,7 @@ static void phylink_pcs_poll_stop(struct
|
||||
|
||||
static void phylink_pcs_poll_start(struct phylink *pl)
|
||||
{
|
||||
|
@@ -35,7 +35,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
bool mac_link_dropped;
|
||||
bool using_mac_select_pcs;
|
||||
@@ -795,6 +800,22 @@ static void phylink_mac_pcs_an_restart(s
|
||||
@@ -806,6 +811,22 @@ static void phylink_mac_pcs_an_restart(s
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
static void phylink_major_config(struct phylink *pl, bool restart,
|
||||
const struct phylink_link_state *state)
|
||||
{
|
||||
@@ -832,12 +853,16 @@ static void phylink_major_config(struct
|
||||
@@ -843,12 +864,16 @@ static void phylink_major_config(struct
|
||||
* for the change.
|
||||
*/
|
||||
if (pcs_changed) {
|
||||
@@ -75,7 +75,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
if (pl->pcs_ops) {
|
||||
err = pl->pcs_ops->pcs_config(pl->pcs, pl->cur_link_an_mode,
|
||||
state->interface,
|
||||
@@ -1260,6 +1285,7 @@ struct phylink *phylink_create(struct ph
|
||||
@@ -1272,6 +1297,7 @@ struct phylink *phylink_create(struct ph
|
||||
pl->link_config.speed = SPEED_UNKNOWN;
|
||||
pl->link_config.duplex = DUPLEX_UNKNOWN;
|
||||
pl->link_config.an_enabled = true;
|
||||
@@ -83,7 +83,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
pl->mac_ops = mac_ops;
|
||||
__set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
|
||||
timer_setup(&pl->link_poll, phylink_fixed_poll, 0);
|
||||
@@ -1651,6 +1677,8 @@ void phylink_start(struct phylink *pl)
|
||||
@@ -1663,6 +1689,8 @@ void phylink_start(struct phylink *pl)
|
||||
if (pl->netdev)
|
||||
netif_carrier_off(pl->netdev);
|
||||
|
||||
@@ -92,7 +92,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
/* Apply the link configuration to the MAC when starting. This allows
|
||||
* a fixed-link to start with the correct parameters, and also
|
||||
* ensures that we set the appropriate advertisement for Serdes links.
|
||||
@@ -1661,6 +1689,8 @@ void phylink_start(struct phylink *pl)
|
||||
@@ -1673,6 +1701,8 @@ void phylink_start(struct phylink *pl)
|
||||
*/
|
||||
phylink_mac_initial_config(pl, true);
|
||||
|
||||
@@ -101,7 +101,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
|
||||
phylink_run_resolve(pl);
|
||||
|
||||
@@ -1680,16 +1710,9 @@ void phylink_start(struct phylink *pl)
|
||||
@@ -1692,16 +1722,9 @@ void phylink_start(struct phylink *pl)
|
||||
poll = true;
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
if (poll)
|
||||
mod_timer(&pl->link_poll, jiffies + HZ);
|
||||
if (pl->phydev)
|
||||
@@ -1726,6 +1749,10 @@ void phylink_stop(struct phylink *pl)
|
||||
@@ -1738,6 +1761,10 @@ void phylink_stop(struct phylink *pl)
|
||||
}
|
||||
|
||||
phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_STOPPED);
|
||||
|
@@ -0,0 +1,39 @@
|
||||
From 156a5bb89ca6f3edd2be0bfd0de15e575442927e Mon Sep 17 00:00:00 2001
|
||||
From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
Date: Tue, 3 Jan 2023 15:12:47 +0200
|
||||
Subject: [PATCH] leds: Move led_init_default_state_get() to the global header
|
||||
|
||||
There are users inside and outside LED framework that have implemented
|
||||
a local copy of led_init_default_state_get(). In order to deduplicate
|
||||
that, as the first step move the declaration from LED header to the
|
||||
global one.
|
||||
|
||||
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
Signed-off-by: Lee Jones <lee@kernel.org>
|
||||
Link: https://lore.kernel.org/r/20230103131256.33894-3-andriy.shevchenko@linux.intel.com
|
||||
---
|
||||
drivers/leds/leds.h | 1 -
|
||||
include/linux/leds.h | 2 ++
|
||||
2 files changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/leds/leds.h
|
||||
+++ b/drivers/leds/leds.h
|
||||
@@ -27,7 +27,6 @@ ssize_t led_trigger_read(struct file *fi
|
||||
ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr, char *buf,
|
||||
loff_t pos, size_t count);
|
||||
-enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode);
|
||||
|
||||
extern struct rw_semaphore leds_list_lock;
|
||||
extern struct list_head leds_list;
|
||||
--- a/include/linux/leds.h
|
||||
+++ b/include/linux/leds.h
|
||||
@@ -63,6 +63,8 @@ struct led_init_data {
|
||||
bool devname_mandatory;
|
||||
};
|
||||
|
||||
+enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode);
|
||||
+
|
||||
struct led_hw_trigger_type {
|
||||
int dummy;
|
||||
};
|
@@ -0,0 +1,67 @@
|
||||
From 3e8b4d6277fd19d98c817576954dd6a4ff3caa2b Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 17 Apr 2023 17:17:23 +0200
|
||||
Subject: [PATCH 1/9] net: dsa: qca8k: move qca8k_port_to_phy() to header
|
||||
|
||||
Move qca8k_port_to_phy() to qca8k header as it's useful for future
|
||||
reference in Switch LEDs module since the same logic is applied to get
|
||||
the right index of the switch port.
|
||||
Make it inline as it's simple function that just decrease the port.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Reviewed-by: Michal Kubiak <michal.kubiak@intel.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 15 ---------------
|
||||
drivers/net/dsa/qca/qca8k.h | 14 ++++++++++++++
|
||||
2 files changed, 14 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -633,21 +633,6 @@ err_clear_skb:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static u32
|
||||
-qca8k_port_to_phy(int port)
|
||||
-{
|
||||
- /* From Andrew Lunn:
|
||||
- * Port 0 has no internal phy.
|
||||
- * Port 1 has an internal PHY at MDIO address 0.
|
||||
- * Port 2 has an internal PHY at MDIO address 1.
|
||||
- * ...
|
||||
- * Port 5 has an internal PHY at MDIO address 4.
|
||||
- * Port 6 has no internal PHY.
|
||||
- */
|
||||
-
|
||||
- return port - 1;
|
||||
-}
|
||||
-
|
||||
static int
|
||||
qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask)
|
||||
{
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -419,6 +419,20 @@ struct qca8k_fdb {
|
||||
u8 mac[6];
|
||||
};
|
||||
|
||||
+static inline u32 qca8k_port_to_phy(int port)
|
||||
+{
|
||||
+ /* From Andrew Lunn:
|
||||
+ * Port 0 has no internal phy.
|
||||
+ * Port 1 has an internal PHY at MDIO address 0.
|
||||
+ * Port 2 has an internal PHY at MDIO address 1.
|
||||
+ * ...
|
||||
+ * Port 5 has an internal PHY at MDIO address 4.
|
||||
+ * Port 6 has no internal PHY.
|
||||
+ */
|
||||
+
|
||||
+ return port - 1;
|
||||
+}
|
||||
+
|
||||
/* Common setup function */
|
||||
extern const struct qca8k_mib_desc ar8327_mib[];
|
||||
extern const struct regmap_access_table qca8k_readable_table;
|
@@ -0,0 +1,435 @@
|
||||
From 1e264f9d2918b5737023c44a23ae04def1095210 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 17 Apr 2023 17:17:24 +0200
|
||||
Subject: [PATCH 2/9] net: dsa: qca8k: add LEDs basic support
|
||||
|
||||
Add LEDs basic support for qca8k Switch Family by adding basic
|
||||
brightness_set() support.
|
||||
|
||||
Since these LEDs refelect port status, the default label is set to
|
||||
":port". DT binding should describe the color and function of the
|
||||
LEDs using standard LEDs api.
|
||||
Each LED always have the device name as prefix. The device name is
|
||||
composed from the mii bus id and the PHY addr resulting in example
|
||||
names like:
|
||||
- qca8k-0.0:00:amber:lan
|
||||
- qca8k-0.0:00:white:lan
|
||||
- qca8k-0.0:01:amber:lan
|
||||
- qca8k-0.0:01:white:lan
|
||||
|
||||
These LEDs supports only blocking variant of the brightness_set()
|
||||
function since they can sleep during access of the switch leds to set
|
||||
the brightness.
|
||||
|
||||
While at it add to the qca8k header file each mode defined by the Switch
|
||||
Documentation for future use.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca/Kconfig | 8 ++
|
||||
drivers/net/dsa/qca/Makefile | 3 +
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 5 +
|
||||
drivers/net/dsa/qca/qca8k-leds.c | 239 +++++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca/qca8k.h | 60 ++++++++
|
||||
drivers/net/dsa/qca/qca8k_leds.h | 16 +++
|
||||
6 files changed, 331 insertions(+)
|
||||
create mode 100644 drivers/net/dsa/qca/qca8k-leds.c
|
||||
create mode 100644 drivers/net/dsa/qca/qca8k_leds.h
|
||||
|
||||
--- a/drivers/net/dsa/qca/Kconfig
|
||||
+++ b/drivers/net/dsa/qca/Kconfig
|
||||
@@ -15,3 +15,11 @@ config NET_DSA_QCA8K
|
||||
help
|
||||
This enables support for the Qualcomm Atheros QCA8K Ethernet
|
||||
switch chips.
|
||||
+
|
||||
+config NET_DSA_QCA8K_LEDS_SUPPORT
|
||||
+ bool "Qualcomm Atheros QCA8K Ethernet switch family LEDs support"
|
||||
+ depends on NET_DSA_QCA8K
|
||||
+ depends on LEDS_CLASS
|
||||
+ help
|
||||
+ This enabled support for LEDs present on the Qualcomm Atheros
|
||||
+ QCA8K Ethernet switch chips.
|
||||
--- a/drivers/net/dsa/qca/Makefile
|
||||
+++ b/drivers/net/dsa/qca/Makefile
|
||||
@@ -2,3 +2,6 @@
|
||||
obj-$(CONFIG_NET_DSA_AR9331) += ar9331.o
|
||||
obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o
|
||||
qca8k-y += qca8k-common.o qca8k-8xxx.o
|
||||
+ifdef CONFIG_NET_DSA_QCA8K_LEDS_SUPPORT
|
||||
+qca8k-y += qca8k-leds.o
|
||||
+endif
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/dsa/tag_qca.h>
|
||||
|
||||
#include "qca8k.h"
|
||||
+#include "qca8k_leds.h"
|
||||
|
||||
static void
|
||||
qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
|
||||
@@ -1102,6 +1103,10 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ ret = qca8k_setup_led_ctrl(priv);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
/* Make sure MAC06 is disabled */
|
||||
ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL,
|
||||
QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN);
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/dsa/qca/qca8k-leds.c
|
||||
@@ -0,0 +1,239 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+#include <linux/regmap.h>
|
||||
+#include <net/dsa.h>
|
||||
+
|
||||
+#include "qca8k.h"
|
||||
+#include "qca8k_leds.h"
|
||||
+
|
||||
+static int
|
||||
+qca8k_get_enable_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info)
|
||||
+{
|
||||
+ switch (port_num) {
|
||||
+ case 0:
|
||||
+ reg_info->reg = QCA8K_LED_CTRL_REG(led_num);
|
||||
+ reg_info->shift = QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT;
|
||||
+ break;
|
||||
+ case 1:
|
||||
+ case 2:
|
||||
+ case 3:
|
||||
+ /* Port 123 are controlled on a different reg */
|
||||
+ reg_info->reg = QCA8K_LED_CTRL3_REG;
|
||||
+ reg_info->shift = QCA8K_LED_PHY123_PATTERN_EN_SHIFT(port_num, led_num);
|
||||
+ break;
|
||||
+ case 4:
|
||||
+ reg_info->reg = QCA8K_LED_CTRL_REG(led_num);
|
||||
+ reg_info->shift = QCA8K_LED_PHY4_CONTROL_RULE_SHIFT;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_led_brightness_set(struct qca8k_led *led,
|
||||
+ enum led_brightness brightness)
|
||||
+{
|
||||
+ struct qca8k_led_pattern_en reg_info;
|
||||
+ struct qca8k_priv *priv = led->priv;
|
||||
+ u32 mask, val;
|
||||
+
|
||||
+ qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info);
|
||||
+
|
||||
+ val = QCA8K_LED_ALWAYS_OFF;
|
||||
+ if (brightness)
|
||||
+ val = QCA8K_LED_ALWAYS_ON;
|
||||
+
|
||||
+ /* HW regs to control brightness is special and port 1-2-3
|
||||
+ * are placed in a different reg.
|
||||
+ *
|
||||
+ * To control port 0 brightness:
|
||||
+ * - the 2 bit (15, 14) of:
|
||||
+ * - QCA8K_LED_CTRL0_REG for led1
|
||||
+ * - QCA8K_LED_CTRL1_REG for led2
|
||||
+ * - QCA8K_LED_CTRL2_REG for led3
|
||||
+ *
|
||||
+ * To control port 4:
|
||||
+ * - the 2 bit (31, 30) of:
|
||||
+ * - QCA8K_LED_CTRL0_REG for led1
|
||||
+ * - QCA8K_LED_CTRL1_REG for led2
|
||||
+ * - QCA8K_LED_CTRL2_REG for led3
|
||||
+ *
|
||||
+ * To control port 1:
|
||||
+ * - the 2 bit at (9, 8) of QCA8K_LED_CTRL3_REG are used for led1
|
||||
+ * - the 2 bit at (11, 10) of QCA8K_LED_CTRL3_REG are used for led2
|
||||
+ * - the 2 bit at (13, 12) of QCA8K_LED_CTRL3_REG are used for led3
|
||||
+ *
|
||||
+ * To control port 2:
|
||||
+ * - the 2 bit at (15, 14) of QCA8K_LED_CTRL3_REG are used for led1
|
||||
+ * - the 2 bit at (17, 16) of QCA8K_LED_CTRL3_REG are used for led2
|
||||
+ * - the 2 bit at (19, 18) of QCA8K_LED_CTRL3_REG are used for led3
|
||||
+ *
|
||||
+ * To control port 3:
|
||||
+ * - the 2 bit at (21, 20) of QCA8K_LED_CTRL3_REG are used for led1
|
||||
+ * - the 2 bit at (23, 22) of QCA8K_LED_CTRL3_REG are used for led2
|
||||
+ * - the 2 bit at (25, 24) of QCA8K_LED_CTRL3_REG are used for led3
|
||||
+ *
|
||||
+ * To abstract this and have less code, we use the port and led numm
|
||||
+ * to calculate the shift and the correct reg due to this problem of
|
||||
+ * not having a 1:1 map of LED with the regs.
|
||||
+ */
|
||||
+ if (led->port_num == 0 || led->port_num == 4) {
|
||||
+ mask = QCA8K_LED_PATTERN_EN_MASK;
|
||||
+ val <<= QCA8K_LED_PATTERN_EN_SHIFT;
|
||||
+ } else {
|
||||
+ mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;
|
||||
+ }
|
||||
+
|
||||
+ return regmap_update_bits(priv->regmap, reg_info.reg,
|
||||
+ mask << reg_info.shift,
|
||||
+ val << reg_info.shift);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_cled_brightness_set_blocking(struct led_classdev *ldev,
|
||||
+ enum led_brightness brightness)
|
||||
+{
|
||||
+ struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
|
||||
+
|
||||
+ return qca8k_led_brightness_set(led, brightness);
|
||||
+}
|
||||
+
|
||||
+static enum led_brightness
|
||||
+qca8k_led_brightness_get(struct qca8k_led *led)
|
||||
+{
|
||||
+ struct qca8k_led_pattern_en reg_info;
|
||||
+ struct qca8k_priv *priv = led->priv;
|
||||
+ u32 val;
|
||||
+ int ret;
|
||||
+
|
||||
+ qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info);
|
||||
+
|
||||
+ ret = regmap_read(priv->regmap, reg_info.reg, &val);
|
||||
+ if (ret)
|
||||
+ return 0;
|
||||
+
|
||||
+ val >>= reg_info.shift;
|
||||
+
|
||||
+ if (led->port_num == 0 || led->port_num == 4) {
|
||||
+ val &= QCA8K_LED_PATTERN_EN_MASK;
|
||||
+ val >>= QCA8K_LED_PATTERN_EN_SHIFT;
|
||||
+ } else {
|
||||
+ val &= QCA8K_LED_PHY123_PATTERN_EN_MASK;
|
||||
+ }
|
||||
+
|
||||
+ /* Assume brightness ON only when the LED is set to always ON */
|
||||
+ return val == QCA8K_LED_ALWAYS_ON;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num)
|
||||
+{
|
||||
+ struct fwnode_handle *led = NULL, *leds = NULL;
|
||||
+ struct led_init_data init_data = { };
|
||||
+ struct dsa_switch *ds = priv->ds;
|
||||
+ enum led_default_state state;
|
||||
+ struct qca8k_led *port_led;
|
||||
+ int led_num, led_index;
|
||||
+ int ret;
|
||||
+
|
||||
+ leds = fwnode_get_named_child_node(port, "leds");
|
||||
+ if (!leds) {
|
||||
+ dev_dbg(priv->dev, "No Leds node specified in device tree for port %d!\n",
|
||||
+ port_num);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ fwnode_for_each_child_node(leds, led) {
|
||||
+ /* Reg represent the led number of the port.
|
||||
+ * Each port can have at most 3 leds attached
|
||||
+ * Commonly:
|
||||
+ * 1. is gigabit led
|
||||
+ * 2. is mbit led
|
||||
+ * 3. additional status led
|
||||
+ */
|
||||
+ if (fwnode_property_read_u32(led, "reg", &led_num))
|
||||
+ continue;
|
||||
+
|
||||
+ if (led_num >= QCA8K_LED_PORT_COUNT) {
|
||||
+ dev_warn(priv->dev, "Invalid LED reg %d defined for port %d",
|
||||
+ led_num, port_num);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ led_index = QCA8K_LED_PORT_INDEX(port_num, led_num);
|
||||
+
|
||||
+ port_led = &priv->ports_led[led_index];
|
||||
+ port_led->port_num = port_num;
|
||||
+ port_led->led_num = led_num;
|
||||
+ port_led->priv = priv;
|
||||
+
|
||||
+ state = led_init_default_state_get(led);
|
||||
+ switch (state) {
|
||||
+ case LEDS_DEFSTATE_ON:
|
||||
+ port_led->cdev.brightness = 1;
|
||||
+ qca8k_led_brightness_set(port_led, 1);
|
||||
+ break;
|
||||
+ case LEDS_DEFSTATE_KEEP:
|
||||
+ port_led->cdev.brightness =
|
||||
+ qca8k_led_brightness_get(port_led);
|
||||
+ break;
|
||||
+ default:
|
||||
+ port_led->cdev.brightness = 0;
|
||||
+ qca8k_led_brightness_set(port_led, 0);
|
||||
+ }
|
||||
+
|
||||
+ port_led->cdev.max_brightness = 1;
|
||||
+ port_led->cdev.brightness_set_blocking = qca8k_cled_brightness_set_blocking;
|
||||
+ init_data.default_label = ":port";
|
||||
+ init_data.fwnode = led;
|
||||
+ init_data.devname_mandatory = true;
|
||||
+ init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d", ds->slave_mii_bus->id,
|
||||
+ port_num);
|
||||
+ if (!init_data.devicename)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ ret = devm_led_classdev_register_ext(priv->dev, &port_led->cdev, &init_data);
|
||||
+ if (ret)
|
||||
+ dev_warn(priv->dev, "Failed to init LED %d for port %d", led_num, port_num);
|
||||
+
|
||||
+ kfree(init_data.devicename);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+qca8k_setup_led_ctrl(struct qca8k_priv *priv)
|
||||
+{
|
||||
+ struct fwnode_handle *ports, *port;
|
||||
+ int port_num;
|
||||
+ int ret;
|
||||
+
|
||||
+ ports = device_get_named_child_node(priv->dev, "ports");
|
||||
+ if (!ports) {
|
||||
+ dev_info(priv->dev, "No ports node specified in device tree!");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ fwnode_for_each_child_node(ports, port) {
|
||||
+ if (fwnode_property_read_u32(port, "reg", &port_num))
|
||||
+ continue;
|
||||
+
|
||||
+ /* Skip checking for CPU port 0 and CPU port 6 as not supported */
|
||||
+ if (port_num == 0 || port_num == 6)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Each port can have at most 3 different leds attached.
|
||||
+ * Switch port starts from 0 to 6, but port 0 and 6 are CPU
|
||||
+ * port. The port index needs to be decreased by one to identify
|
||||
+ * the correct port for LED setup.
|
||||
+ */
|
||||
+ ret = qca8k_parse_port_leds(priv, port, qca8k_port_to_phy(port_num));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/gpio.h>
|
||||
+#include <linux/leds.h>
|
||||
#include <linux/dsa/tag_qca.h>
|
||||
|
||||
#define QCA8K_ETHERNET_MDIO_PRIORITY 7
|
||||
@@ -85,6 +86,51 @@
|
||||
#define QCA8K_MDIO_MASTER_DATA(x) FIELD_PREP(QCA8K_MDIO_MASTER_DATA_MASK, x)
|
||||
#define QCA8K_MDIO_MASTER_MAX_PORTS 5
|
||||
#define QCA8K_MDIO_MASTER_MAX_REG 32
|
||||
+
|
||||
+/* LED control register */
|
||||
+#define QCA8K_LED_PORT_COUNT 3
|
||||
+#define QCA8K_LED_COUNT ((QCA8K_NUM_PORTS - QCA8K_NUM_CPU_PORTS) * QCA8K_LED_PORT_COUNT)
|
||||
+#define QCA8K_LED_RULE_COUNT 6
|
||||
+#define QCA8K_LED_RULE_MAX 11
|
||||
+#define QCA8K_LED_PORT_INDEX(_phy, _led) (((_phy) * QCA8K_LED_PORT_COUNT) + (_led))
|
||||
+
|
||||
+#define QCA8K_LED_PHY123_PATTERN_EN_SHIFT(_phy, _led) ((((_phy) - 1) * 6) + 8 + (2 * (_led)))
|
||||
+#define QCA8K_LED_PHY123_PATTERN_EN_MASK GENMASK(1, 0)
|
||||
+
|
||||
+#define QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT 0
|
||||
+#define QCA8K_LED_PHY4_CONTROL_RULE_SHIFT 16
|
||||
+
|
||||
+#define QCA8K_LED_CTRL_REG(_i) (0x050 + (_i) * 4)
|
||||
+#define QCA8K_LED_CTRL0_REG 0x50
|
||||
+#define QCA8K_LED_CTRL1_REG 0x54
|
||||
+#define QCA8K_LED_CTRL2_REG 0x58
|
||||
+#define QCA8K_LED_CTRL3_REG 0x5C
|
||||
+#define QCA8K_LED_CTRL_SHIFT(_i) (((_i) % 2) * 16)
|
||||
+#define QCA8K_LED_CTRL_MASK GENMASK(15, 0)
|
||||
+#define QCA8K_LED_RULE_MASK GENMASK(13, 0)
|
||||
+#define QCA8K_LED_BLINK_FREQ_MASK GENMASK(1, 0)
|
||||
+#define QCA8K_LED_BLINK_FREQ_SHITF 0
|
||||
+#define QCA8K_LED_BLINK_2HZ 0
|
||||
+#define QCA8K_LED_BLINK_4HZ 1
|
||||
+#define QCA8K_LED_BLINK_8HZ 2
|
||||
+#define QCA8K_LED_BLINK_AUTO 3
|
||||
+#define QCA8K_LED_LINKUP_OVER_MASK BIT(2)
|
||||
+#define QCA8K_LED_TX_BLINK_MASK BIT(4)
|
||||
+#define QCA8K_LED_RX_BLINK_MASK BIT(5)
|
||||
+#define QCA8K_LED_COL_BLINK_MASK BIT(7)
|
||||
+#define QCA8K_LED_LINK_10M_EN_MASK BIT(8)
|
||||
+#define QCA8K_LED_LINK_100M_EN_MASK BIT(9)
|
||||
+#define QCA8K_LED_LINK_1000M_EN_MASK BIT(10)
|
||||
+#define QCA8K_LED_POWER_ON_LIGHT_MASK BIT(11)
|
||||
+#define QCA8K_LED_HALF_DUPLEX_MASK BIT(12)
|
||||
+#define QCA8K_LED_FULL_DUPLEX_MASK BIT(13)
|
||||
+#define QCA8K_LED_PATTERN_EN_MASK GENMASK(15, 14)
|
||||
+#define QCA8K_LED_PATTERN_EN_SHIFT 14
|
||||
+#define QCA8K_LED_ALWAYS_OFF 0
|
||||
+#define QCA8K_LED_ALWAYS_BLINK_4HZ 1
|
||||
+#define QCA8K_LED_ALWAYS_ON 2
|
||||
+#define QCA8K_LED_RULE_CONTROLLED 3
|
||||
+
|
||||
#define QCA8K_GOL_MAC_ADDR0 0x60
|
||||
#define QCA8K_GOL_MAC_ADDR1 0x64
|
||||
#define QCA8K_MAX_FRAME_SIZE 0x78
|
||||
@@ -382,6 +428,19 @@ struct qca8k_mdio_cache {
|
||||
u16 hi;
|
||||
};
|
||||
|
||||
+struct qca8k_led_pattern_en {
|
||||
+ u32 reg;
|
||||
+ u8 shift;
|
||||
+};
|
||||
+
|
||||
+struct qca8k_led {
|
||||
+ u8 port_num;
|
||||
+ u8 led_num;
|
||||
+ u16 old_rule;
|
||||
+ struct qca8k_priv *priv;
|
||||
+ struct led_classdev cdev;
|
||||
+};
|
||||
+
|
||||
struct qca8k_priv {
|
||||
u8 switch_id;
|
||||
u8 switch_revision;
|
||||
@@ -404,6 +463,7 @@ struct qca8k_priv {
|
||||
struct qca8k_mib_eth_data mib_eth_data;
|
||||
struct qca8k_mdio_cache mdio_cache;
|
||||
const struct qca8k_match_data *info;
|
||||
+ struct qca8k_led ports_led[QCA8K_LED_COUNT];
|
||||
};
|
||||
|
||||
struct qca8k_mib_desc {
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/dsa/qca/qca8k_leds.h
|
||||
@@ -0,0 +1,16 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
+
|
||||
+#ifndef __QCA8K_LEDS_H
|
||||
+#define __QCA8K_LEDS_H
|
||||
+
|
||||
+/* Leds Support function */
|
||||
+#ifdef CONFIG_NET_DSA_QCA8K_LEDS_SUPPORT
|
||||
+int qca8k_setup_led_ctrl(struct qca8k_priv *priv);
|
||||
+#else
|
||||
+static inline int qca8k_setup_led_ctrl(struct qca8k_priv *priv)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+#endif /* __QCA8K_LEDS_H */
|
@@ -0,0 +1,74 @@
|
||||
From 91acadcc6e599dfc62717abcdad58a459cfb1684 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 17 Apr 2023 17:17:25 +0200
|
||||
Subject: [PATCH 3/9] net: dsa: qca8k: add LEDs blink_set() support
|
||||
|
||||
Add LEDs blink_set() support to qca8k Switch Family.
|
||||
These LEDs support hw accellerated blinking at a fixed rate
|
||||
of 4Hz.
|
||||
|
||||
Reject any other value since not supported by the LEDs switch.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Acked-by: Pavel Machek <pavel@ucw.cz>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-leds.c | 38 ++++++++++++++++++++++++++++++++
|
||||
1 file changed, 38 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-leds.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-leds.c
|
||||
@@ -128,6 +128,43 @@ qca8k_led_brightness_get(struct qca8k_le
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_cled_blink_set(struct led_classdev *ldev,
|
||||
+ unsigned long *delay_on,
|
||||
+ unsigned long *delay_off)
|
||||
+{
|
||||
+ struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
|
||||
+ u32 mask, val = QCA8K_LED_ALWAYS_BLINK_4HZ;
|
||||
+ struct qca8k_led_pattern_en reg_info;
|
||||
+ struct qca8k_priv *priv = led->priv;
|
||||
+
|
||||
+ if (*delay_on == 0 && *delay_off == 0) {
|
||||
+ *delay_on = 125;
|
||||
+ *delay_off = 125;
|
||||
+ }
|
||||
+
|
||||
+ if (*delay_on != 125 || *delay_off != 125) {
|
||||
+ /* The hardware only supports blinking at 4Hz. Fall back
|
||||
+ * to software implementation in other cases.
|
||||
+ */
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info);
|
||||
+
|
||||
+ if (led->port_num == 0 || led->port_num == 4) {
|
||||
+ mask = QCA8K_LED_PATTERN_EN_MASK;
|
||||
+ val <<= QCA8K_LED_PATTERN_EN_SHIFT;
|
||||
+ } else {
|
||||
+ mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;
|
||||
+ }
|
||||
+
|
||||
+ regmap_update_bits(priv->regmap, reg_info.reg, mask << reg_info.shift,
|
||||
+ val << reg_info.shift);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num)
|
||||
{
|
||||
struct fwnode_handle *led = NULL, *leds = NULL;
|
||||
@@ -186,6 +223,7 @@ qca8k_parse_port_leds(struct qca8k_priv
|
||||
|
||||
port_led->cdev.max_brightness = 1;
|
||||
port_led->cdev.brightness_set_blocking = qca8k_cled_brightness_set_blocking;
|
||||
+ port_led->cdev.blink_set = qca8k_cled_blink_set;
|
||||
init_data.default_label = ":port";
|
||||
init_data.fwnode = led;
|
||||
init_data.devname_mandatory = true;
|
@@ -0,0 +1,59 @@
|
||||
From e5029edd53937a29801ef507cee12e657ff31ea9 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Lunn <andrew@lunn.ch>
|
||||
Date: Mon, 17 Apr 2023 17:17:26 +0200
|
||||
Subject: [PATCH 4/9] leds: Provide stubs for when CLASS_LED & NEW_LEDS are
|
||||
disabled
|
||||
|
||||
Provide stubs for devm_led_classdev_register_ext() and
|
||||
led_init_default_state_get() so that LED drivers embedded within other
|
||||
drivers such as PHYs and Ethernet switches still build when LEDS_CLASS
|
||||
or NEW_LEDS are disabled. This also helps with Kconfig dependencies,
|
||||
which are somewhat hairy for phylib and mdio and only get worse when
|
||||
adding a dependency on LED_CLASS.
|
||||
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/linux/leds.h | 18 ++++++++++++++++++
|
||||
1 file changed, 18 insertions(+)
|
||||
|
||||
--- a/include/linux/leds.h
|
||||
+++ b/include/linux/leds.h
|
||||
@@ -63,7 +63,15 @@ struct led_init_data {
|
||||
bool devname_mandatory;
|
||||
};
|
||||
|
||||
+#if IS_ENABLED(CONFIG_NEW_LEDS)
|
||||
enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode);
|
||||
+#else
|
||||
+static inline enum led_default_state
|
||||
+led_init_default_state_get(struct fwnode_handle *fwnode)
|
||||
+{
|
||||
+ return LEDS_DEFSTATE_OFF;
|
||||
+}
|
||||
+#endif
|
||||
|
||||
struct led_hw_trigger_type {
|
||||
int dummy;
|
||||
@@ -198,9 +206,19 @@ static inline int led_classdev_register(
|
||||
return led_classdev_register_ext(parent, led_cdev, NULL);
|
||||
}
|
||||
|
||||
+#if IS_ENABLED(CONFIG_LEDS_CLASS)
|
||||
int devm_led_classdev_register_ext(struct device *parent,
|
||||
struct led_classdev *led_cdev,
|
||||
struct led_init_data *init_data);
|
||||
+#else
|
||||
+static inline int
|
||||
+devm_led_classdev_register_ext(struct device *parent,
|
||||
+ struct led_classdev *led_cdev,
|
||||
+ struct led_init_data *init_data)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
|
||||
static inline int devm_led_classdev_register(struct device *parent,
|
||||
struct led_classdev *led_cdev)
|
@@ -0,0 +1,191 @@
|
||||
From 01e5b728e9e43ae444e0369695a5f72209906464 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Lunn <andrew@lunn.ch>
|
||||
Date: Mon, 17 Apr 2023 17:17:27 +0200
|
||||
Subject: [PATCH 5/9] net: phy: Add a binding for PHY LEDs
|
||||
|
||||
Define common binding parsing for all PHY drivers with LEDs using
|
||||
phylib. Parse the DT as part of the phy_probe and add LEDs to the
|
||||
linux LED class infrastructure. For the moment, provide a dummy
|
||||
brightness function, which will later be replaced with a call into the
|
||||
PHY driver. This allows testing since the LED core might otherwise
|
||||
reject an LED whose brightness cannot be set.
|
||||
|
||||
Add a dependency on LED_CLASS. It either needs to be built in, or not
|
||||
enabled, since a modular build can result in linker errors.
|
||||
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/Kconfig | 1 +
|
||||
drivers/net/phy/phy_device.c | 76 ++++++++++++++++++++++++++++++++++++
|
||||
include/linux/phy.h | 16 ++++++++
|
||||
3 files changed, 93 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/Kconfig
|
||||
+++ b/drivers/net/phy/Kconfig
|
||||
@@ -18,6 +18,7 @@ menuconfig PHYLIB
|
||||
depends on NETDEVICES
|
||||
select MDIO_DEVICE
|
||||
select MDIO_DEVRES
|
||||
+ depends on LEDS_CLASS || LEDS_CLASS=n
|
||||
help
|
||||
Ethernet controllers are usually attached to PHY
|
||||
devices. This option provides infrastructure for
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -19,10 +19,12 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
+#include <linux/list.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phy_led_triggers.h>
|
||||
@@ -641,6 +643,7 @@ struct phy_device *phy_device_create(str
|
||||
device_initialize(&mdiodev->dev);
|
||||
|
||||
dev->state = PHY_DOWN;
|
||||
+ INIT_LIST_HEAD(&dev->leds);
|
||||
|
||||
mutex_init(&dev->lock);
|
||||
INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
|
||||
@@ -2942,6 +2945,74 @@ static bool phy_drv_supports_irq(struct
|
||||
return phydrv->config_intr && phydrv->handle_interrupt;
|
||||
}
|
||||
|
||||
+/* Dummy implementation until calls into PHY driver are added */
|
||||
+static int phy_led_set_brightness(struct led_classdev *led_cdev,
|
||||
+ enum led_brightness value)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int of_phy_led(struct phy_device *phydev,
|
||||
+ struct device_node *led)
|
||||
+{
|
||||
+ struct device *dev = &phydev->mdio.dev;
|
||||
+ struct led_init_data init_data = {};
|
||||
+ struct led_classdev *cdev;
|
||||
+ struct phy_led *phyled;
|
||||
+ int err;
|
||||
+
|
||||
+ phyled = devm_kzalloc(dev, sizeof(*phyled), GFP_KERNEL);
|
||||
+ if (!phyled)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ cdev = &phyled->led_cdev;
|
||||
+
|
||||
+ err = of_property_read_u8(led, "reg", &phyled->index);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ cdev->brightness_set_blocking = phy_led_set_brightness;
|
||||
+ cdev->max_brightness = 1;
|
||||
+ init_data.devicename = dev_name(&phydev->mdio.dev);
|
||||
+ init_data.fwnode = of_fwnode_handle(led);
|
||||
+ init_data.devname_mandatory = true;
|
||||
+
|
||||
+ err = devm_led_classdev_register_ext(dev, cdev, &init_data);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ list_add(&phyled->list, &phydev->leds);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int of_phy_leds(struct phy_device *phydev)
|
||||
+{
|
||||
+ struct device_node *node = phydev->mdio.dev.of_node;
|
||||
+ struct device_node *leds, *led;
|
||||
+ int err;
|
||||
+
|
||||
+ if (!IS_ENABLED(CONFIG_OF_MDIO))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (!node)
|
||||
+ return 0;
|
||||
+
|
||||
+ leds = of_get_child_by_name(node, "leds");
|
||||
+ if (!leds)
|
||||
+ return 0;
|
||||
+
|
||||
+ for_each_available_child_of_node(leds, led) {
|
||||
+ err = of_phy_led(phydev, led);
|
||||
+ if (err) {
|
||||
+ of_node_put(led);
|
||||
+ return err;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* fwnode_mdio_find_device - Given a fwnode, find the mdio_device
|
||||
* @fwnode: pointer to the mdio_device's fwnode
|
||||
@@ -3120,6 +3191,11 @@ static int phy_probe(struct device *dev)
|
||||
/* Set the state to READY by default */
|
||||
phydev->state = PHY_READY;
|
||||
|
||||
+ /* Get the LEDs from the device tree, and instantiate standard
|
||||
+ * LEDs for them.
|
||||
+ */
|
||||
+ err = of_phy_leds(phydev);
|
||||
+
|
||||
out:
|
||||
/* Re-assert the reset signal on error */
|
||||
if (err)
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/ethtool.h>
|
||||
+#include <linux/leds.h>
|
||||
#include <linux/linkmode.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/mdio.h>
|
||||
@@ -582,6 +583,7 @@ struct macsec_ops;
|
||||
* @phy_num_led_triggers: Number of triggers in @phy_led_triggers
|
||||
* @led_link_trigger: LED trigger for link up/down
|
||||
* @last_triggered: last LED trigger for link speed
|
||||
+ * @leds: list of PHY LED structures
|
||||
* @master_slave_set: User requested master/slave configuration
|
||||
* @master_slave_get: Current master/slave advertisement
|
||||
* @master_slave_state: Current master/slave configuration
|
||||
@@ -668,6 +670,7 @@ struct phy_device {
|
||||
|
||||
struct phy_led_trigger *led_link_trigger;
|
||||
#endif
|
||||
+ struct list_head leds;
|
||||
|
||||
/*
|
||||
* Interrupt number for this PHY
|
||||
@@ -739,6 +742,19 @@ struct phy_tdr_config {
|
||||
#define PHY_PAIR_ALL -1
|
||||
|
||||
/**
|
||||
+ * struct phy_led: An LED driven by the PHY
|
||||
+ *
|
||||
+ * @list: List of LEDs
|
||||
+ * @led_cdev: Standard LED class structure
|
||||
+ * @index: Number of the LED
|
||||
+ */
|
||||
+struct phy_led {
|
||||
+ struct list_head list;
|
||||
+ struct led_classdev led_cdev;
|
||||
+ u8 index;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
* struct phy_driver - Driver structure for a particular PHY type
|
||||
*
|
||||
* @mdiodrv: Data common to all MDIO devices
|
@@ -0,0 +1,97 @@
|
||||
From 684818189b04b095b34964ed4a3ea5249a840eab Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Lunn <andrew@lunn.ch>
|
||||
Date: Mon, 17 Apr 2023 17:17:28 +0200
|
||||
Subject: [PATCH 6/9] net: phy: phy_device: Call into the PHY driver to set LED
|
||||
brightness
|
||||
|
||||
Linux LEDs can be software controlled via the brightness file in /sys.
|
||||
LED drivers need to implement a brightness_set function which the core
|
||||
will call. Implement an intermediary in phy_device, which will call
|
||||
into the phy driver if it implements the necessary function.
|
||||
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/phy_device.c | 15 ++++++++++++---
|
||||
include/linux/phy.h | 13 +++++++++++++
|
||||
2 files changed, 25 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -2945,11 +2945,18 @@ static bool phy_drv_supports_irq(struct
|
||||
return phydrv->config_intr && phydrv->handle_interrupt;
|
||||
}
|
||||
|
||||
-/* Dummy implementation until calls into PHY driver are added */
|
||||
static int phy_led_set_brightness(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
- return 0;
|
||||
+ struct phy_led *phyled = to_phy_led(led_cdev);
|
||||
+ struct phy_device *phydev = phyled->phydev;
|
||||
+ int err;
|
||||
+
|
||||
+ mutex_lock(&phydev->lock);
|
||||
+ err = phydev->drv->led_brightness_set(phydev, phyled->index, value);
|
||||
+ mutex_unlock(&phydev->lock);
|
||||
+
|
||||
+ return err;
|
||||
}
|
||||
|
||||
static int of_phy_led(struct phy_device *phydev,
|
||||
@@ -2966,12 +2973,14 @@ static int of_phy_led(struct phy_device
|
||||
return -ENOMEM;
|
||||
|
||||
cdev = &phyled->led_cdev;
|
||||
+ phyled->phydev = phydev;
|
||||
|
||||
err = of_property_read_u8(led, "reg", &phyled->index);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
- cdev->brightness_set_blocking = phy_led_set_brightness;
|
||||
+ if (phydev->drv->led_brightness_set)
|
||||
+ cdev->brightness_set_blocking = phy_led_set_brightness;
|
||||
cdev->max_brightness = 1;
|
||||
init_data.devicename = dev_name(&phydev->mdio.dev);
|
||||
init_data.fwnode = of_fwnode_handle(led);
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -745,15 +745,19 @@ struct phy_tdr_config {
|
||||
* struct phy_led: An LED driven by the PHY
|
||||
*
|
||||
* @list: List of LEDs
|
||||
+ * @phydev: PHY this LED is attached to
|
||||
* @led_cdev: Standard LED class structure
|
||||
* @index: Number of the LED
|
||||
*/
|
||||
struct phy_led {
|
||||
struct list_head list;
|
||||
+ struct phy_device *phydev;
|
||||
struct led_classdev led_cdev;
|
||||
u8 index;
|
||||
};
|
||||
|
||||
+#define to_phy_led(d) container_of(d, struct phy_led, led_cdev)
|
||||
+
|
||||
/**
|
||||
* struct phy_driver - Driver structure for a particular PHY type
|
||||
*
|
||||
@@ -953,6 +957,15 @@ struct phy_driver {
|
||||
int (*get_sqi)(struct phy_device *dev);
|
||||
/** @get_sqi_max: Get the maximum signal quality indication */
|
||||
int (*get_sqi_max)(struct phy_device *dev);
|
||||
+
|
||||
+ /**
|
||||
+ * @led_brightness_set: Set a PHY LED brightness. Index
|
||||
+ * indicates which of the PHYs led should be set. Value
|
||||
+ * follows the standard LED class meaning, e.g. LED_OFF,
|
||||
+ * LED_HALF, LED_FULL.
|
||||
+ */
|
||||
+ int (*led_brightness_set)(struct phy_device *dev,
|
||||
+ u8 index, enum led_brightness value);
|
||||
};
|
||||
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
|
||||
struct phy_driver, mdiodrv)
|
@@ -0,0 +1,112 @@
|
||||
From 2d3960e58ef7c83fe1dbf952f056b9e906cb6df8 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Lunn <andrew@lunn.ch>
|
||||
Date: Mon, 17 Apr 2023 17:17:29 +0200
|
||||
Subject: [PATCH 7/9] net: phy: marvell: Add software control of the LEDs
|
||||
|
||||
Add a brightness function, so the LEDs can be controlled from
|
||||
software using the standard Linux LED infrastructure.
|
||||
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/marvell.c | 45 ++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 40 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/marvell.c
|
||||
+++ b/drivers/net/phy/marvell.c
|
||||
@@ -144,11 +144,13 @@
|
||||
/* WOL Event Interrupt Enable */
|
||||
#define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7)
|
||||
|
||||
-/* LED Timer Control Register */
|
||||
-#define MII_88E1318S_PHY_LED_TCR 0x12
|
||||
-#define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15)
|
||||
-#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7)
|
||||
-#define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11)
|
||||
+#define MII_88E1318S_PHY_LED_FUNC 0x10
|
||||
+#define MII_88E1318S_PHY_LED_FUNC_OFF (0x8)
|
||||
+#define MII_88E1318S_PHY_LED_FUNC_ON (0x9)
|
||||
+#define MII_88E1318S_PHY_LED_TCR 0x12
|
||||
+#define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15)
|
||||
+#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7)
|
||||
+#define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11)
|
||||
|
||||
/* Magic Packet MAC address registers */
|
||||
#define MII_88E1318S_PHY_MAGIC_PACKET_WORD2 0x17
|
||||
@@ -2793,6 +2795,34 @@ static int marvell_hwmon_probe(struct ph
|
||||
}
|
||||
#endif
|
||||
|
||||
+static int m88e1318_led_brightness_set(struct phy_device *phydev,
|
||||
+ u8 index, enum led_brightness value)
|
||||
+{
|
||||
+ int reg;
|
||||
+
|
||||
+ reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,
|
||||
+ MII_88E1318S_PHY_LED_FUNC);
|
||||
+ if (reg < 0)
|
||||
+ return reg;
|
||||
+
|
||||
+ switch (index) {
|
||||
+ case 0:
|
||||
+ case 1:
|
||||
+ case 2:
|
||||
+ reg &= ~(0xf << (4 * index));
|
||||
+ if (value == LED_OFF)
|
||||
+ reg |= MII_88E1318S_PHY_LED_FUNC_OFF << (4 * index);
|
||||
+ else
|
||||
+ reg |= MII_88E1318S_PHY_LED_FUNC_ON << (4 * index);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return phy_write_paged(phydev, MII_MARVELL_LED_PAGE,
|
||||
+ MII_88E1318S_PHY_LED_FUNC, reg);
|
||||
+}
|
||||
+
|
||||
static int marvell_probe(struct phy_device *phydev)
|
||||
{
|
||||
struct marvell_priv *priv;
|
||||
@@ -3041,6 +3071,7 @@ static struct phy_driver marvell_drivers
|
||||
.get_sset_count = marvell_get_sset_count,
|
||||
.get_strings = marvell_get_strings,
|
||||
.get_stats = marvell_get_stats,
|
||||
+ .led_brightness_set = m88e1318_led_brightness_set,
|
||||
},
|
||||
{
|
||||
.phy_id = MARVELL_PHY_ID_88E1145,
|
||||
@@ -3147,6 +3178,7 @@ static struct phy_driver marvell_drivers
|
||||
.cable_test_start = marvell_vct7_cable_test_start,
|
||||
.cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
|
||||
.cable_test_get_status = marvell_vct7_cable_test_get_status,
|
||||
+ .led_brightness_set = m88e1318_led_brightness_set,
|
||||
},
|
||||
{
|
||||
.phy_id = MARVELL_PHY_ID_88E1540,
|
||||
@@ -3173,6 +3205,7 @@ static struct phy_driver marvell_drivers
|
||||
.cable_test_start = marvell_vct7_cable_test_start,
|
||||
.cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
|
||||
.cable_test_get_status = marvell_vct7_cable_test_get_status,
|
||||
+ .led_brightness_set = m88e1318_led_brightness_set,
|
||||
},
|
||||
{
|
||||
.phy_id = MARVELL_PHY_ID_88E1545,
|
||||
@@ -3199,6 +3232,7 @@ static struct phy_driver marvell_drivers
|
||||
.cable_test_start = marvell_vct7_cable_test_start,
|
||||
.cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
|
||||
.cable_test_get_status = marvell_vct7_cable_test_get_status,
|
||||
+ .led_brightness_set = m88e1318_led_brightness_set,
|
||||
},
|
||||
{
|
||||
.phy_id = MARVELL_PHY_ID_88E3016,
|
||||
@@ -3340,6 +3374,7 @@ static struct phy_driver marvell_drivers
|
||||
.get_stats = marvell_get_stats,
|
||||
.get_tunable = m88e1540_get_tunable,
|
||||
.set_tunable = m88e1540_set_tunable,
|
||||
+ .led_brightness_set = m88e1318_led_brightness_set,
|
||||
},
|
||||
};
|
||||
|
@@ -0,0 +1,73 @@
|
||||
From 4e901018432e38eab35d2a352661ce4727795be1 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Lunn <andrew@lunn.ch>
|
||||
Date: Mon, 17 Apr 2023 17:17:30 +0200
|
||||
Subject: [PATCH 8/9] net: phy: phy_device: Call into the PHY driver to set LED
|
||||
blinking
|
||||
|
||||
Linux LEDs can be requested to perform hardware accelerated
|
||||
blinking. Pass this to the PHY driver, if it implements the op.
|
||||
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/phy_device.c | 18 ++++++++++++++++++
|
||||
include/linux/phy.h | 12 ++++++++++++
|
||||
2 files changed, 30 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -2959,6 +2959,22 @@ static int phy_led_set_brightness(struct
|
||||
return err;
|
||||
}
|
||||
|
||||
+static int phy_led_blink_set(struct led_classdev *led_cdev,
|
||||
+ unsigned long *delay_on,
|
||||
+ unsigned long *delay_off)
|
||||
+{
|
||||
+ struct phy_led *phyled = to_phy_led(led_cdev);
|
||||
+ struct phy_device *phydev = phyled->phydev;
|
||||
+ int err;
|
||||
+
|
||||
+ mutex_lock(&phydev->lock);
|
||||
+ err = phydev->drv->led_blink_set(phydev, phyled->index,
|
||||
+ delay_on, delay_off);
|
||||
+ mutex_unlock(&phydev->lock);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
static int of_phy_led(struct phy_device *phydev,
|
||||
struct device_node *led)
|
||||
{
|
||||
@@ -2981,6 +2997,8 @@ static int of_phy_led(struct phy_device
|
||||
|
||||
if (phydev->drv->led_brightness_set)
|
||||
cdev->brightness_set_blocking = phy_led_set_brightness;
|
||||
+ if (phydev->drv->led_blink_set)
|
||||
+ cdev->blink_set = phy_led_blink_set;
|
||||
cdev->max_brightness = 1;
|
||||
init_data.devicename = dev_name(&phydev->mdio.dev);
|
||||
init_data.fwnode = of_fwnode_handle(led);
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -966,6 +966,18 @@ struct phy_driver {
|
||||
*/
|
||||
int (*led_brightness_set)(struct phy_device *dev,
|
||||
u8 index, enum led_brightness value);
|
||||
+
|
||||
+ /**
|
||||
+ * @led_blink_set: Set a PHY LED brightness. Index indicates
|
||||
+ * which of the PHYs led should be configured to blink. Delays
|
||||
+ * are in milliseconds and if both are zero then a sensible
|
||||
+ * default should be chosen. The call should adjust the
|
||||
+ * timings in that case and if it can't match the values
|
||||
+ * specified exactly.
|
||||
+ */
|
||||
+ int (*led_blink_set)(struct phy_device *dev, u8 index,
|
||||
+ unsigned long *delay_on,
|
||||
+ unsigned long *delay_off);
|
||||
};
|
||||
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
|
||||
struct phy_driver, mdiodrv)
|
@@ -0,0 +1,104 @@
|
||||
From ea9e86485decb2ac1750005bd96c166c9b780406 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Lunn <andrew@lunn.ch>
|
||||
Date: Mon, 17 Apr 2023 17:17:31 +0200
|
||||
Subject: [PATCH 9/9] net: phy: marvell: Implement led_blink_set()
|
||||
|
||||
The Marvell PHY can blink the LEDs, simple on/off. All LEDs blink at
|
||||
the same rate, and the reset default is 84ms per blink, which is
|
||||
around 12Hz.
|
||||
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/marvell.c | 36 ++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 36 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/marvell.c
|
||||
+++ b/drivers/net/phy/marvell.c
|
||||
@@ -147,6 +147,8 @@
|
||||
#define MII_88E1318S_PHY_LED_FUNC 0x10
|
||||
#define MII_88E1318S_PHY_LED_FUNC_OFF (0x8)
|
||||
#define MII_88E1318S_PHY_LED_FUNC_ON (0x9)
|
||||
+#define MII_88E1318S_PHY_LED_FUNC_HI_Z (0xa)
|
||||
+#define MII_88E1318S_PHY_LED_FUNC_BLINK (0xb)
|
||||
#define MII_88E1318S_PHY_LED_TCR 0x12
|
||||
#define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15)
|
||||
#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7)
|
||||
@@ -2823,6 +2825,35 @@ static int m88e1318_led_brightness_set(s
|
||||
MII_88E1318S_PHY_LED_FUNC, reg);
|
||||
}
|
||||
|
||||
+static int m88e1318_led_blink_set(struct phy_device *phydev, u8 index,
|
||||
+ unsigned long *delay_on,
|
||||
+ unsigned long *delay_off)
|
||||
+{
|
||||
+ int reg;
|
||||
+
|
||||
+ reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,
|
||||
+ MII_88E1318S_PHY_LED_FUNC);
|
||||
+ if (reg < 0)
|
||||
+ return reg;
|
||||
+
|
||||
+ switch (index) {
|
||||
+ case 0:
|
||||
+ case 1:
|
||||
+ case 2:
|
||||
+ reg &= ~(0xf << (4 * index));
|
||||
+ reg |= MII_88E1318S_PHY_LED_FUNC_BLINK << (4 * index);
|
||||
+ /* Reset default is 84ms */
|
||||
+ *delay_on = 84 / 2;
|
||||
+ *delay_off = 84 / 2;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return phy_write_paged(phydev, MII_MARVELL_LED_PAGE,
|
||||
+ MII_88E1318S_PHY_LED_FUNC, reg);
|
||||
+}
|
||||
+
|
||||
static int marvell_probe(struct phy_device *phydev)
|
||||
{
|
||||
struct marvell_priv *priv;
|
||||
@@ -3072,6 +3103,7 @@ static struct phy_driver marvell_drivers
|
||||
.get_strings = marvell_get_strings,
|
||||
.get_stats = marvell_get_stats,
|
||||
.led_brightness_set = m88e1318_led_brightness_set,
|
||||
+ .led_blink_set = m88e1318_led_blink_set,
|
||||
},
|
||||
{
|
||||
.phy_id = MARVELL_PHY_ID_88E1145,
|
||||
@@ -3179,6 +3211,7 @@ static struct phy_driver marvell_drivers
|
||||
.cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
|
||||
.cable_test_get_status = marvell_vct7_cable_test_get_status,
|
||||
.led_brightness_set = m88e1318_led_brightness_set,
|
||||
+ .led_blink_set = m88e1318_led_blink_set,
|
||||
},
|
||||
{
|
||||
.phy_id = MARVELL_PHY_ID_88E1540,
|
||||
@@ -3206,6 +3239,7 @@ static struct phy_driver marvell_drivers
|
||||
.cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
|
||||
.cable_test_get_status = marvell_vct7_cable_test_get_status,
|
||||
.led_brightness_set = m88e1318_led_brightness_set,
|
||||
+ .led_blink_set = m88e1318_led_blink_set,
|
||||
},
|
||||
{
|
||||
.phy_id = MARVELL_PHY_ID_88E1545,
|
||||
@@ -3233,6 +3267,7 @@ static struct phy_driver marvell_drivers
|
||||
.cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,
|
||||
.cable_test_get_status = marvell_vct7_cable_test_get_status,
|
||||
.led_brightness_set = m88e1318_led_brightness_set,
|
||||
+ .led_blink_set = m88e1318_led_blink_set,
|
||||
},
|
||||
{
|
||||
.phy_id = MARVELL_PHY_ID_88E3016,
|
||||
@@ -3375,6 +3410,7 @@ static struct phy_driver marvell_drivers
|
||||
.get_tunable = m88e1540_get_tunable,
|
||||
.set_tunable = m88e1540_set_tunable,
|
||||
.led_brightness_set = m88e1318_led_brightness_set,
|
||||
+ .led_blink_set = m88e1318_led_blink_set,
|
||||
},
|
||||
};
|
||||
|
@@ -0,0 +1,38 @@
|
||||
From 4774ad841bef97cc51df90195338c5b2573dd4cb Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Sun, 23 Apr 2023 19:28:00 +0200
|
||||
Subject: [PATCH] net: phy: marvell: Fix inconsistent indenting in
|
||||
led_blink_set
|
||||
|
||||
Fix inconsistent indeinting in m88e1318_led_blink_set reported by kernel
|
||||
test robot, probably done by the presence of an if condition dropped in
|
||||
later revision of the same code.
|
||||
|
||||
Reported-by: kernel test robot <lkp@intel.com>
|
||||
Link: https://lore.kernel.org/oe-kbuild-all/202304240007.0VEX8QYG-lkp@intel.com/
|
||||
Fixes: ea9e86485dec ("net: phy: marvell: Implement led_blink_set()")
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Link: https://lore.kernel.org/r/20230423172800.3470-1-ansuelsmth@gmail.com
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/phy/marvell.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/marvell.c
|
||||
+++ b/drivers/net/phy/marvell.c
|
||||
@@ -2841,10 +2841,10 @@ static int m88e1318_led_blink_set(struct
|
||||
case 1:
|
||||
case 2:
|
||||
reg &= ~(0xf << (4 * index));
|
||||
- reg |= MII_88E1318S_PHY_LED_FUNC_BLINK << (4 * index);
|
||||
- /* Reset default is 84ms */
|
||||
- *delay_on = 84 / 2;
|
||||
- *delay_off = 84 / 2;
|
||||
+ reg |= MII_88E1318S_PHY_LED_FUNC_BLINK << (4 * index);
|
||||
+ /* Reset default is 84ms */
|
||||
+ *delay_on = 84 / 2;
|
||||
+ *delay_off = 84 / 2;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
@@ -0,0 +1,87 @@
|
||||
From e2f24cb1b5daf9a4f6f3ba574c1fa74aab9807a4 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 19 Apr 2023 23:07:40 +0200
|
||||
Subject: [PATCH 2/5] leds: trigger: netdev: Drop NETDEV_LED_MODE_LINKUP from
|
||||
mode
|
||||
|
||||
Putting NETDEV_LED_MODE_LINKUP in the same list of the netdev trigger
|
||||
modes is wrong as it's used to set the link state of the device and not
|
||||
to set a blink mode as it's done by NETDEV_LED_LINK, NETDEV_LED_TX and
|
||||
NETDEV_LED_RX. It's also wrong to put this state in the same bitmap of the
|
||||
netdev trigger mode and should be external to it.
|
||||
|
||||
Drop NETDEV_LED_MODE_LINKUP from mode list and convert to a simple bool
|
||||
that will be true or false based on the carrier link. No functional
|
||||
change intended.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Lee Jones <lee@kernel.org>
|
||||
Link: https://lore.kernel.org/r/20230419210743.3594-3-ansuelsmth@gmail.com
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 19 ++++++++-----------
|
||||
1 file changed, 8 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -50,10 +50,10 @@ struct led_netdev_data {
|
||||
unsigned int last_activity;
|
||||
|
||||
unsigned long mode;
|
||||
+ bool carrier_link_up;
|
||||
#define NETDEV_LED_LINK 0
|
||||
#define NETDEV_LED_TX 1
|
||||
#define NETDEV_LED_RX 2
|
||||
-#define NETDEV_LED_MODE_LINKUP 3
|
||||
};
|
||||
|
||||
enum netdev_led_attr {
|
||||
@@ -73,9 +73,9 @@ static void set_baseline_state(struct le
|
||||
if (!led_cdev->blink_brightness)
|
||||
led_cdev->blink_brightness = led_cdev->max_brightness;
|
||||
|
||||
- if (!test_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode))
|
||||
+ if (!trigger_data->carrier_link_up) {
|
||||
led_set_brightness(led_cdev, LED_OFF);
|
||||
- else {
|
||||
+ } else {
|
||||
if (test_bit(NETDEV_LED_LINK, &trigger_data->mode))
|
||||
led_set_brightness(led_cdev,
|
||||
led_cdev->blink_brightness);
|
||||
@@ -131,10 +131,9 @@ static ssize_t device_name_store(struct
|
||||
trigger_data->net_dev =
|
||||
dev_get_by_name(&init_net, trigger_data->device_name);
|
||||
|
||||
- clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||
+ trigger_data->carrier_link_up = false;
|
||||
if (trigger_data->net_dev != NULL)
|
||||
- if (netif_carrier_ok(trigger_data->net_dev))
|
||||
- set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||
+ trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev);
|
||||
|
||||
trigger_data->last_activity = 0;
|
||||
|
||||
@@ -315,11 +314,10 @@ static int netdev_trig_notify(struct not
|
||||
|
||||
spin_lock_bh(&trigger_data->lock);
|
||||
|
||||
- clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||
+ trigger_data->carrier_link_up = false;
|
||||
switch (evt) {
|
||||
case NETDEV_CHANGENAME:
|
||||
- if (netif_carrier_ok(dev))
|
||||
- set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||
+ trigger_data->carrier_link_up = netif_carrier_ok(dev);
|
||||
fallthrough;
|
||||
case NETDEV_REGISTER:
|
||||
if (trigger_data->net_dev)
|
||||
@@ -333,8 +331,7 @@ static int netdev_trig_notify(struct not
|
||||
break;
|
||||
case NETDEV_UP:
|
||||
case NETDEV_CHANGE:
|
||||
- if (netif_carrier_ok(dev))
|
||||
- set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||
+ trigger_data->carrier_link_up = netif_carrier_ok(dev);
|
||||
break;
|
||||
}
|
||||
|
@@ -0,0 +1,149 @@
|
||||
From bdec9cb83936e0ac4cb87fed5b49fad0175f7dec Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 19 Apr 2023 23:07:41 +0200
|
||||
Subject: [PATCH 3/5] leds: trigger: netdev: Rename add namespace to netdev
|
||||
trigger enum modes
|
||||
|
||||
Rename NETDEV trigger enum modes to a more symbolic name and add a
|
||||
namespace to them.
|
||||
|
||||
Also add __TRIGGER_NETDEV_MAX to identify the max modes of the netdev
|
||||
trigger.
|
||||
|
||||
This is a cleanup to drop the define and no behaviour change are
|
||||
intended.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Lee Jones <lee@kernel.org>
|
||||
Link: https://lore.kernel.org/r/20230419210743.3594-4-ansuelsmth@gmail.com
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 58 ++++++++++++---------------
|
||||
1 file changed, 25 insertions(+), 33 deletions(-)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -51,15 +51,15 @@ struct led_netdev_data {
|
||||
|
||||
unsigned long mode;
|
||||
bool carrier_link_up;
|
||||
-#define NETDEV_LED_LINK 0
|
||||
-#define NETDEV_LED_TX 1
|
||||
-#define NETDEV_LED_RX 2
|
||||
};
|
||||
|
||||
-enum netdev_led_attr {
|
||||
- NETDEV_ATTR_LINK,
|
||||
- NETDEV_ATTR_TX,
|
||||
- NETDEV_ATTR_RX
|
||||
+enum led_trigger_netdev_modes {
|
||||
+ TRIGGER_NETDEV_LINK = 0,
|
||||
+ TRIGGER_NETDEV_TX,
|
||||
+ TRIGGER_NETDEV_RX,
|
||||
+
|
||||
+ /* Keep last */
|
||||
+ __TRIGGER_NETDEV_MAX,
|
||||
};
|
||||
|
||||
static void set_baseline_state(struct led_netdev_data *trigger_data)
|
||||
@@ -76,7 +76,7 @@ static void set_baseline_state(struct le
|
||||
if (!trigger_data->carrier_link_up) {
|
||||
led_set_brightness(led_cdev, LED_OFF);
|
||||
} else {
|
||||
- if (test_bit(NETDEV_LED_LINK, &trigger_data->mode))
|
||||
+ if (test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode))
|
||||
led_set_brightness(led_cdev,
|
||||
led_cdev->blink_brightness);
|
||||
else
|
||||
@@ -85,8 +85,8 @@ static void set_baseline_state(struct le
|
||||
/* If we are looking for RX/TX start periodically
|
||||
* checking stats
|
||||
*/
|
||||
- if (test_bit(NETDEV_LED_TX, &trigger_data->mode) ||
|
||||
- test_bit(NETDEV_LED_RX, &trigger_data->mode))
|
||||
+ if (test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) ||
|
||||
+ test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode))
|
||||
schedule_delayed_work(&trigger_data->work, 0);
|
||||
}
|
||||
}
|
||||
@@ -146,20 +146,16 @@ static ssize_t device_name_store(struct
|
||||
static DEVICE_ATTR_RW(device_name);
|
||||
|
||||
static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
|
||||
- enum netdev_led_attr attr)
|
||||
+ enum led_trigger_netdev_modes attr)
|
||||
{
|
||||
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
int bit;
|
||||
|
||||
switch (attr) {
|
||||
- case NETDEV_ATTR_LINK:
|
||||
- bit = NETDEV_LED_LINK;
|
||||
- break;
|
||||
- case NETDEV_ATTR_TX:
|
||||
- bit = NETDEV_LED_TX;
|
||||
- break;
|
||||
- case NETDEV_ATTR_RX:
|
||||
- bit = NETDEV_LED_RX;
|
||||
+ case TRIGGER_NETDEV_LINK:
|
||||
+ case TRIGGER_NETDEV_TX:
|
||||
+ case TRIGGER_NETDEV_RX:
|
||||
+ bit = attr;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -169,7 +165,7 @@ static ssize_t netdev_led_attr_show(stru
|
||||
}
|
||||
|
||||
static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
|
||||
- size_t size, enum netdev_led_attr attr)
|
||||
+ size_t size, enum led_trigger_netdev_modes attr)
|
||||
{
|
||||
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
unsigned long state;
|
||||
@@ -181,14 +177,10 @@ static ssize_t netdev_led_attr_store(str
|
||||
return ret;
|
||||
|
||||
switch (attr) {
|
||||
- case NETDEV_ATTR_LINK:
|
||||
- bit = NETDEV_LED_LINK;
|
||||
- break;
|
||||
- case NETDEV_ATTR_TX:
|
||||
- bit = NETDEV_LED_TX;
|
||||
- break;
|
||||
- case NETDEV_ATTR_RX:
|
||||
- bit = NETDEV_LED_RX;
|
||||
+ case TRIGGER_NETDEV_LINK:
|
||||
+ case TRIGGER_NETDEV_TX:
|
||||
+ case TRIGGER_NETDEV_RX:
|
||||
+ bit = attr;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -360,21 +352,21 @@ static void netdev_trig_work(struct work
|
||||
}
|
||||
|
||||
/* If we are not looking for RX/TX then return */
|
||||
- if (!test_bit(NETDEV_LED_TX, &trigger_data->mode) &&
|
||||
- !test_bit(NETDEV_LED_RX, &trigger_data->mode))
|
||||
+ if (!test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) &&
|
||||
+ !test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode))
|
||||
return;
|
||||
|
||||
dev_stats = dev_get_stats(trigger_data->net_dev, &temp);
|
||||
new_activity =
|
||||
- (test_bit(NETDEV_LED_TX, &trigger_data->mode) ?
|
||||
+ (test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) ?
|
||||
dev_stats->tx_packets : 0) +
|
||||
- (test_bit(NETDEV_LED_RX, &trigger_data->mode) ?
|
||||
+ (test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode) ?
|
||||
dev_stats->rx_packets : 0);
|
||||
|
||||
if (trigger_data->last_activity != new_activity) {
|
||||
led_stop_software_blink(trigger_data->led_cdev);
|
||||
|
||||
- invert = test_bit(NETDEV_LED_LINK, &trigger_data->mode);
|
||||
+ invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode);
|
||||
interval = jiffies_to_msecs(
|
||||
atomic_read(&trigger_data->interval));
|
||||
/* base state is ON (link present) */
|
@@ -0,0 +1,82 @@
|
||||
From 164b67d53476a9d114be85c885bd31f783835be4 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 19 Apr 2023 23:07:42 +0200
|
||||
Subject: [PATCH 4/5] leds: trigger: netdev: Convert device attr to macro
|
||||
|
||||
Convert link tx and rx device attr to a common macro to reduce common
|
||||
code and in preparation for additional attr.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Lee Jones <lee@kernel.org>
|
||||
Link: https://lore.kernel.org/r/20230419210743.3594-5-ansuelsmth@gmail.com
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 57 ++++++++-------------------
|
||||
1 file changed, 16 insertions(+), 41 deletions(-)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -198,47 +198,22 @@ static ssize_t netdev_led_attr_store(str
|
||||
return size;
|
||||
}
|
||||
|
||||
-static ssize_t link_show(struct device *dev,
|
||||
- struct device_attribute *attr, char *buf)
|
||||
-{
|
||||
- return netdev_led_attr_show(dev, buf, NETDEV_ATTR_LINK);
|
||||
-}
|
||||
-
|
||||
-static ssize_t link_store(struct device *dev,
|
||||
- struct device_attribute *attr, const char *buf, size_t size)
|
||||
-{
|
||||
- return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_LINK);
|
||||
-}
|
||||
-
|
||||
-static DEVICE_ATTR_RW(link);
|
||||
-
|
||||
-static ssize_t tx_show(struct device *dev,
|
||||
- struct device_attribute *attr, char *buf)
|
||||
-{
|
||||
- return netdev_led_attr_show(dev, buf, NETDEV_ATTR_TX);
|
||||
-}
|
||||
-
|
||||
-static ssize_t tx_store(struct device *dev,
|
||||
- struct device_attribute *attr, const char *buf, size_t size)
|
||||
-{
|
||||
- return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_TX);
|
||||
-}
|
||||
-
|
||||
-static DEVICE_ATTR_RW(tx);
|
||||
-
|
||||
-static ssize_t rx_show(struct device *dev,
|
||||
- struct device_attribute *attr, char *buf)
|
||||
-{
|
||||
- return netdev_led_attr_show(dev, buf, NETDEV_ATTR_RX);
|
||||
-}
|
||||
-
|
||||
-static ssize_t rx_store(struct device *dev,
|
||||
- struct device_attribute *attr, const char *buf, size_t size)
|
||||
-{
|
||||
- return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_RX);
|
||||
-}
|
||||
-
|
||||
-static DEVICE_ATTR_RW(rx);
|
||||
+#define DEFINE_NETDEV_TRIGGER(trigger_name, trigger) \
|
||||
+ static ssize_t trigger_name##_show(struct device *dev, \
|
||||
+ struct device_attribute *attr, char *buf) \
|
||||
+ { \
|
||||
+ return netdev_led_attr_show(dev, buf, trigger); \
|
||||
+ } \
|
||||
+ static ssize_t trigger_name##_store(struct device *dev, \
|
||||
+ struct device_attribute *attr, const char *buf, size_t size) \
|
||||
+ { \
|
||||
+ return netdev_led_attr_store(dev, buf, size, trigger); \
|
||||
+ } \
|
||||
+ static DEVICE_ATTR_RW(trigger_name)
|
||||
+
|
||||
+DEFINE_NETDEV_TRIGGER(link, TRIGGER_NETDEV_LINK);
|
||||
+DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX);
|
||||
+DEFINE_NETDEV_TRIGGER(rx, TRIGGER_NETDEV_RX);
|
||||
|
||||
static ssize_t interval_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
@@ -0,0 +1,106 @@
|
||||
From d1b9e1391ab2dc80e9db87fe8b2de015c651e4c9 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 19 Apr 2023 23:07:43 +0200
|
||||
Subject: [PATCH 5/5] leds: trigger: netdev: Use mutex instead of spinlocks
|
||||
|
||||
Some LEDs may require to sleep while doing some operation like setting
|
||||
brightness and other cleanup.
|
||||
|
||||
For this reason, using a spinlock will cause a sleep under spinlock
|
||||
warning.
|
||||
|
||||
It should be safe to convert this to a sleepable lock since:
|
||||
- sysfs read/write can sleep
|
||||
- netdev_trig_work is a work queue and can sleep
|
||||
- netdev _trig_notify can sleep
|
||||
|
||||
The spinlock was used when brightness didn't support sleeping, but this
|
||||
changed and now it supported with brightness_set_blocking().
|
||||
|
||||
Convert to mutex lock to permit sleeping using brightness_set_blocking().
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Lee Jones <lee@kernel.org>
|
||||
Link: https://lore.kernel.org/r/20230419210743.3594-6-ansuelsmth@gmail.com
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 18 +++++++++---------
|
||||
1 file changed, 9 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
-#include <linux/spinlock.h>
|
||||
+#include <linux/mutex.h>
|
||||
#include <linux/timer.h>
|
||||
#include "../leds.h"
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
*/
|
||||
|
||||
struct led_netdev_data {
|
||||
- spinlock_t lock;
|
||||
+ struct mutex lock;
|
||||
|
||||
struct delayed_work work;
|
||||
struct notifier_block notifier;
|
||||
@@ -97,9 +97,9 @@ static ssize_t device_name_show(struct d
|
||||
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
ssize_t len;
|
||||
|
||||
- spin_lock_bh(&trigger_data->lock);
|
||||
+ mutex_lock(&trigger_data->lock);
|
||||
len = sprintf(buf, "%s\n", trigger_data->device_name);
|
||||
- spin_unlock_bh(&trigger_data->lock);
|
||||
+ mutex_unlock(&trigger_data->lock);
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -115,7 +115,7 @@ static ssize_t device_name_store(struct
|
||||
|
||||
cancel_delayed_work_sync(&trigger_data->work);
|
||||
|
||||
- spin_lock_bh(&trigger_data->lock);
|
||||
+ mutex_lock(&trigger_data->lock);
|
||||
|
||||
if (trigger_data->net_dev) {
|
||||
dev_put(trigger_data->net_dev);
|
||||
@@ -138,7 +138,7 @@ static ssize_t device_name_store(struct
|
||||
trigger_data->last_activity = 0;
|
||||
|
||||
set_baseline_state(trigger_data);
|
||||
- spin_unlock_bh(&trigger_data->lock);
|
||||
+ mutex_unlock(&trigger_data->lock);
|
||||
|
||||
return size;
|
||||
}
|
||||
@@ -279,7 +279,7 @@ static int netdev_trig_notify(struct not
|
||||
|
||||
cancel_delayed_work_sync(&trigger_data->work);
|
||||
|
||||
- spin_lock_bh(&trigger_data->lock);
|
||||
+ mutex_lock(&trigger_data->lock);
|
||||
|
||||
trigger_data->carrier_link_up = false;
|
||||
switch (evt) {
|
||||
@@ -304,7 +304,7 @@ static int netdev_trig_notify(struct not
|
||||
|
||||
set_baseline_state(trigger_data);
|
||||
|
||||
- spin_unlock_bh(&trigger_data->lock);
|
||||
+ mutex_unlock(&trigger_data->lock);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
@@ -365,7 +365,7 @@ static int netdev_trig_activate(struct l
|
||||
if (!trigger_data)
|
||||
return -ENOMEM;
|
||||
|
||||
- spin_lock_init(&trigger_data->lock);
|
||||
+ mutex_init(&trigger_data->lock);
|
||||
|
||||
trigger_data->notifier.notifier_call = netdev_trig_notify;
|
||||
trigger_data->notifier.priority = 10;
|
@@ -0,0 +1,74 @@
|
||||
From ed554d3f945179c5b159bddfad7be34b403fe11a Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 29 May 2023 18:32:31 +0200
|
||||
Subject: [PATCH 01/13] leds: add APIs for LEDs hw control
|
||||
|
||||
Add an option to permit LED driver to declare support for a specific
|
||||
trigger to use hw control and setup the LED to blink based on specific
|
||||
provided modes.
|
||||
|
||||
Add APIs for LEDs hw control. These functions will be used to activate
|
||||
hardware control where a LED will use the provided flags, from an
|
||||
unique defined supported trigger, to setup the LED to be driven by
|
||||
hardware.
|
||||
|
||||
Add hw_control_is_supported() to ask the LED driver if the requested
|
||||
mode by the trigger are supported and the LED can be setup to follow
|
||||
the requested modes.
|
||||
|
||||
Deactivate hardware blink control by setting brightness to LED_OFF via
|
||||
the brightness_set() callback.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/linux/leds.h | 37 +++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 37 insertions(+)
|
||||
|
||||
--- a/include/linux/leds.h
|
||||
+++ b/include/linux/leds.h
|
||||
@@ -164,6 +164,43 @@ struct led_classdev {
|
||||
|
||||
/* LEDs that have private triggers have this set */
|
||||
struct led_hw_trigger_type *trigger_type;
|
||||
+
|
||||
+ /* Unique trigger name supported by LED set in hw control mode */
|
||||
+ const char *hw_control_trigger;
|
||||
+ /*
|
||||
+ * Check if the LED driver supports the requested mode provided by the
|
||||
+ * defined supported trigger to setup the LED to hw control mode.
|
||||
+ *
|
||||
+ * Return 0 on success. Return -EOPNOTSUPP when the passed flags are not
|
||||
+ * supported and software fallback needs to be used.
|
||||
+ * Return a negative error number on any other case for check fail due
|
||||
+ * to various reason like device not ready or timeouts.
|
||||
+ */
|
||||
+ int (*hw_control_is_supported)(struct led_classdev *led_cdev,
|
||||
+ unsigned long flags);
|
||||
+ /*
|
||||
+ * Activate hardware control, LED driver will use the provided flags
|
||||
+ * from the supported trigger and setup the LED to be driven by hardware
|
||||
+ * following the requested mode from the trigger flags.
|
||||
+ * Deactivate hardware blink control by setting brightness to LED_OFF via
|
||||
+ * the brightness_set() callback.
|
||||
+ *
|
||||
+ * Return 0 on success, a negative error number on flags apply fail.
|
||||
+ */
|
||||
+ int (*hw_control_set)(struct led_classdev *led_cdev,
|
||||
+ unsigned long flags);
|
||||
+ /*
|
||||
+ * Get from the LED driver the current mode that the LED is set in hw
|
||||
+ * control mode and put them in flags.
|
||||
+ * Trigger can use this to get the initial state of a LED already set in
|
||||
+ * hardware blink control.
|
||||
+ *
|
||||
+ * Return 0 on success, a negative error number on failing parsing the
|
||||
+ * initial mode. Error from this function is NOT FATAL as the device
|
||||
+ * may be in a not supported initial state by the attached LED trigger.
|
||||
+ */
|
||||
+ int (*hw_control_get)(struct led_classdev *led_cdev,
|
||||
+ unsigned long *flags);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
|
@@ -0,0 +1,37 @@
|
||||
From 052c38eb17e866c5b4cd43924e7a5e20167b55c0 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Lunn <andrew@lunn.ch>
|
||||
Date: Mon, 29 May 2023 18:32:32 +0200
|
||||
Subject: [PATCH 02/13] leds: add API to get attached device for LED hw control
|
||||
|
||||
Some specific LED triggers blink the LED based on events from a device
|
||||
or subsystem.
|
||||
For example, an LED could be blinked to indicate a network device is
|
||||
receiving packets, or a disk is reading blocks. To correctly enable and
|
||||
request the hw control of the LED, the trigger has to check if the
|
||||
network interface or block device configured via a /sys/class/led file
|
||||
match the one the LED driver provide for hw control for.
|
||||
|
||||
Provide an API call to get the device which the LED blinks for.
|
||||
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/linux/leds.h | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
--- a/include/linux/leds.h
|
||||
+++ b/include/linux/leds.h
|
||||
@@ -201,6 +201,12 @@ struct led_classdev {
|
||||
*/
|
||||
int (*hw_control_get)(struct led_classdev *led_cdev,
|
||||
unsigned long *flags);
|
||||
+ /*
|
||||
+ * Get the device this LED blinks in response to.
|
||||
+ * e.g. for a PHY LED, it is the network device. If the LED is
|
||||
+ * not yet associated to a device, return NULL.
|
||||
+ */
|
||||
+ struct device *(*hw_control_get_device)(struct led_classdev *led_cdev);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
|
@@ -0,0 +1,113 @@
|
||||
From 8aa2fd7b66980ecd2e45e95af61cf7eafede1211 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 29 May 2023 18:32:33 +0200
|
||||
Subject: [PATCH 03/13] Documentation: leds: leds-class: Document new Hardware
|
||||
driven LEDs APIs
|
||||
|
||||
Document new Hardware driven LEDs APIs.
|
||||
|
||||
Some LEDs can be programmed to be driven by hardware. This is not
|
||||
limited to blink but also to turn off or on autonomously.
|
||||
To support this feature, a LED needs to implement various additional
|
||||
ops and needs to declare specific support for the supported triggers.
|
||||
|
||||
Add documentation for each required value and API to make hw control
|
||||
possible and implementable by both LEDs and triggers.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
Documentation/leds/leds-class.rst | 81 +++++++++++++++++++++++++++++++
|
||||
1 file changed, 81 insertions(+)
|
||||
|
||||
--- a/Documentation/leds/leds-class.rst
|
||||
+++ b/Documentation/leds/leds-class.rst
|
||||
@@ -169,6 +169,87 @@ Setting the brightness to zero with brig
|
||||
should completely turn off the LED and cancel the previously programmed
|
||||
hardware blinking function, if any.
|
||||
|
||||
+Hardware driven LEDs
|
||||
+====================
|
||||
+
|
||||
+Some LEDs can be programmed to be driven by hardware. This is not
|
||||
+limited to blink but also to turn off or on autonomously.
|
||||
+To support this feature, a LED needs to implement various additional
|
||||
+ops and needs to declare specific support for the supported triggers.
|
||||
+
|
||||
+With hw control we refer to the LED driven by hardware.
|
||||
+
|
||||
+LED driver must define the following value to support hw control:
|
||||
+
|
||||
+ - hw_control_trigger:
|
||||
+ unique trigger name supported by the LED in hw control
|
||||
+ mode.
|
||||
+
|
||||
+LED driver must implement the following API to support hw control:
|
||||
+ - hw_control_is_supported:
|
||||
+ check if the flags passed by the supported trigger can
|
||||
+ be parsed and activate hw control on the LED.
|
||||
+
|
||||
+ Return 0 if the passed flags mask is supported and
|
||||
+ can be set with hw_control_set().
|
||||
+
|
||||
+ If the passed flags mask is not supported -EOPNOTSUPP
|
||||
+ must be returned, the LED trigger will use software
|
||||
+ fallback in this case.
|
||||
+
|
||||
+ Return a negative error in case of any other error like
|
||||
+ device not ready or timeouts.
|
||||
+
|
||||
+ - hw_control_set:
|
||||
+ activate hw control. LED driver will use the provided
|
||||
+ flags passed from the supported trigger, parse them to
|
||||
+ a set of mode and setup the LED to be driven by hardware
|
||||
+ following the requested modes.
|
||||
+
|
||||
+ Set LED_OFF via the brightness_set to deactivate hw control.
|
||||
+
|
||||
+ Return 0 on success, a negative error number on failing to
|
||||
+ apply flags.
|
||||
+
|
||||
+ - hw_control_get:
|
||||
+ get active modes from a LED already in hw control, parse
|
||||
+ them and set in flags the current active flags for the
|
||||
+ supported trigger.
|
||||
+
|
||||
+ Return 0 on success, a negative error number on failing
|
||||
+ parsing the initial mode.
|
||||
+ Error from this function is NOT FATAL as the device may
|
||||
+ be in a not supported initial state by the attached LED
|
||||
+ trigger.
|
||||
+
|
||||
+ - hw_control_get_device:
|
||||
+ return the device associated with the LED driver in
|
||||
+ hw control. A trigger might use this to match the
|
||||
+ returned device from this function with a configured
|
||||
+ device for the trigger as the source for blinking
|
||||
+ events and correctly enable hw control.
|
||||
+ (example a netdev trigger configured to blink for a
|
||||
+ particular dev match the returned dev from get_device
|
||||
+ to set hw control)
|
||||
+
|
||||
+ Returns a pointer to a struct device or NULL if nothing
|
||||
+ is currently attached.
|
||||
+
|
||||
+LED driver can activate additional modes by default to workaround the
|
||||
+impossibility of supporting each different mode on the supported trigger.
|
||||
+Examples are hardcoding the blink speed to a set interval, enable special
|
||||
+feature like bypassing blink if some requirements are not met.
|
||||
+
|
||||
+A trigger should first check if the hw control API are supported by the LED
|
||||
+driver and check if the trigger is supported to verify if hw control is possible,
|
||||
+use hw_control_is_supported to check if the flags are supported and only at
|
||||
+the end use hw_control_set to activate hw control.
|
||||
+
|
||||
+A trigger can use hw_control_get to check if a LED is already in hw control
|
||||
+and init their flags.
|
||||
+
|
||||
+When the LED is in hw control, no software blink is possible and doing so
|
||||
+will effectively disable hw control.
|
||||
|
||||
Known Issues
|
||||
============
|
@@ -0,0 +1,69 @@
|
||||
From 28a6a2ef18ad840a390d519840c303b03040961c Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Lunn <andrew@lunn.ch>
|
||||
Date: Mon, 29 May 2023 18:32:34 +0200
|
||||
Subject: [PATCH 04/13] leds: trigger: netdev: refactor code setting device
|
||||
name
|
||||
|
||||
Move the code into a helper, ready for it to be called at
|
||||
other times. No intended behaviour change.
|
||||
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 29 ++++++++++++++++++---------
|
||||
1 file changed, 20 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -104,15 +104,9 @@ static ssize_t device_name_show(struct d
|
||||
return len;
|
||||
}
|
||||
|
||||
-static ssize_t device_name_store(struct device *dev,
|
||||
- struct device_attribute *attr, const char *buf,
|
||||
- size_t size)
|
||||
+static int set_device_name(struct led_netdev_data *trigger_data,
|
||||
+ const char *name, size_t size)
|
||||
{
|
||||
- struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
-
|
||||
- if (size >= IFNAMSIZ)
|
||||
- return -EINVAL;
|
||||
-
|
||||
cancel_delayed_work_sync(&trigger_data->work);
|
||||
|
||||
mutex_lock(&trigger_data->lock);
|
||||
@@ -122,7 +116,7 @@ static ssize_t device_name_store(struct
|
||||
trigger_data->net_dev = NULL;
|
||||
}
|
||||
|
||||
- memcpy(trigger_data->device_name, buf, size);
|
||||
+ memcpy(trigger_data->device_name, name, size);
|
||||
trigger_data->device_name[size] = 0;
|
||||
if (size > 0 && trigger_data->device_name[size - 1] == '\n')
|
||||
trigger_data->device_name[size - 1] = 0;
|
||||
@@ -140,6 +134,23 @@ static ssize_t device_name_store(struct
|
||||
set_baseline_state(trigger_data);
|
||||
mutex_unlock(&trigger_data->lock);
|
||||
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static ssize_t device_name_store(struct device *dev,
|
||||
+ struct device_attribute *attr, const char *buf,
|
||||
+ size_t size)
|
||||
+{
|
||||
+ struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
+ int ret;
|
||||
+
|
||||
+ if (size >= IFNAMSIZ)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ ret = set_device_name(trigger_data, buf, size);
|
||||
+
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
return size;
|
||||
}
|
||||
|
@@ -0,0 +1,54 @@
|
||||
From 4fd1b6d47a7a38e81fdc6f8be2ccd4216b3f93db Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 29 May 2023 18:32:35 +0200
|
||||
Subject: [PATCH 05/13] leds: trigger: netdev: introduce check for possible hw
|
||||
control
|
||||
|
||||
Introduce function to check if the requested mode can use hw control in
|
||||
preparation for hw control support. Currently everything is handled in
|
||||
software so can_hw_control will always return false.
|
||||
|
||||
Add knob with the new value hw_control in trigger_data struct to
|
||||
set hw control possible. Useful for future implementation to implement
|
||||
in set_baseline_state() the required function to set the requested mode
|
||||
using LEDs hw control ops and in other function to reject set if hw
|
||||
control is currently active.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -51,6 +51,7 @@ struct led_netdev_data {
|
||||
|
||||
unsigned long mode;
|
||||
bool carrier_link_up;
|
||||
+ bool hw_control;
|
||||
};
|
||||
|
||||
enum led_trigger_netdev_modes {
|
||||
@@ -91,6 +92,11 @@ static void set_baseline_state(struct le
|
||||
}
|
||||
}
|
||||
|
||||
+static bool can_hw_control(struct led_netdev_data *trigger_data)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
static ssize_t device_name_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -204,6 +210,8 @@ static ssize_t netdev_led_attr_store(str
|
||||
else
|
||||
clear_bit(bit, &trigger_data->mode);
|
||||
|
||||
+ trigger_data->hw_control = can_hw_control(trigger_data);
|
||||
+
|
||||
set_baseline_state(trigger_data);
|
||||
|
||||
return size;
|
@@ -0,0 +1,42 @@
|
||||
From 6352f25f9fadba59d5df2ba7139495759ccc81d5 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 29 May 2023 18:32:36 +0200
|
||||
Subject: [PATCH 06/13] leds: trigger: netdev: add basic check for hw control
|
||||
support
|
||||
|
||||
Add basic check for hw control support. Check if the required API are
|
||||
defined and check if the defined trigger supported in hw control for the
|
||||
LED driver match netdev.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -92,8 +92,22 @@ static void set_baseline_state(struct le
|
||||
}
|
||||
}
|
||||
|
||||
+static bool supports_hw_control(struct led_classdev *led_cdev)
|
||||
+{
|
||||
+ if (!led_cdev->hw_control_get || !led_cdev->hw_control_set ||
|
||||
+ !led_cdev->hw_control_is_supported)
|
||||
+ return false;
|
||||
+
|
||||
+ return !strcmp(led_cdev->hw_control_trigger, led_cdev->trigger->name);
|
||||
+}
|
||||
+
|
||||
static bool can_hw_control(struct led_netdev_data *trigger_data)
|
||||
{
|
||||
+ struct led_classdev *led_cdev = trigger_data->led_cdev;
|
||||
+
|
||||
+ if (!supports_hw_control(led_cdev))
|
||||
+ return false;
|
||||
+
|
||||
return false;
|
||||
}
|
||||
|
@@ -0,0 +1,28 @@
|
||||
From c84c80c7388f887b10dafd70fc55bc6c5fe9fa5a Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 29 May 2023 18:32:37 +0200
|
||||
Subject: [PATCH 07/13] leds: trigger: netdev: reject interval store for
|
||||
hw_control
|
||||
|
||||
Reject interval store with hw_control enabled. It's are currently not
|
||||
supported and MUST be set to the default value with hw control enabled.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -265,6 +265,9 @@ static ssize_t interval_store(struct dev
|
||||
unsigned long value;
|
||||
int ret;
|
||||
|
||||
+ if (trigger_data->hw_control)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
ret = kstrtoul(buf, 0, &value);
|
||||
if (ret)
|
||||
return ret;
|
@@ -0,0 +1,107 @@
|
||||
From 7c145a34ba6e380616af93262fcab9fc7261d851 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 29 May 2023 18:32:38 +0200
|
||||
Subject: [PATCH 08/13] leds: trigger: netdev: add support for LED hw control
|
||||
|
||||
Add support for LED hw control for the netdev trigger.
|
||||
|
||||
The trigger on calling set_baseline_state to configure a new mode, will
|
||||
do various check to verify if hw control can be used for the requested
|
||||
mode in can_hw_control() function.
|
||||
|
||||
It will first check if the LED driver supports hw control for the netdev
|
||||
trigger, then will use hw_control_is_supported() and finally will call
|
||||
hw_control_set() to apply the requested mode.
|
||||
|
||||
To use such mode, interval MUST be set to the default value and net_dev
|
||||
MUST be set. If one of these 2 value are not valid, hw control will
|
||||
never be used and normal software fallback is used.
|
||||
|
||||
The default interval value is moved to a define to make sure they are
|
||||
always synced.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 43 +++++++++++++++++++++++++--
|
||||
1 file changed, 41 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -24,6 +24,8 @@
|
||||
#include <linux/timer.h>
|
||||
#include "../leds.h"
|
||||
|
||||
+#define NETDEV_LED_DEFAULT_INTERVAL 50
|
||||
+
|
||||
/*
|
||||
* Configurable sysfs attributes:
|
||||
*
|
||||
@@ -68,6 +70,13 @@ static void set_baseline_state(struct le
|
||||
int current_brightness;
|
||||
struct led_classdev *led_cdev = trigger_data->led_cdev;
|
||||
|
||||
+ /* Already validated, hw control is possible with the requested mode */
|
||||
+ if (trigger_data->hw_control) {
|
||||
+ led_cdev->hw_control_set(led_cdev, trigger_data->mode);
|
||||
+
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
current_brightness = led_cdev->brightness;
|
||||
if (current_brightness)
|
||||
led_cdev->blink_brightness = current_brightness;
|
||||
@@ -103,12 +112,42 @@ static bool supports_hw_control(struct l
|
||||
|
||||
static bool can_hw_control(struct led_netdev_data *trigger_data)
|
||||
{
|
||||
+ unsigned long default_interval = msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL);
|
||||
+ unsigned int interval = atomic_read(&trigger_data->interval);
|
||||
struct led_classdev *led_cdev = trigger_data->led_cdev;
|
||||
+ int ret;
|
||||
|
||||
if (!supports_hw_control(led_cdev))
|
||||
return false;
|
||||
|
||||
- return false;
|
||||
+ /*
|
||||
+ * Interval must be set to the default
|
||||
+ * value. Any different value is rejected if in hw
|
||||
+ * control.
|
||||
+ */
|
||||
+ if (interval != default_interval)
|
||||
+ return false;
|
||||
+
|
||||
+ /*
|
||||
+ * net_dev must be set with hw control, otherwise no
|
||||
+ * blinking can be happening and there is nothing to
|
||||
+ * offloaded.
|
||||
+ */
|
||||
+ if (!trigger_data->net_dev)
|
||||
+ return false;
|
||||
+
|
||||
+ /* Check if the requested mode is supported */
|
||||
+ ret = led_cdev->hw_control_is_supported(led_cdev, trigger_data->mode);
|
||||
+ /* Fall back to software blinking if not supported */
|
||||
+ if (ret == -EOPNOTSUPP)
|
||||
+ return false;
|
||||
+ if (ret) {
|
||||
+ dev_warn(led_cdev->dev,
|
||||
+ "Current mode check failed with error %d\n", ret);
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
}
|
||||
|
||||
static ssize_t device_name_show(struct device *dev,
|
||||
@@ -413,7 +452,7 @@ static int netdev_trig_activate(struct l
|
||||
trigger_data->device_name[0] = 0;
|
||||
|
||||
trigger_data->mode = 0;
|
||||
- atomic_set(&trigger_data->interval, msecs_to_jiffies(50));
|
||||
+ atomic_set(&trigger_data->interval, msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL));
|
||||
trigger_data->last_activity = 0;
|
||||
|
||||
led_set_trigger_data(led_cdev, trigger_data);
|
@@ -0,0 +1,58 @@
|
||||
From 33ec0b53befff2c0a7f3aa19ff08556d60585d6b Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Lunn <andrew@lunn.ch>
|
||||
Date: Mon, 29 May 2023 18:32:39 +0200
|
||||
Subject: [PATCH 09/13] leds: trigger: netdev: validate configured netdev
|
||||
|
||||
The netdev which the LED should blink for is configurable in
|
||||
/sys/class/led/foo/device_name. Ensure when offloading that the
|
||||
configured netdev is the same as the netdev the LED is associated
|
||||
with. If it is not, only perform software blinking.
|
||||
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 24 ++++++++++++++++++++++--
|
||||
1 file changed, 22 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -110,6 +110,24 @@ static bool supports_hw_control(struct l
|
||||
return !strcmp(led_cdev->hw_control_trigger, led_cdev->trigger->name);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Validate the configured netdev is the same as the one associated with
|
||||
+ * the LED driver in hw control.
|
||||
+ */
|
||||
+static bool validate_net_dev(struct led_classdev *led_cdev,
|
||||
+ struct net_device *net_dev)
|
||||
+{
|
||||
+ struct device *dev = led_cdev->hw_control_get_device(led_cdev);
|
||||
+ struct net_device *ndev;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return false;
|
||||
+
|
||||
+ ndev = to_net_dev(dev);
|
||||
+
|
||||
+ return ndev == net_dev;
|
||||
+}
|
||||
+
|
||||
static bool can_hw_control(struct led_netdev_data *trigger_data)
|
||||
{
|
||||
unsigned long default_interval = msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL);
|
||||
@@ -131,9 +149,11 @@ static bool can_hw_control(struct led_ne
|
||||
/*
|
||||
* net_dev must be set with hw control, otherwise no
|
||||
* blinking can be happening and there is nothing to
|
||||
- * offloaded.
|
||||
+ * offloaded. Additionally, for hw control to be
|
||||
+ * valid, the configured netdev must be the same as
|
||||
+ * netdev associated to the LED.
|
||||
*/
|
||||
- if (!trigger_data->net_dev)
|
||||
+ if (!validate_net_dev(led_cdev, trigger_data->net_dev))
|
||||
return false;
|
||||
|
||||
/* Check if the requested mode is supported */
|
@@ -0,0 +1,53 @@
|
||||
From 0316cc5629d15880dd3f097d221c55ca648bcd61 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 29 May 2023 18:32:40 +0200
|
||||
Subject: [PATCH 10/13] leds: trigger: netdev: init mode if hw control already
|
||||
active
|
||||
|
||||
On netdev trigger activation, hw control may be already active by
|
||||
default. If this is the case and a device is actually provided by
|
||||
hw_control_get_device(), init the already active mode and set the
|
||||
bool to hw_control bool to true to reflect the already set mode in the
|
||||
trigger_data.
|
||||
|
||||
Co-developed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 17 +++++++++++++++++
|
||||
1 file changed, 17 insertions(+)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -454,6 +454,8 @@ static void netdev_trig_work(struct work
|
||||
static int netdev_trig_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct led_netdev_data *trigger_data;
|
||||
+ unsigned long mode;
|
||||
+ struct device *dev;
|
||||
int rc;
|
||||
|
||||
trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
|
||||
@@ -475,6 +477,21 @@ static int netdev_trig_activate(struct l
|
||||
atomic_set(&trigger_data->interval, msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL));
|
||||
trigger_data->last_activity = 0;
|
||||
|
||||
+ /* Check if hw control is active by default on the LED.
|
||||
+ * Init already enabled mode in hw control.
|
||||
+ */
|
||||
+ if (supports_hw_control(led_cdev) &&
|
||||
+ !led_cdev->hw_control_get(led_cdev, &mode)) {
|
||||
+ dev = led_cdev->hw_control_get_device(led_cdev);
|
||||
+ if (dev) {
|
||||
+ const char *name = dev_name(dev);
|
||||
+
|
||||
+ set_device_name(trigger_data, name, strlen(name));
|
||||
+ trigger_data->hw_control = true;
|
||||
+ trigger_data->mode = mode;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
led_set_trigger_data(led_cdev, trigger_data);
|
||||
|
||||
rc = register_netdevice_notifier(&trigger_data->notifier);
|
@@ -0,0 +1,54 @@
|
||||
From 947acacab5ea151291b861cdfbde16ff5cf1b08c Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 29 May 2023 18:32:41 +0200
|
||||
Subject: [PATCH 11/13] leds: trigger: netdev: expose netdev trigger modes in
|
||||
linux include
|
||||
|
||||
Expose netdev trigger modes to make them accessible by LED driver that
|
||||
will support netdev trigger for hw control.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 9 ---------
|
||||
include/linux/leds.h | 10 ++++++++++
|
||||
2 files changed, 10 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -56,15 +56,6 @@ struct led_netdev_data {
|
||||
bool hw_control;
|
||||
};
|
||||
|
||||
-enum led_trigger_netdev_modes {
|
||||
- TRIGGER_NETDEV_LINK = 0,
|
||||
- TRIGGER_NETDEV_TX,
|
||||
- TRIGGER_NETDEV_RX,
|
||||
-
|
||||
- /* Keep last */
|
||||
- __TRIGGER_NETDEV_MAX,
|
||||
-};
|
||||
-
|
||||
static void set_baseline_state(struct led_netdev_data *trigger_data)
|
||||
{
|
||||
int current_brightness;
|
||||
--- a/include/linux/leds.h
|
||||
+++ b/include/linux/leds.h
|
||||
@@ -527,6 +527,16 @@ static inline void *led_get_trigger_data
|
||||
|
||||
#endif /* CONFIG_LEDS_TRIGGERS */
|
||||
|
||||
+/* Trigger specific enum */
|
||||
+enum led_trigger_netdev_modes {
|
||||
+ TRIGGER_NETDEV_LINK = 0,
|
||||
+ TRIGGER_NETDEV_TX,
|
||||
+ TRIGGER_NETDEV_RX,
|
||||
+
|
||||
+ /* Keep last */
|
||||
+ __TRIGGER_NETDEV_MAX,
|
||||
+};
|
||||
+
|
||||
/* Trigger specific functions */
|
||||
#ifdef CONFIG_LEDS_TRIGGER_DISK
|
||||
void ledtrig_disk_activity(bool write);
|
@@ -0,0 +1,200 @@
|
||||
From e0256648c831af13cbfe4a1787327fcec01c2807 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 29 May 2023 18:32:42 +0200
|
||||
Subject: [PATCH 12/13] net: dsa: qca8k: implement hw_control ops
|
||||
|
||||
Implement hw_control ops to drive Switch LEDs based on hardware events.
|
||||
|
||||
Netdev trigger is the declared supported trigger for hw control
|
||||
operation and supports the following mode:
|
||||
- tx
|
||||
- rx
|
||||
|
||||
When hw_control_set is called, LEDs are set to follow the requested
|
||||
mode.
|
||||
Each LEDs will blink at 4Hz by default.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-leds.c | 154 +++++++++++++++++++++++++++++++
|
||||
1 file changed, 154 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-leds.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-leds.c
|
||||
@@ -32,6 +32,43 @@ qca8k_get_enable_led_reg(int port_num, i
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_get_control_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info)
|
||||
+{
|
||||
+ reg_info->reg = QCA8K_LED_CTRL_REG(led_num);
|
||||
+
|
||||
+ /* 6 total control rule:
|
||||
+ * 3 control rules for phy0-3 that applies to all their leds
|
||||
+ * 3 control rules for phy4
|
||||
+ */
|
||||
+ if (port_num == 4)
|
||||
+ reg_info->shift = QCA8K_LED_PHY4_CONTROL_RULE_SHIFT;
|
||||
+ else
|
||||
+ reg_info->shift = QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_parse_netdev(unsigned long rules, u32 *offload_trigger)
|
||||
+{
|
||||
+ /* Parsing specific to netdev trigger */
|
||||
+ if (test_bit(TRIGGER_NETDEV_TX, &rules))
|
||||
+ *offload_trigger |= QCA8K_LED_TX_BLINK_MASK;
|
||||
+ if (test_bit(TRIGGER_NETDEV_RX, &rules))
|
||||
+ *offload_trigger |= QCA8K_LED_RX_BLINK_MASK;
|
||||
+
|
||||
+ if (rules && !*offload_trigger)
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
+ /* Enable some default rule by default to the requested mode:
|
||||
+ * - Blink at 4Hz by default
|
||||
+ */
|
||||
+ *offload_trigger |= QCA8K_LED_BLINK_4HZ;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_led_brightness_set(struct qca8k_led *led,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
@@ -165,6 +202,119 @@ qca8k_cled_blink_set(struct led_classdev
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_cled_trigger_offload(struct led_classdev *ldev, bool enable)
|
||||
+{
|
||||
+ struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
|
||||
+
|
||||
+ struct qca8k_led_pattern_en reg_info;
|
||||
+ struct qca8k_priv *priv = led->priv;
|
||||
+ u32 mask, val = QCA8K_LED_ALWAYS_OFF;
|
||||
+
|
||||
+ qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info);
|
||||
+
|
||||
+ if (enable)
|
||||
+ val = QCA8K_LED_RULE_CONTROLLED;
|
||||
+
|
||||
+ if (led->port_num == 0 || led->port_num == 4) {
|
||||
+ mask = QCA8K_LED_PATTERN_EN_MASK;
|
||||
+ val <<= QCA8K_LED_PATTERN_EN_SHIFT;
|
||||
+ } else {
|
||||
+ mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;
|
||||
+ }
|
||||
+
|
||||
+ return regmap_update_bits(priv->regmap, reg_info.reg, mask << reg_info.shift,
|
||||
+ val << reg_info.shift);
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
+qca8k_cled_hw_control_status(struct led_classdev *ldev)
|
||||
+{
|
||||
+ struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
|
||||
+
|
||||
+ struct qca8k_led_pattern_en reg_info;
|
||||
+ struct qca8k_priv *priv = led->priv;
|
||||
+ u32 val;
|
||||
+
|
||||
+ qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info);
|
||||
+
|
||||
+ regmap_read(priv->regmap, reg_info.reg, &val);
|
||||
+
|
||||
+ val >>= reg_info.shift;
|
||||
+
|
||||
+ if (led->port_num == 0 || led->port_num == 4) {
|
||||
+ val &= QCA8K_LED_PATTERN_EN_MASK;
|
||||
+ val >>= QCA8K_LED_PATTERN_EN_SHIFT;
|
||||
+ } else {
|
||||
+ val &= QCA8K_LED_PHY123_PATTERN_EN_MASK;
|
||||
+ }
|
||||
+
|
||||
+ return val == QCA8K_LED_RULE_CONTROLLED;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_cled_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules)
|
||||
+{
|
||||
+ u32 offload_trigger = 0;
|
||||
+
|
||||
+ return qca8k_parse_netdev(rules, &offload_trigger);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_cled_hw_control_set(struct led_classdev *ldev, unsigned long rules)
|
||||
+{
|
||||
+ struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
|
||||
+ struct qca8k_led_pattern_en reg_info;
|
||||
+ struct qca8k_priv *priv = led->priv;
|
||||
+ u32 offload_trigger = 0;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = qca8k_parse_netdev(rules, &offload_trigger);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = qca8k_cled_trigger_offload(ldev, true);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ qca8k_get_control_led_reg(led->port_num, led->led_num, ®_info);
|
||||
+
|
||||
+ return regmap_update_bits(priv->regmap, reg_info.reg,
|
||||
+ QCA8K_LED_RULE_MASK << reg_info.shift,
|
||||
+ offload_trigger << reg_info.shift);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_cled_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
|
||||
+{
|
||||
+ struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
|
||||
+ struct qca8k_led_pattern_en reg_info;
|
||||
+ struct qca8k_priv *priv = led->priv;
|
||||
+ u32 val;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* With hw control not active return err */
|
||||
+ if (!qca8k_cled_hw_control_status(ldev))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ qca8k_get_control_led_reg(led->port_num, led->led_num, ®_info);
|
||||
+
|
||||
+ ret = regmap_read(priv->regmap, reg_info.reg, &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ val >>= reg_info.shift;
|
||||
+ val &= QCA8K_LED_RULE_MASK;
|
||||
+
|
||||
+ /* Parsing specific to netdev trigger */
|
||||
+ if (val & QCA8K_LED_TX_BLINK_MASK)
|
||||
+ set_bit(TRIGGER_NETDEV_TX, rules);
|
||||
+ if (val & QCA8K_LED_RX_BLINK_MASK)
|
||||
+ set_bit(TRIGGER_NETDEV_RX, rules);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num)
|
||||
{
|
||||
struct fwnode_handle *led = NULL, *leds = NULL;
|
||||
@@ -224,6 +374,10 @@ qca8k_parse_port_leds(struct qca8k_priv
|
||||
port_led->cdev.max_brightness = 1;
|
||||
port_led->cdev.brightness_set_blocking = qca8k_cled_brightness_set_blocking;
|
||||
port_led->cdev.blink_set = qca8k_cled_blink_set;
|
||||
+ port_led->cdev.hw_control_is_supported = qca8k_cled_hw_control_is_supported;
|
||||
+ port_led->cdev.hw_control_set = qca8k_cled_hw_control_set;
|
||||
+ port_led->cdev.hw_control_get = qca8k_cled_hw_control_get;
|
||||
+ port_led->cdev.hw_control_trigger = "netdev";
|
||||
init_data.default_label = ":port";
|
||||
init_data.fwnode = led;
|
||||
init_data.devname_mandatory = true;
|
@@ -0,0 +1,70 @@
|
||||
From 4f53c27f772e27e4cf4e5507d6f4d5980002cb6a Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Lunn <andrew@lunn.ch>
|
||||
Date: Mon, 29 May 2023 18:32:43 +0200
|
||||
Subject: [PATCH 13/13] net: dsa: qca8k: add op to get ports netdev
|
||||
|
||||
In order that the LED trigger can blink the switch MAC ports LED, it
|
||||
needs to know the netdev associated to the port. Add the callback to
|
||||
return the struct device of the netdev.
|
||||
|
||||
Add an helper function qca8k_phy_to_port() to convert the phy back to
|
||||
dsa_port index, as we reference LED port based on the internal PHY
|
||||
index and needs to be converted back.
|
||||
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-leds.c | 27 +++++++++++++++++++++++++++
|
||||
1 file changed, 27 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-leds.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-leds.c
|
||||
@@ -5,6 +5,18 @@
|
||||
#include "qca8k.h"
|
||||
#include "qca8k_leds.h"
|
||||
|
||||
+static u32 qca8k_phy_to_port(int phy)
|
||||
+{
|
||||
+ /* Internal PHY 0 has port at index 1.
|
||||
+ * Internal PHY 1 has port at index 2.
|
||||
+ * Internal PHY 2 has port at index 3.
|
||||
+ * Internal PHY 3 has port at index 4.
|
||||
+ * Internal PHY 4 has port at index 5.
|
||||
+ */
|
||||
+
|
||||
+ return phy + 1;
|
||||
+}
|
||||
+
|
||||
static int
|
||||
qca8k_get_enable_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info)
|
||||
{
|
||||
@@ -314,6 +326,20 @@ qca8k_cled_hw_control_get(struct led_cla
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static struct device *qca8k_cled_hw_control_get_device(struct led_classdev *ldev)
|
||||
+{
|
||||
+ struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
|
||||
+ struct qca8k_priv *priv = led->priv;
|
||||
+ struct dsa_port *dp;
|
||||
+
|
||||
+ dp = dsa_to_port(priv->ds, qca8k_phy_to_port(led->port_num));
|
||||
+ if (!dp)
|
||||
+ return NULL;
|
||||
+ if (dp->slave)
|
||||
+ return &dp->slave->dev;
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
static int
|
||||
qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num)
|
||||
{
|
||||
@@ -377,6 +403,7 @@ qca8k_parse_port_leds(struct qca8k_priv
|
||||
port_led->cdev.hw_control_is_supported = qca8k_cled_hw_control_is_supported;
|
||||
port_led->cdev.hw_control_set = qca8k_cled_hw_control_set;
|
||||
port_led->cdev.hw_control_get = qca8k_cled_hw_control_get;
|
||||
+ port_led->cdev.hw_control_get_device = qca8k_cled_hw_control_get_device;
|
||||
port_led->cdev.hw_control_trigger = "netdev";
|
||||
init_data.default_label = ":port";
|
||||
init_data.fwnode = led;
|
@@ -0,0 +1,39 @@
|
||||
From 156a5bb89ca6f3edd2be0bfd0de15e575442927e Mon Sep 17 00:00:00 2001
|
||||
From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
Date: Tue, 3 Jan 2023 15:12:47 +0200
|
||||
Subject: [PATCH] leds: Move led_init_default_state_get() to the global header
|
||||
|
||||
There are users inside and outside LED framework that have implemented
|
||||
a local copy of led_init_default_state_get(). In order to deduplicate
|
||||
that, as the first step move the declaration from LED header to the
|
||||
global one.
|
||||
|
||||
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
Signed-off-by: Lee Jones <lee@kernel.org>
|
||||
Link: https://lore.kernel.org/r/20230103131256.33894-3-andriy.shevchenko@linux.intel.com
|
||||
---
|
||||
drivers/leds/leds.h | 1 -
|
||||
include/linux/leds.h | 2 ++
|
||||
2 files changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/leds/leds.h
|
||||
+++ b/drivers/leds/leds.h
|
||||
@@ -27,7 +27,6 @@ ssize_t led_trigger_read(struct file *fi
|
||||
ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr, char *buf,
|
||||
loff_t pos, size_t count);
|
||||
-enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode);
|
||||
|
||||
extern struct rw_semaphore leds_list_lock;
|
||||
extern struct list_head leds_list;
|
||||
--- a/include/linux/leds.h
|
||||
+++ b/include/linux/leds.h
|
||||
@@ -63,6 +63,8 @@ struct led_init_data {
|
||||
bool devname_mandatory;
|
||||
};
|
||||
|
||||
+enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode);
|
||||
+
|
||||
struct led_hw_trigger_type {
|
||||
int dummy;
|
||||
};
|
@@ -0,0 +1,67 @@
|
||||
From 3e8b4d6277fd19d98c817576954dd6a4ff3caa2b Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 17 Apr 2023 17:17:23 +0200
|
||||
Subject: [PATCH 1/9] net: dsa: qca8k: move qca8k_port_to_phy() to header
|
||||
|
||||
Move qca8k_port_to_phy() to qca8k header as it's useful for future
|
||||
reference in Switch LEDs module since the same logic is applied to get
|
||||
the right index of the switch port.
|
||||
Make it inline as it's simple function that just decrease the port.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Reviewed-by: Michal Kubiak <michal.kubiak@intel.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 15 ---------------
|
||||
drivers/net/dsa/qca/qca8k.h | 14 ++++++++++++++
|
||||
2 files changed, 14 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -716,21 +716,6 @@ err_clear_skb:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static u32
|
||||
-qca8k_port_to_phy(int port)
|
||||
-{
|
||||
- /* From Andrew Lunn:
|
||||
- * Port 0 has no internal phy.
|
||||
- * Port 1 has an internal PHY at MDIO address 0.
|
||||
- * Port 2 has an internal PHY at MDIO address 1.
|
||||
- * ...
|
||||
- * Port 5 has an internal PHY at MDIO address 4.
|
||||
- * Port 6 has no internal PHY.
|
||||
- */
|
||||
-
|
||||
- return port - 1;
|
||||
-}
|
||||
-
|
||||
static int
|
||||
qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask)
|
||||
{
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -422,6 +422,20 @@ struct qca8k_fdb {
|
||||
u8 mac[6];
|
||||
};
|
||||
|
||||
+static inline u32 qca8k_port_to_phy(int port)
|
||||
+{
|
||||
+ /* From Andrew Lunn:
|
||||
+ * Port 0 has no internal phy.
|
||||
+ * Port 1 has an internal PHY at MDIO address 0.
|
||||
+ * Port 2 has an internal PHY at MDIO address 1.
|
||||
+ * ...
|
||||
+ * Port 5 has an internal PHY at MDIO address 4.
|
||||
+ * Port 6 has no internal PHY.
|
||||
+ */
|
||||
+
|
||||
+ return port - 1;
|
||||
+}
|
||||
+
|
||||
/* Common setup function */
|
||||
extern const struct qca8k_mib_desc ar8327_mib[];
|
||||
extern const struct regmap_access_table qca8k_readable_table;
|
@@ -0,0 +1,435 @@
|
||||
From 1e264f9d2918b5737023c44a23ae04def1095210 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 17 Apr 2023 17:17:24 +0200
|
||||
Subject: [PATCH 2/9] net: dsa: qca8k: add LEDs basic support
|
||||
|
||||
Add LEDs basic support for qca8k Switch Family by adding basic
|
||||
brightness_set() support.
|
||||
|
||||
Since these LEDs refelect port status, the default label is set to
|
||||
":port". DT binding should describe the color and function of the
|
||||
LEDs using standard LEDs api.
|
||||
Each LED always have the device name as prefix. The device name is
|
||||
composed from the mii bus id and the PHY addr resulting in example
|
||||
names like:
|
||||
- qca8k-0.0:00:amber:lan
|
||||
- qca8k-0.0:00:white:lan
|
||||
- qca8k-0.0:01:amber:lan
|
||||
- qca8k-0.0:01:white:lan
|
||||
|
||||
These LEDs supports only blocking variant of the brightness_set()
|
||||
function since they can sleep during access of the switch leds to set
|
||||
the brightness.
|
||||
|
||||
While at it add to the qca8k header file each mode defined by the Switch
|
||||
Documentation for future use.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca/Kconfig | 8 ++
|
||||
drivers/net/dsa/qca/Makefile | 3 +
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 5 +
|
||||
drivers/net/dsa/qca/qca8k-leds.c | 239 +++++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca/qca8k.h | 60 ++++++++
|
||||
drivers/net/dsa/qca/qca8k_leds.h | 16 +++
|
||||
6 files changed, 331 insertions(+)
|
||||
create mode 100644 drivers/net/dsa/qca/qca8k-leds.c
|
||||
create mode 100644 drivers/net/dsa/qca/qca8k_leds.h
|
||||
|
||||
--- a/drivers/net/dsa/qca/Kconfig
|
||||
+++ b/drivers/net/dsa/qca/Kconfig
|
||||
@@ -15,3 +15,11 @@ config NET_DSA_QCA8K
|
||||
help
|
||||
This enables support for the Qualcomm Atheros QCA8K Ethernet
|
||||
switch chips.
|
||||
+
|
||||
+config NET_DSA_QCA8K_LEDS_SUPPORT
|
||||
+ bool "Qualcomm Atheros QCA8K Ethernet switch family LEDs support"
|
||||
+ depends on NET_DSA_QCA8K
|
||||
+ depends on LEDS_CLASS
|
||||
+ help
|
||||
+ This enabled support for LEDs present on the Qualcomm Atheros
|
||||
+ QCA8K Ethernet switch chips.
|
||||
--- a/drivers/net/dsa/qca/Makefile
|
||||
+++ b/drivers/net/dsa/qca/Makefile
|
||||
@@ -2,3 +2,6 @@
|
||||
obj-$(CONFIG_NET_DSA_AR9331) += ar9331.o
|
||||
obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o
|
||||
qca8k-y += qca8k-common.o qca8k-8xxx.o
|
||||
+ifdef CONFIG_NET_DSA_QCA8K_LEDS_SUPPORT
|
||||
+qca8k-y += qca8k-leds.o
|
||||
+endif
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/dsa/tag_qca.h>
|
||||
|
||||
#include "qca8k.h"
|
||||
+#include "qca8k_leds.h"
|
||||
|
||||
static void
|
||||
qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
|
||||
@@ -1726,6 +1727,10 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ ret = qca8k_setup_led_ctrl(priv);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
qca8k_setup_pcs(priv, &priv->pcs_port_0, 0);
|
||||
qca8k_setup_pcs(priv, &priv->pcs_port_6, 6);
|
||||
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/dsa/qca/qca8k-leds.c
|
||||
@@ -0,0 +1,239 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+#include <linux/regmap.h>
|
||||
+#include <net/dsa.h>
|
||||
+
|
||||
+#include "qca8k.h"
|
||||
+#include "qca8k_leds.h"
|
||||
+
|
||||
+static int
|
||||
+qca8k_get_enable_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info)
|
||||
+{
|
||||
+ switch (port_num) {
|
||||
+ case 0:
|
||||
+ reg_info->reg = QCA8K_LED_CTRL_REG(led_num);
|
||||
+ reg_info->shift = QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT;
|
||||
+ break;
|
||||
+ case 1:
|
||||
+ case 2:
|
||||
+ case 3:
|
||||
+ /* Port 123 are controlled on a different reg */
|
||||
+ reg_info->reg = QCA8K_LED_CTRL3_REG;
|
||||
+ reg_info->shift = QCA8K_LED_PHY123_PATTERN_EN_SHIFT(port_num, led_num);
|
||||
+ break;
|
||||
+ case 4:
|
||||
+ reg_info->reg = QCA8K_LED_CTRL_REG(led_num);
|
||||
+ reg_info->shift = QCA8K_LED_PHY4_CONTROL_RULE_SHIFT;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_led_brightness_set(struct qca8k_led *led,
|
||||
+ enum led_brightness brightness)
|
||||
+{
|
||||
+ struct qca8k_led_pattern_en reg_info;
|
||||
+ struct qca8k_priv *priv = led->priv;
|
||||
+ u32 mask, val;
|
||||
+
|
||||
+ qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info);
|
||||
+
|
||||
+ val = QCA8K_LED_ALWAYS_OFF;
|
||||
+ if (brightness)
|
||||
+ val = QCA8K_LED_ALWAYS_ON;
|
||||
+
|
||||
+ /* HW regs to control brightness is special and port 1-2-3
|
||||
+ * are placed in a different reg.
|
||||
+ *
|
||||
+ * To control port 0 brightness:
|
||||
+ * - the 2 bit (15, 14) of:
|
||||
+ * - QCA8K_LED_CTRL0_REG for led1
|
||||
+ * - QCA8K_LED_CTRL1_REG for led2
|
||||
+ * - QCA8K_LED_CTRL2_REG for led3
|
||||
+ *
|
||||
+ * To control port 4:
|
||||
+ * - the 2 bit (31, 30) of:
|
||||
+ * - QCA8K_LED_CTRL0_REG for led1
|
||||
+ * - QCA8K_LED_CTRL1_REG for led2
|
||||
+ * - QCA8K_LED_CTRL2_REG for led3
|
||||
+ *
|
||||
+ * To control port 1:
|
||||
+ * - the 2 bit at (9, 8) of QCA8K_LED_CTRL3_REG are used for led1
|
||||
+ * - the 2 bit at (11, 10) of QCA8K_LED_CTRL3_REG are used for led2
|
||||
+ * - the 2 bit at (13, 12) of QCA8K_LED_CTRL3_REG are used for led3
|
||||
+ *
|
||||
+ * To control port 2:
|
||||
+ * - the 2 bit at (15, 14) of QCA8K_LED_CTRL3_REG are used for led1
|
||||
+ * - the 2 bit at (17, 16) of QCA8K_LED_CTRL3_REG are used for led2
|
||||
+ * - the 2 bit at (19, 18) of QCA8K_LED_CTRL3_REG are used for led3
|
||||
+ *
|
||||
+ * To control port 3:
|
||||
+ * - the 2 bit at (21, 20) of QCA8K_LED_CTRL3_REG are used for led1
|
||||
+ * - the 2 bit at (23, 22) of QCA8K_LED_CTRL3_REG are used for led2
|
||||
+ * - the 2 bit at (25, 24) of QCA8K_LED_CTRL3_REG are used for led3
|
||||
+ *
|
||||
+ * To abstract this and have less code, we use the port and led numm
|
||||
+ * to calculate the shift and the correct reg due to this problem of
|
||||
+ * not having a 1:1 map of LED with the regs.
|
||||
+ */
|
||||
+ if (led->port_num == 0 || led->port_num == 4) {
|
||||
+ mask = QCA8K_LED_PATTERN_EN_MASK;
|
||||
+ val <<= QCA8K_LED_PATTERN_EN_SHIFT;
|
||||
+ } else {
|
||||
+ mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;
|
||||
+ }
|
||||
+
|
||||
+ return regmap_update_bits(priv->regmap, reg_info.reg,
|
||||
+ mask << reg_info.shift,
|
||||
+ val << reg_info.shift);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_cled_brightness_set_blocking(struct led_classdev *ldev,
|
||||
+ enum led_brightness brightness)
|
||||
+{
|
||||
+ struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
|
||||
+
|
||||
+ return qca8k_led_brightness_set(led, brightness);
|
||||
+}
|
||||
+
|
||||
+static enum led_brightness
|
||||
+qca8k_led_brightness_get(struct qca8k_led *led)
|
||||
+{
|
||||
+ struct qca8k_led_pattern_en reg_info;
|
||||
+ struct qca8k_priv *priv = led->priv;
|
||||
+ u32 val;
|
||||
+ int ret;
|
||||
+
|
||||
+ qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info);
|
||||
+
|
||||
+ ret = regmap_read(priv->regmap, reg_info.reg, &val);
|
||||
+ if (ret)
|
||||
+ return 0;
|
||||
+
|
||||
+ val >>= reg_info.shift;
|
||||
+
|
||||
+ if (led->port_num == 0 || led->port_num == 4) {
|
||||
+ val &= QCA8K_LED_PATTERN_EN_MASK;
|
||||
+ val >>= QCA8K_LED_PATTERN_EN_SHIFT;
|
||||
+ } else {
|
||||
+ val &= QCA8K_LED_PHY123_PATTERN_EN_MASK;
|
||||
+ }
|
||||
+
|
||||
+ /* Assume brightness ON only when the LED is set to always ON */
|
||||
+ return val == QCA8K_LED_ALWAYS_ON;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num)
|
||||
+{
|
||||
+ struct fwnode_handle *led = NULL, *leds = NULL;
|
||||
+ struct led_init_data init_data = { };
|
||||
+ struct dsa_switch *ds = priv->ds;
|
||||
+ enum led_default_state state;
|
||||
+ struct qca8k_led *port_led;
|
||||
+ int led_num, led_index;
|
||||
+ int ret;
|
||||
+
|
||||
+ leds = fwnode_get_named_child_node(port, "leds");
|
||||
+ if (!leds) {
|
||||
+ dev_dbg(priv->dev, "No Leds node specified in device tree for port %d!\n",
|
||||
+ port_num);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ fwnode_for_each_child_node(leds, led) {
|
||||
+ /* Reg represent the led number of the port.
|
||||
+ * Each port can have at most 3 leds attached
|
||||
+ * Commonly:
|
||||
+ * 1. is gigabit led
|
||||
+ * 2. is mbit led
|
||||
+ * 3. additional status led
|
||||
+ */
|
||||
+ if (fwnode_property_read_u32(led, "reg", &led_num))
|
||||
+ continue;
|
||||
+
|
||||
+ if (led_num >= QCA8K_LED_PORT_COUNT) {
|
||||
+ dev_warn(priv->dev, "Invalid LED reg %d defined for port %d",
|
||||
+ led_num, port_num);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ led_index = QCA8K_LED_PORT_INDEX(port_num, led_num);
|
||||
+
|
||||
+ port_led = &priv->ports_led[led_index];
|
||||
+ port_led->port_num = port_num;
|
||||
+ port_led->led_num = led_num;
|
||||
+ port_led->priv = priv;
|
||||
+
|
||||
+ state = led_init_default_state_get(led);
|
||||
+ switch (state) {
|
||||
+ case LEDS_DEFSTATE_ON:
|
||||
+ port_led->cdev.brightness = 1;
|
||||
+ qca8k_led_brightness_set(port_led, 1);
|
||||
+ break;
|
||||
+ case LEDS_DEFSTATE_KEEP:
|
||||
+ port_led->cdev.brightness =
|
||||
+ qca8k_led_brightness_get(port_led);
|
||||
+ break;
|
||||
+ default:
|
||||
+ port_led->cdev.brightness = 0;
|
||||
+ qca8k_led_brightness_set(port_led, 0);
|
||||
+ }
|
||||
+
|
||||
+ port_led->cdev.max_brightness = 1;
|
||||
+ port_led->cdev.brightness_set_blocking = qca8k_cled_brightness_set_blocking;
|
||||
+ init_data.default_label = ":port";
|
||||
+ init_data.fwnode = led;
|
||||
+ init_data.devname_mandatory = true;
|
||||
+ init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d", ds->slave_mii_bus->id,
|
||||
+ port_num);
|
||||
+ if (!init_data.devicename)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ ret = devm_led_classdev_register_ext(priv->dev, &port_led->cdev, &init_data);
|
||||
+ if (ret)
|
||||
+ dev_warn(priv->dev, "Failed to init LED %d for port %d", led_num, port_num);
|
||||
+
|
||||
+ kfree(init_data.devicename);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+qca8k_setup_led_ctrl(struct qca8k_priv *priv)
|
||||
+{
|
||||
+ struct fwnode_handle *ports, *port;
|
||||
+ int port_num;
|
||||
+ int ret;
|
||||
+
|
||||
+ ports = device_get_named_child_node(priv->dev, "ports");
|
||||
+ if (!ports) {
|
||||
+ dev_info(priv->dev, "No ports node specified in device tree!");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ fwnode_for_each_child_node(ports, port) {
|
||||
+ if (fwnode_property_read_u32(port, "reg", &port_num))
|
||||
+ continue;
|
||||
+
|
||||
+ /* Skip checking for CPU port 0 and CPU port 6 as not supported */
|
||||
+ if (port_num == 0 || port_num == 6)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Each port can have at most 3 different leds attached.
|
||||
+ * Switch port starts from 0 to 6, but port 0 and 6 are CPU
|
||||
+ * port. The port index needs to be decreased by one to identify
|
||||
+ * the correct port for LED setup.
|
||||
+ */
|
||||
+ ret = qca8k_parse_port_leds(priv, port, qca8k_port_to_phy(port_num));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
--- a/drivers/net/dsa/qca/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/gpio.h>
|
||||
+#include <linux/leds.h>
|
||||
#include <linux/dsa/tag_qca.h>
|
||||
|
||||
#define QCA8K_ETHERNET_MDIO_PRIORITY 7
|
||||
@@ -85,6 +86,51 @@
|
||||
#define QCA8K_MDIO_MASTER_DATA(x) FIELD_PREP(QCA8K_MDIO_MASTER_DATA_MASK, x)
|
||||
#define QCA8K_MDIO_MASTER_MAX_PORTS 5
|
||||
#define QCA8K_MDIO_MASTER_MAX_REG 32
|
||||
+
|
||||
+/* LED control register */
|
||||
+#define QCA8K_LED_PORT_COUNT 3
|
||||
+#define QCA8K_LED_COUNT ((QCA8K_NUM_PORTS - QCA8K_NUM_CPU_PORTS) * QCA8K_LED_PORT_COUNT)
|
||||
+#define QCA8K_LED_RULE_COUNT 6
|
||||
+#define QCA8K_LED_RULE_MAX 11
|
||||
+#define QCA8K_LED_PORT_INDEX(_phy, _led) (((_phy) * QCA8K_LED_PORT_COUNT) + (_led))
|
||||
+
|
||||
+#define QCA8K_LED_PHY123_PATTERN_EN_SHIFT(_phy, _led) ((((_phy) - 1) * 6) + 8 + (2 * (_led)))
|
||||
+#define QCA8K_LED_PHY123_PATTERN_EN_MASK GENMASK(1, 0)
|
||||
+
|
||||
+#define QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT 0
|
||||
+#define QCA8K_LED_PHY4_CONTROL_RULE_SHIFT 16
|
||||
+
|
||||
+#define QCA8K_LED_CTRL_REG(_i) (0x050 + (_i) * 4)
|
||||
+#define QCA8K_LED_CTRL0_REG 0x50
|
||||
+#define QCA8K_LED_CTRL1_REG 0x54
|
||||
+#define QCA8K_LED_CTRL2_REG 0x58
|
||||
+#define QCA8K_LED_CTRL3_REG 0x5C
|
||||
+#define QCA8K_LED_CTRL_SHIFT(_i) (((_i) % 2) * 16)
|
||||
+#define QCA8K_LED_CTRL_MASK GENMASK(15, 0)
|
||||
+#define QCA8K_LED_RULE_MASK GENMASK(13, 0)
|
||||
+#define QCA8K_LED_BLINK_FREQ_MASK GENMASK(1, 0)
|
||||
+#define QCA8K_LED_BLINK_FREQ_SHITF 0
|
||||
+#define QCA8K_LED_BLINK_2HZ 0
|
||||
+#define QCA8K_LED_BLINK_4HZ 1
|
||||
+#define QCA8K_LED_BLINK_8HZ 2
|
||||
+#define QCA8K_LED_BLINK_AUTO 3
|
||||
+#define QCA8K_LED_LINKUP_OVER_MASK BIT(2)
|
||||
+#define QCA8K_LED_TX_BLINK_MASK BIT(4)
|
||||
+#define QCA8K_LED_RX_BLINK_MASK BIT(5)
|
||||
+#define QCA8K_LED_COL_BLINK_MASK BIT(7)
|
||||
+#define QCA8K_LED_LINK_10M_EN_MASK BIT(8)
|
||||
+#define QCA8K_LED_LINK_100M_EN_MASK BIT(9)
|
||||
+#define QCA8K_LED_LINK_1000M_EN_MASK BIT(10)
|
||||
+#define QCA8K_LED_POWER_ON_LIGHT_MASK BIT(11)
|
||||
+#define QCA8K_LED_HALF_DUPLEX_MASK BIT(12)
|
||||
+#define QCA8K_LED_FULL_DUPLEX_MASK BIT(13)
|
||||
+#define QCA8K_LED_PATTERN_EN_MASK GENMASK(15, 14)
|
||||
+#define QCA8K_LED_PATTERN_EN_SHIFT 14
|
||||
+#define QCA8K_LED_ALWAYS_OFF 0
|
||||
+#define QCA8K_LED_ALWAYS_BLINK_4HZ 1
|
||||
+#define QCA8K_LED_ALWAYS_ON 2
|
||||
+#define QCA8K_LED_RULE_CONTROLLED 3
|
||||
+
|
||||
#define QCA8K_GOL_MAC_ADDR0 0x60
|
||||
#define QCA8K_GOL_MAC_ADDR1 0x64
|
||||
#define QCA8K_MAX_FRAME_SIZE 0x78
|
||||
@@ -383,6 +429,19 @@ struct qca8k_pcs {
|
||||
int port;
|
||||
};
|
||||
|
||||
+struct qca8k_led_pattern_en {
|
||||
+ u32 reg;
|
||||
+ u8 shift;
|
||||
+};
|
||||
+
|
||||
+struct qca8k_led {
|
||||
+ u8 port_num;
|
||||
+ u8 led_num;
|
||||
+ u16 old_rule;
|
||||
+ struct qca8k_priv *priv;
|
||||
+ struct led_classdev cdev;
|
||||
+};
|
||||
+
|
||||
struct qca8k_priv {
|
||||
u8 switch_id;
|
||||
u8 switch_revision;
|
||||
@@ -407,6 +466,7 @@ struct qca8k_priv {
|
||||
struct qca8k_pcs pcs_port_0;
|
||||
struct qca8k_pcs pcs_port_6;
|
||||
const struct qca8k_match_data *info;
|
||||
+ struct qca8k_led ports_led[QCA8K_LED_COUNT];
|
||||
};
|
||||
|
||||
struct qca8k_mib_desc {
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/dsa/qca/qca8k_leds.h
|
||||
@@ -0,0 +1,16 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
+
|
||||
+#ifndef __QCA8K_LEDS_H
|
||||
+#define __QCA8K_LEDS_H
|
||||
+
|
||||
+/* Leds Support function */
|
||||
+#ifdef CONFIG_NET_DSA_QCA8K_LEDS_SUPPORT
|
||||
+int qca8k_setup_led_ctrl(struct qca8k_priv *priv);
|
||||
+#else
|
||||
+static inline int qca8k_setup_led_ctrl(struct qca8k_priv *priv)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+#endif /* __QCA8K_LEDS_H */
|
@@ -0,0 +1,74 @@
|
||||
From 91acadcc6e599dfc62717abcdad58a459cfb1684 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 17 Apr 2023 17:17:25 +0200
|
||||
Subject: [PATCH 3/9] net: dsa: qca8k: add LEDs blink_set() support
|
||||
|
||||
Add LEDs blink_set() support to qca8k Switch Family.
|
||||
These LEDs support hw accellerated blinking at a fixed rate
|
||||
of 4Hz.
|
||||
|
||||
Reject any other value since not supported by the LEDs switch.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Acked-by: Pavel Machek <pavel@ucw.cz>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-leds.c | 38 ++++++++++++++++++++++++++++++++
|
||||
1 file changed, 38 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-leds.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-leds.c
|
||||
@@ -128,6 +128,43 @@ qca8k_led_brightness_get(struct qca8k_le
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_cled_blink_set(struct led_classdev *ldev,
|
||||
+ unsigned long *delay_on,
|
||||
+ unsigned long *delay_off)
|
||||
+{
|
||||
+ struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
|
||||
+ u32 mask, val = QCA8K_LED_ALWAYS_BLINK_4HZ;
|
||||
+ struct qca8k_led_pattern_en reg_info;
|
||||
+ struct qca8k_priv *priv = led->priv;
|
||||
+
|
||||
+ if (*delay_on == 0 && *delay_off == 0) {
|
||||
+ *delay_on = 125;
|
||||
+ *delay_off = 125;
|
||||
+ }
|
||||
+
|
||||
+ if (*delay_on != 125 || *delay_off != 125) {
|
||||
+ /* The hardware only supports blinking at 4Hz. Fall back
|
||||
+ * to software implementation in other cases.
|
||||
+ */
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info);
|
||||
+
|
||||
+ if (led->port_num == 0 || led->port_num == 4) {
|
||||
+ mask = QCA8K_LED_PATTERN_EN_MASK;
|
||||
+ val <<= QCA8K_LED_PATTERN_EN_SHIFT;
|
||||
+ } else {
|
||||
+ mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;
|
||||
+ }
|
||||
+
|
||||
+ regmap_update_bits(priv->regmap, reg_info.reg, mask << reg_info.shift,
|
||||
+ val << reg_info.shift);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num)
|
||||
{
|
||||
struct fwnode_handle *led = NULL, *leds = NULL;
|
||||
@@ -186,6 +223,7 @@ qca8k_parse_port_leds(struct qca8k_priv
|
||||
|
||||
port_led->cdev.max_brightness = 1;
|
||||
port_led->cdev.brightness_set_blocking = qca8k_cled_brightness_set_blocking;
|
||||
+ port_led->cdev.blink_set = qca8k_cled_blink_set;
|
||||
init_data.default_label = ":port";
|
||||
init_data.fwnode = led;
|
||||
init_data.devname_mandatory = true;
|
@@ -0,0 +1,59 @@
|
||||
From e5029edd53937a29801ef507cee12e657ff31ea9 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Lunn <andrew@lunn.ch>
|
||||
Date: Mon, 17 Apr 2023 17:17:26 +0200
|
||||
Subject: [PATCH 4/9] leds: Provide stubs for when CLASS_LED & NEW_LEDS are
|
||||
disabled
|
||||
|
||||
Provide stubs for devm_led_classdev_register_ext() and
|
||||
led_init_default_state_get() so that LED drivers embedded within other
|
||||
drivers such as PHYs and Ethernet switches still build when LEDS_CLASS
|
||||
or NEW_LEDS are disabled. This also helps with Kconfig dependencies,
|
||||
which are somewhat hairy for phylib and mdio and only get worse when
|
||||
adding a dependency on LED_CLASS.
|
||||
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/linux/leds.h | 18 ++++++++++++++++++
|
||||
1 file changed, 18 insertions(+)
|
||||
|
||||
--- a/include/linux/leds.h
|
||||
+++ b/include/linux/leds.h
|
||||
@@ -63,7 +63,15 @@ struct led_init_data {
|
||||
bool devname_mandatory;
|
||||
};
|
||||
|
||||
+#if IS_ENABLED(CONFIG_NEW_LEDS)
|
||||
enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode);
|
||||
+#else
|
||||
+static inline enum led_default_state
|
||||
+led_init_default_state_get(struct fwnode_handle *fwnode)
|
||||
+{
|
||||
+ return LEDS_DEFSTATE_OFF;
|
||||
+}
|
||||
+#endif
|
||||
|
||||
struct led_hw_trigger_type {
|
||||
int dummy;
|
||||
@@ -198,9 +206,19 @@ static inline int led_classdev_register(
|
||||
return led_classdev_register_ext(parent, led_cdev, NULL);
|
||||
}
|
||||
|
||||
+#if IS_ENABLED(CONFIG_LEDS_CLASS)
|
||||
int devm_led_classdev_register_ext(struct device *parent,
|
||||
struct led_classdev *led_cdev,
|
||||
struct led_init_data *init_data);
|
||||
+#else
|
||||
+static inline int
|
||||
+devm_led_classdev_register_ext(struct device *parent,
|
||||
+ struct led_classdev *led_cdev,
|
||||
+ struct led_init_data *init_data)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
|
||||
static inline int devm_led_classdev_register(struct device *parent,
|
||||
struct led_classdev *led_cdev)
|
@@ -0,0 +1,191 @@
|
||||
From 01e5b728e9e43ae444e0369695a5f72209906464 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Lunn <andrew@lunn.ch>
|
||||
Date: Mon, 17 Apr 2023 17:17:27 +0200
|
||||
Subject: [PATCH 5/9] net: phy: Add a binding for PHY LEDs
|
||||
|
||||
Define common binding parsing for all PHY drivers with LEDs using
|
||||
phylib. Parse the DT as part of the phy_probe and add LEDs to the
|
||||
linux LED class infrastructure. For the moment, provide a dummy
|
||||
brightness function, which will later be replaced with a call into the
|
||||
PHY driver. This allows testing since the LED core might otherwise
|
||||
reject an LED whose brightness cannot be set.
|
||||
|
||||
Add a dependency on LED_CLASS. It either needs to be built in, or not
|
||||
enabled, since a modular build can result in linker errors.
|
||||
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/Kconfig | 1 +
|
||||
drivers/net/phy/phy_device.c | 76 ++++++++++++++++++++++++++++++++++++
|
||||
include/linux/phy.h | 16 ++++++++
|
||||
3 files changed, 93 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/Kconfig
|
||||
+++ b/drivers/net/phy/Kconfig
|
||||
@@ -18,6 +18,7 @@ menuconfig PHYLIB
|
||||
depends on NETDEVICES
|
||||
select MDIO_DEVICE
|
||||
select MDIO_DEVRES
|
||||
+ depends on LEDS_CLASS || LEDS_CLASS=n
|
||||
help
|
||||
Ethernet controllers are usually attached to PHY
|
||||
devices. This option provides infrastructure for
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -19,10 +19,12 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
+#include <linux/list.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phy_led_triggers.h>
|
||||
@@ -644,6 +646,7 @@ struct phy_device *phy_device_create(str
|
||||
device_initialize(&mdiodev->dev);
|
||||
|
||||
dev->state = PHY_DOWN;
|
||||
+ INIT_LIST_HEAD(&dev->leds);
|
||||
|
||||
mutex_init(&dev->lock);
|
||||
INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
|
||||
@@ -2931,6 +2934,74 @@ static bool phy_drv_supports_irq(struct
|
||||
return phydrv->config_intr && phydrv->handle_interrupt;
|
||||
}
|
||||
|
||||
+/* Dummy implementation until calls into PHY driver are added */
|
||||
+static int phy_led_set_brightness(struct led_classdev *led_cdev,
|
||||
+ enum led_brightness value)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int of_phy_led(struct phy_device *phydev,
|
||||
+ struct device_node *led)
|
||||
+{
|
||||
+ struct device *dev = &phydev->mdio.dev;
|
||||
+ struct led_init_data init_data = {};
|
||||
+ struct led_classdev *cdev;
|
||||
+ struct phy_led *phyled;
|
||||
+ int err;
|
||||
+
|
||||
+ phyled = devm_kzalloc(dev, sizeof(*phyled), GFP_KERNEL);
|
||||
+ if (!phyled)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ cdev = &phyled->led_cdev;
|
||||
+
|
||||
+ err = of_property_read_u8(led, "reg", &phyled->index);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ cdev->brightness_set_blocking = phy_led_set_brightness;
|
||||
+ cdev->max_brightness = 1;
|
||||
+ init_data.devicename = dev_name(&phydev->mdio.dev);
|
||||
+ init_data.fwnode = of_fwnode_handle(led);
|
||||
+ init_data.devname_mandatory = true;
|
||||
+
|
||||
+ err = devm_led_classdev_register_ext(dev, cdev, &init_data);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ list_add(&phyled->list, &phydev->leds);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int of_phy_leds(struct phy_device *phydev)
|
||||
+{
|
||||
+ struct device_node *node = phydev->mdio.dev.of_node;
|
||||
+ struct device_node *leds, *led;
|
||||
+ int err;
|
||||
+
|
||||
+ if (!IS_ENABLED(CONFIG_OF_MDIO))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (!node)
|
||||
+ return 0;
|
||||
+
|
||||
+ leds = of_get_child_by_name(node, "leds");
|
||||
+ if (!leds)
|
||||
+ return 0;
|
||||
+
|
||||
+ for_each_available_child_of_node(leds, led) {
|
||||
+ err = of_phy_led(phydev, led);
|
||||
+ if (err) {
|
||||
+ of_node_put(led);
|
||||
+ return err;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* fwnode_mdio_find_device - Given a fwnode, find the mdio_device
|
||||
* @fwnode: pointer to the mdio_device's fwnode
|
||||
@@ -3107,6 +3178,11 @@ static int phy_probe(struct device *dev)
|
||||
/* Set the state to READY by default */
|
||||
phydev->state = PHY_READY;
|
||||
|
||||
+ /* Get the LEDs from the device tree, and instantiate standard
|
||||
+ * LEDs for them.
|
||||
+ */
|
||||
+ err = of_phy_leds(phydev);
|
||||
+
|
||||
out:
|
||||
/* Re-assert the reset signal on error */
|
||||
if (err)
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/ethtool.h>
|
||||
+#include <linux/leds.h>
|
||||
#include <linux/linkmode.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/mdio.h>
|
||||
@@ -593,6 +594,7 @@ struct macsec_ops;
|
||||
* @phy_num_led_triggers: Number of triggers in @phy_led_triggers
|
||||
* @led_link_trigger: LED trigger for link up/down
|
||||
* @last_triggered: last LED trigger for link speed
|
||||
+ * @leds: list of PHY LED structures
|
||||
* @master_slave_set: User requested master/slave configuration
|
||||
* @master_slave_get: Current master/slave advertisement
|
||||
* @master_slave_state: Current master/slave configuration
|
||||
@@ -685,6 +687,7 @@ struct phy_device {
|
||||
|
||||
struct phy_led_trigger *led_link_trigger;
|
||||
#endif
|
||||
+ struct list_head leds;
|
||||
|
||||
/*
|
||||
* Interrupt number for this PHY
|
||||
@@ -759,6 +762,19 @@ struct phy_tdr_config {
|
||||
#define PHY_PAIR_ALL -1
|
||||
|
||||
/**
|
||||
+ * struct phy_led: An LED driven by the PHY
|
||||
+ *
|
||||
+ * @list: List of LEDs
|
||||
+ * @led_cdev: Standard LED class structure
|
||||
+ * @index: Number of the LED
|
||||
+ */
|
||||
+struct phy_led {
|
||||
+ struct list_head list;
|
||||
+ struct led_classdev led_cdev;
|
||||
+ u8 index;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
* struct phy_driver - Driver structure for a particular PHY type
|
||||
*
|
||||
* @mdiodrv: Data common to all MDIO devices
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user