Merge upstream changes
This commit is contained in:
commit
24c944c698
306 changed files with 10491 additions and 26482 deletions
2
Makefile
2
Makefile
|
@ -15,6 +15,8 @@ $(if $(findstring $(space),$(TOPDIR)),$(error ERROR: The path to the OpenWrt dir
|
||||||
world:
|
world:
|
||||||
|
|
||||||
DISTRO_PKG_CONFIG:=$(shell $(TOPDIR)/scripts/command_all.sh pkg-config | grep '/usr' -m 1)
|
DISTRO_PKG_CONFIG:=$(shell $(TOPDIR)/scripts/command_all.sh pkg-config | grep '/usr' -m 1)
|
||||||
|
|
||||||
|
export ORIG_PATH:=$(if $(ORIG_PATH),$(ORIG_PATH),$(PATH))
|
||||||
export PATH:=$(if $(STAGING_DIR),$(abspath $(STAGING_DIR)/../host/bin),$(TOPDIR)/staging_dir/host/bin):$(PATH)
|
export PATH:=$(if $(STAGING_DIR),$(abspath $(STAGING_DIR)/../host/bin),$(TOPDIR)/staging_dir/host/bin):$(PATH)
|
||||||
|
|
||||||
ifneq ($(OPENWRT_BUILD),1)
|
ifneq ($(OPENWRT_BUILD),1)
|
||||||
|
|
|
@ -26,6 +26,7 @@ HOST_STAMP_CONFIGURED:=$(HOST_BUILD_DIR)/.configured
|
||||||
HOST_STAMP_BUILT:=$(HOST_BUILD_DIR)/.built
|
HOST_STAMP_BUILT:=$(HOST_BUILD_DIR)/.built
|
||||||
HOST_BUILD_PREFIX?=$(if $(IS_PACKAGE_BUILD),$(STAGING_DIR_HOSTPKG),$(STAGING_DIR_HOST))
|
HOST_BUILD_PREFIX?=$(if $(IS_PACKAGE_BUILD),$(STAGING_DIR_HOSTPKG),$(STAGING_DIR_HOST))
|
||||||
HOST_STAMP_INSTALLED:=$(HOST_BUILD_PREFIX)/stamp/.$(PKG_NAME)_installed
|
HOST_STAMP_INSTALLED:=$(HOST_BUILD_PREFIX)/stamp/.$(PKG_NAME)_installed
|
||||||
|
HOST_STAMP_PROGRAMS:=$(foreach program,$(PKG_PROGRAMS),$(subst $(PKG_NAME),$(program),$(HOST_STAMP_INSTALLED)) )
|
||||||
|
|
||||||
override MAKEFLAGS=
|
override MAKEFLAGS=
|
||||||
|
|
||||||
|
@ -172,7 +173,7 @@ ifndef DUMP
|
||||||
$(foreach hook,$(Hooks/HostInstall/Post),$(call $(hook))$(sep))
|
$(foreach hook,$(Hooks/HostInstall/Post),$(call $(hook))$(sep))
|
||||||
mkdir -p $$(shell dirname $$@)
|
mkdir -p $$(shell dirname $$@)
|
||||||
touch $(HOST_STAMP_BUILT)
|
touch $(HOST_STAMP_BUILT)
|
||||||
touch $$@
|
touch $$@ $(HOST_STAMP_PROGRAMS)
|
||||||
|
|
||||||
$(call DefaultTargets,$(patsubst %,host-%,$(DEFAULT_SUBDIR_TARGETS)))
|
$(call DefaultTargets,$(patsubst %,host-%,$(DEFAULT_SUBDIR_TARGETS)))
|
||||||
ifndef STAMP_BUILT
|
ifndef STAMP_BUILT
|
||||||
|
@ -187,7 +188,7 @@ ifndef DUMP
|
||||||
|
|
||||||
$(_host_target)host-prepare: $(HOST_STAMP_PREPARED)
|
$(_host_target)host-prepare: $(HOST_STAMP_PREPARED)
|
||||||
$(_host_target)host-configure: $(HOST_STAMP_CONFIGURED)
|
$(_host_target)host-configure: $(HOST_STAMP_CONFIGURED)
|
||||||
$(_host_target)host-compile: $(HOST_STAMP_BUILT) $(HOST_STAMP_INSTALLED)
|
$(_host_target)host-compile: $(HOST_STAMP_BUILT) $(HOST_STAMP_INSTALLED) $(HOST_STAMP_PROGRAMS)
|
||||||
host-install: host-compile
|
host-install: host-compile
|
||||||
|
|
||||||
host-clean-build: FORCE
|
host-clean-build: FORCE
|
||||||
|
@ -196,7 +197,7 @@ ifndef DUMP
|
||||||
|
|
||||||
host-clean: host-clean-build
|
host-clean: host-clean-build
|
||||||
$(call Host/Clean)
|
$(call Host/Clean)
|
||||||
rm -rf $(HOST_STAMP_INSTALLED)
|
rm -rf $(HOST_STAMP_INSTALLED) $(HOST_STAMP_PROGRAMS)
|
||||||
|
|
||||||
ifneq ($(CONFIG_AUTOREMOVE),)
|
ifneq ($(CONFIG_AUTOREMOVE),)
|
||||||
host-compile:
|
host-compile:
|
||||||
|
|
|
@ -307,7 +307,7 @@ define Build/fit
|
||||||
$(if $(DEVICE_FDT_NUM),-n $(DEVICE_FDT_NUM)) \
|
$(if $(DEVICE_FDT_NUM),-n $(DEVICE_FDT_NUM)) \
|
||||||
$(if $(DEVICE_DTS_DELIMITER),-l $(DEVICE_DTS_DELIMITER)) \
|
$(if $(DEVICE_DTS_DELIMITER),-l $(DEVICE_DTS_DELIMITER)) \
|
||||||
$(if $(DEVICE_DTS_LOADADDR),-s $(DEVICE_DTS_LOADADDR)) \
|
$(if $(DEVICE_DTS_LOADADDR),-s $(DEVICE_DTS_LOADADDR)) \
|
||||||
$(if $(DEVICE_DTS_OVERLAY),$(foreach dtso,$(DEVICE_DTS_OVERLAY), -O $(dtso):$(KERNEL_BUILD_DIR)/image-$(dtso).dtb)) \
|
$(if $(DEVICE_DTS_OVERLAY),$(foreach dtso,$(DEVICE_DTS_OVERLAY), -O $(dtso):$(KERNEL_BUILD_DIR)/image-$(dtso).dtbo)) \
|
||||||
-c $(if $(DEVICE_DTS_CONFIG),$(DEVICE_DTS_CONFIG),"config-1") \
|
-c $(if $(DEVICE_DTS_CONFIG),$(DEVICE_DTS_CONFIG),"config-1") \
|
||||||
-A $(LINUX_KARCH) -v $(LINUX_VERSION)
|
-A $(LINUX_KARCH) -v $(LINUX_VERSION)
|
||||||
PATH=$(LINUX_DIR)/scripts/dtc:$(PATH) mkimage $(if $(findstring external,$(word 3,$(1))),\
|
PATH=$(LINUX_DIR)/scripts/dtc:$(PATH) mkimage $(if $(findstring external,$(word 3,$(1))),\
|
||||||
|
|
|
@ -146,7 +146,7 @@ endif
|
||||||
|
|
||||||
|
|
||||||
# Disable noisy checks by default as in upstream
|
# Disable noisy checks by default as in upstream
|
||||||
DTC_FLAGS += \
|
DTC_WARN_FLAGS := \
|
||||||
-Wno-unit_address_vs_reg \
|
-Wno-unit_address_vs_reg \
|
||||||
-Wno-simple_bus_reg \
|
-Wno-simple_bus_reg \
|
||||||
-Wno-unit_address_format \
|
-Wno-unit_address_format \
|
||||||
|
@ -159,6 +159,9 @@ DTC_FLAGS += \
|
||||||
-Wno-graph_port \
|
-Wno-graph_port \
|
||||||
-Wno-unique_unit_address
|
-Wno-unique_unit_address
|
||||||
|
|
||||||
|
DTC_FLAGS += $(DTC_WARN_FLAGS)
|
||||||
|
DTCO_FLAGS += $(DTC_WARN_FLAGS)
|
||||||
|
|
||||||
define Image/pad-to
|
define Image/pad-to
|
||||||
dd if=$(1) of=$(1).new bs=$(2) conv=sync
|
dd if=$(1) of=$(1).new bs=$(2) conv=sync
|
||||||
mv $(1).new $(1)
|
mv $(1).new $(1)
|
||||||
|
@ -174,7 +177,7 @@ endef
|
||||||
# $(2) target dtb file
|
# $(2) target dtb file
|
||||||
# $(3) extra CPP flags
|
# $(3) extra CPP flags
|
||||||
# $(4) extra DTC flags
|
# $(4) extra DTC flags
|
||||||
define Image/BuildDTB
|
define Image/BuildDTB/sub
|
||||||
$(TARGET_CROSS)cpp -nostdinc -x assembler-with-cpp \
|
$(TARGET_CROSS)cpp -nostdinc -x assembler-with-cpp \
|
||||||
$(DTS_CPPFLAGS) \
|
$(DTS_CPPFLAGS) \
|
||||||
-I$(DTS_DIR) \
|
-I$(DTS_DIR) \
|
||||||
|
@ -183,12 +186,20 @@ define Image/BuildDTB
|
||||||
-undef -D__DTS__ $(3) \
|
-undef -D__DTS__ $(3) \
|
||||||
-o $(2).tmp $(1)
|
-o $(2).tmp $(1)
|
||||||
$(LINUX_DIR)/scripts/dtc/dtc -O dtb \
|
$(LINUX_DIR)/scripts/dtc/dtc -O dtb \
|
||||||
-i$(dir $(1)) $(DTC_FLAGS) $(4) \
|
-i$(dir $(1)) $(4) \
|
||||||
$(if $(CONFIG_HAS_DT_OVERLAY_SUPPORT),-@) \
|
$(if $(CONFIG_HAS_DT_OVERLAY_SUPPORT),-@) \
|
||||||
-o $(2) $(2).tmp
|
-o $(2) $(2).tmp
|
||||||
$(RM) $(2).tmp
|
$(RM) $(2).tmp
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
define Image/BuildDTB
|
||||||
|
$(call Image/BuildDTB/sub,$(1),$(2),$(3),$(DTC_FLAGS) $(DEVICE_DTC_FLAGS) $(4))
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Image/BuildDTBO
|
||||||
|
$(call Image/BuildDTB/sub,$(1),$(2),$(3),$(DTCO_FLAGS) $(DEVICE_DTCO_FLAGS) $(4))
|
||||||
|
endef
|
||||||
|
|
||||||
define Image/mkfs/jffs2/sub-raw
|
define Image/mkfs/jffs2/sub-raw
|
||||||
$(STAGING_DIR_HOST)/bin/mkfs.jffs2 \
|
$(STAGING_DIR_HOST)/bin/mkfs.jffs2 \
|
||||||
$(2) \
|
$(2) \
|
||||||
|
@ -400,6 +411,8 @@ define Device/Init
|
||||||
DEVICE_DTS_LOADADDR :=
|
DEVICE_DTS_LOADADDR :=
|
||||||
DEVICE_DTS_OVERLAY :=
|
DEVICE_DTS_OVERLAY :=
|
||||||
DEVICE_FDT_NUM :=
|
DEVICE_FDT_NUM :=
|
||||||
|
DEVICE_DTC_FLAGS :=
|
||||||
|
DEVICE_DTCO_FLAGS :=
|
||||||
SOC :=
|
SOC :=
|
||||||
|
|
||||||
BOARD_NAME :=
|
BOARD_NAME :=
|
||||||
|
@ -422,9 +435,9 @@ endef
|
||||||
DEFAULT_DEVICE_VARS := \
|
DEFAULT_DEVICE_VARS := \
|
||||||
DEVICE_NAME KERNEL KERNEL_INITRAMFS KERNEL_INITRAMFS_IMAGE KERNEL_SIZE \
|
DEVICE_NAME KERNEL KERNEL_INITRAMFS KERNEL_INITRAMFS_IMAGE KERNEL_SIZE \
|
||||||
CMDLINE UBOOTENV_IN_UBI KERNEL_IN_UBI BLOCKSIZE PAGESIZE SUBPAGESIZE \
|
CMDLINE UBOOTENV_IN_UBI KERNEL_IN_UBI BLOCKSIZE PAGESIZE SUBPAGESIZE \
|
||||||
VID_HDR_OFFSET UBINIZE_OPTS UBINIZE_PARTS MKUBIFS_OPTS DEVICE_DTS \
|
VID_HDR_OFFSET UBINIZE_OPTS UBINIZE_PARTS MKUBIFS_OPTS DEVICE_DTC_FLAGS \
|
||||||
DEVICE_DTS_CONFIG DEVICE_DTS_DELIMITER DEVICE_DTS_DIR DEVICE_DTS_OVERLAY \
|
DEVICE_DTCO_FLAGS DEVICE_DTS DEVICE_DTS_CONFIG DEVICE_DTS_DELIMITER \
|
||||||
DEVICE_DTS_LOADADDR \
|
DEVICE_DTS_DIR DEVICE_DTS_OVERLAY DEVICE_DTS_LOADADDR \
|
||||||
DEVICE_FDT_NUM DEVICE_IMG_PREFIX SOC BOARD_NAME UIMAGE_MAGIC UIMAGE_NAME \
|
DEVICE_FDT_NUM DEVICE_IMG_PREFIX SOC BOARD_NAME UIMAGE_MAGIC UIMAGE_NAME \
|
||||||
UIMAGE_TIME SUPPORTED_DEVICES IMAGE_METADATA KERNEL_ENTRY KERNEL_LOADADDR \
|
UIMAGE_TIME SUPPORTED_DEVICES IMAGE_METADATA KERNEL_ENTRY KERNEL_LOADADDR \
|
||||||
UBOOT_PATH IMAGE_SIZE \
|
UBOOT_PATH IMAGE_SIZE \
|
||||||
|
@ -554,16 +567,33 @@ define Device/Build/dtb
|
||||||
image_prepare: $(KDIR)/image-$(1).dtb
|
image_prepare: $(KDIR)/image-$(1).dtb
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Device/Build/dtbo
|
||||||
|
ifndef BUILD_DTSO_$(1)
|
||||||
|
BUILD_DTSO_$(1) := 1
|
||||||
|
$(KDIR)/image-$(1).dtbo: FORCE
|
||||||
|
$(call Image/BuildDTBO,$(strip $(2))/$(strip $(3)).dtso,$$@)
|
||||||
|
|
||||||
|
image_prepare: $(KDIR)/image-$(1).dtbo
|
||||||
|
endif
|
||||||
|
|
||||||
endef
|
endef
|
||||||
endif
|
endif
|
||||||
|
|
||||||
define Device/Build/kernel
|
define Device/Build/kernel
|
||||||
$$(eval $$(foreach dts,$$(DEVICE_DTS) $$(DEVICE_DTS_OVERLAY), \
|
$$(eval $$(foreach dts,$$(DEVICE_DTS), \
|
||||||
$$(call Device/Build/dtb,$$(notdir $$(dts)), \
|
$$(call Device/Build/dtb,$$(notdir $$(dts)), \
|
||||||
$$(if $$(DEVICE_DTS_DIR),$$(DEVICE_DTS_DIR),$$(DTS_DIR)), \
|
$$(if $$(DEVICE_DTS_DIR),$$(DEVICE_DTS_DIR),$$(DTS_DIR)), \
|
||||||
$$(dts) \
|
$$(dts) \
|
||||||
) \
|
) \
|
||||||
))
|
))
|
||||||
|
$$(eval $$(foreach dtso,$$(DEVICE_DTS_OVERLAY), \
|
||||||
|
$$(call Device/Build/dtbo,$$(notdir $$(dtso)), \
|
||||||
|
$$(if $$(DEVICE_DTS_DIR),$$(DEVICE_DTS_DIR),$$(DTS_DIR)), \
|
||||||
|
$$(dtso) \
|
||||||
|
) \
|
||||||
|
))
|
||||||
|
|
||||||
$(KDIR)/$$(KERNEL_NAME):: image_prepare
|
$(KDIR)/$$(KERNEL_NAME):: image_prepare
|
||||||
$$(_TARGET): $$(if $$(KERNEL_INSTALL),$(BIN_DIR)/$$(KERNEL_IMAGE))
|
$$(_TARGET): $$(if $$(KERNEL_INSTALL),$(BIN_DIR)/$$(KERNEL_IMAGE))
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
LINUX_VERSION-6.1 = .31
|
LINUX_VERSION-6.1 = .32
|
||||||
LINUX_KERNEL_HASH-6.1.31 = e86917bba1990e967943645484182a64ba325f98b114a1906cc1d50992e073c1
|
LINUX_KERNEL_HASH-6.1.32 = 7c88b7a09ba2b9e47b78eba2b32b1db6a4d89636f7ddd586545f9671a2521a6c
|
|
@ -28,9 +28,9 @@ define Require
|
||||||
|
|
||||||
prereq-$(1): $(if $(PREREQ_PREV),prereq-$(PREREQ_PREV)) FORCE
|
prereq-$(1): $(if $(PREREQ_PREV),prereq-$(PREREQ_PREV)) FORCE
|
||||||
printf "Checking '$(1)'... "
|
printf "Checking '$(1)'... "
|
||||||
if $(NO_TRACE_MAKE) -f $(firstword $(MAKEFILE_LIST)) check-$(1) >/dev/null 2>/dev/null; then \
|
if $(NO_TRACE_MAKE) -f $(firstword $(MAKEFILE_LIST)) check-$(1) PATH="$(ORIG_PATH)" >/dev/null 2>/dev/null; then \
|
||||||
echo 'ok.'; \
|
echo 'ok.'; \
|
||||||
elif $(NO_TRACE_MAKE) -f $(firstword $(MAKEFILE_LIST)) check-$(1) >/dev/null 2>/dev/null; then \
|
elif $(NO_TRACE_MAKE) -f $(firstword $(MAKEFILE_LIST)) check-$(1) PATH="$(ORIG_PATH)" >/dev/null 2>/dev/null; then \
|
||||||
echo 'updated.'; \
|
echo 'updated.'; \
|
||||||
else \
|
else \
|
||||||
echo 'failed.'; \
|
echo 'failed.'; \
|
||||||
|
@ -104,16 +104,24 @@ define SetupHostCommand
|
||||||
$(call QuoteHostCommand,$(9)) $(call QuoteHostCommand,$(10)) \
|
$(call QuoteHostCommand,$(9)) $(call QuoteHostCommand,$(10)) \
|
||||||
$(call QuoteHostCommand,$(11)) $(call QuoteHostCommand,$(12)); do \
|
$(call QuoteHostCommand,$(11)) $(call QuoteHostCommand,$(12)); do \
|
||||||
if [ -n "$$$$$$$$cmd" ]; then \
|
if [ -n "$$$$$$$$cmd" ]; then \
|
||||||
bin="$$$$$$$$(PATH="$(subst $(space),:,$(filter-out $(STAGING_DIR_HOST)/%,$(subst :,$(space),$(PATH))))" \
|
bin="$$$$$$$$(command -v "$$$$$$$${cmd%% *}")"; \
|
||||||
command -v "$$$$$$$${cmd%% *}")"; \
|
|
||||||
if [ -x "$$$$$$$$bin" ] && eval "$$$$$$$$cmd" >/dev/null 2>/dev/null; then \
|
if [ -x "$$$$$$$$bin" ] && eval "$$$$$$$$cmd" >/dev/null 2>/dev/null; then \
|
||||||
case "$$$$$$$$(ls -dl -- $(STAGING_DIR_HOST)/bin/$(strip $(1)))" in \
|
case "$$$$$$$$(ls -dl -- $(STAGING_DIR_HOST)/bin/$(strip $(1)))" in \
|
||||||
*" -> $$$$$$$$bin"*) \
|
*" -> $$$$$$$$bin"*) \
|
||||||
[ -x "$(STAGING_DIR_HOST)/bin/$(strip $(1))" ] && exit 0 \
|
[ -x "$(STAGING_DIR_HOST)/bin/$(strip $(1))" ] && exit 0 \
|
||||||
;; \
|
;; \
|
||||||
|
"-"*) \
|
||||||
|
find "$(STAGING_DIR_HOST)/stamp" | grep $(strip $(1)) && \
|
||||||
|
[ -x "$(STAGING_DIR_HOST)/bin/$(strip $(1))" ] && exit 0 \
|
||||||
|
;; \
|
||||||
|
*" -> /"*) \
|
||||||
|
;; \
|
||||||
|
*" -> "*) \
|
||||||
|
[ -x "$(STAGING_DIR_HOST)/bin/$(strip $(1))" ] && exit 0 \
|
||||||
|
;; \
|
||||||
esac; \
|
esac; \
|
||||||
ln -sf "$$$$$$$$bin" "$(STAGING_DIR_HOST)/bin/$(strip $(1))"; \
|
ln -sf "$$$$$$$$bin" "$(STAGING_DIR_HOST)/bin/$(strip $(1))"; \
|
||||||
exit 0; \
|
exit 1; \
|
||||||
fi; \
|
fi; \
|
||||||
fi; \
|
fi; \
|
||||||
done; \
|
done; \
|
||||||
|
|
|
@ -11,6 +11,7 @@ TARGET_STAMP:=$(TMP_DIR)/info/.files-$(SCAN_TARGET).stamp
|
||||||
FILELIST:=$(TMP_DIR)/info/.files-$(SCAN_TARGET)-$(SCAN_COOKIE)
|
FILELIST:=$(TMP_DIR)/info/.files-$(SCAN_TARGET)-$(SCAN_COOKIE)
|
||||||
OVERRIDELIST:=$(TMP_DIR)/info/.overrides-$(SCAN_TARGET)-$(SCAN_COOKIE)
|
OVERRIDELIST:=$(TMP_DIR)/info/.overrides-$(SCAN_TARGET)-$(SCAN_COOKIE)
|
||||||
|
|
||||||
|
export ORIG_PATH:=$(if $(ORIG_PATH),$(ORIG_PATH),$(PATH))
|
||||||
export PATH:=$(STAGING_DIR_HOST)/bin:$(PATH)
|
export PATH:=$(STAGING_DIR_HOST)/bin:$(PATH)
|
||||||
|
|
||||||
define feedname
|
define feedname
|
||||||
|
|
|
@ -50,6 +50,7 @@ space:= $(empty) $(empty)
|
||||||
path:=$(subst :,$(space),$(PATH))
|
path:=$(subst :,$(space),$(PATH))
|
||||||
path:=$(filter-out .%,$(path))
|
path:=$(filter-out .%,$(path))
|
||||||
path:=$(subst $(space),:,$(path))
|
path:=$(subst $(space),:,$(path))
|
||||||
|
export ORIG_PATH:=$(if $(ORIG_PATH),$(ORIG_PATH),$(PATH))
|
||||||
export PATH:=$(path)
|
export PATH:=$(path)
|
||||||
export STAGING_DIR_HOST:=$(if $(STAGING_DIR),$(abspath $(STAGING_DIR)/../host),$(TOPDIR)/staging_dir/host)
|
export STAGING_DIR_HOST:=$(if $(STAGING_DIR),$(abspath $(STAGING_DIR)/../host),$(TOPDIR)/staging_dir/host)
|
||||||
|
|
||||||
|
|
|
@ -173,9 +173,9 @@
|
||||||
+loadaddr=0x48000000
|
+loadaddr=0x48000000
|
||||||
+bootargs=root=/dev/mmcblk1p65
|
+bootargs=root=/dev/mmcblk1p65
|
||||||
+bootcmd=if pstore check ; then run boot_recovery ; else run boot_sdmmc ; fi
|
+bootcmd=if pstore check ; then run boot_recovery ; else run boot_sdmmc ; fi
|
||||||
+bootconf=config-mt7622-bananapi-bpi-r64-pcie1
|
+bootconf=config-1#mt7622-bananapi-bpi-r64-pcie1
|
||||||
+bootconf_pcie=config-mt7622-bananapi-bpi-r64-pcie1
|
+bootconf_pcie=config-1#mt7622-bananapi-bpi-r64-pcie1
|
||||||
+bootconf_sata=config-mt7622-bananapi-bpi-r64-sata
|
+bootconf_sata=config-1#mt7622-bananapi-bpi-r64-sata
|
||||||
+bootdelay=0
|
+bootdelay=0
|
||||||
+bootfile=openwrt-mediatek-mt7622-bananapi_bpi-r64-initramfs-recovery.itb
|
+bootfile=openwrt-mediatek-mt7622-bananapi_bpi-r64-initramfs-recovery.itb
|
||||||
+bootfile_emmcbl2=openwrt-mediatek-mt7622-bananapi_bpi-r64-emmc-preloader.bin
|
+bootfile_emmcbl2=openwrt-mediatek-mt7622-bananapi_bpi-r64-emmc-preloader.bin
|
||||||
|
@ -412,9 +412,9 @@
|
||||||
+loadaddr=0x48000000
|
+loadaddr=0x48000000
|
||||||
+bootcmd=if pstore check ; then run boot_recovery ; else run boot_emmc ; fi
|
+bootcmd=if pstore check ; then run boot_recovery ; else run boot_emmc ; fi
|
||||||
+bootargs=root=/dev/mmcblk0p65
|
+bootargs=root=/dev/mmcblk0p65
|
||||||
+bootconf=config-mt7622-bananapi-bpi-r64-pcie1
|
+bootconf=config-1#mt7622-bananapi-bpi-r64-pcie1
|
||||||
+bootconf_pcie=config-mt7622-bananapi-bpi-r64-pcie1
|
+bootconf_pcie=config-1#mt7622-bananapi-bpi-r64-pcie1
|
||||||
+bootconf_sata=config-mt7622-bananapi-bpi-r64-sata
|
+bootconf_sata=config-1#mt7622-bananapi-bpi-r64-sata
|
||||||
+bootdelay=0
|
+bootdelay=0
|
||||||
+bootfile=openwrt-mediatek-mt7622-bananapi_bpi-r64-initramfs-recovery.itb
|
+bootfile=openwrt-mediatek-mt7622-bananapi_bpi-r64-initramfs-recovery.itb
|
||||||
+bootfile_upg=openwrt-mediatek-mt7622-bananapi_bpi-r64-squashfs-sysupgrade.itb
|
+bootfile_upg=openwrt-mediatek-mt7622-bananapi_bpi-r64-squashfs-sysupgrade.itb
|
||||||
|
@ -619,9 +619,9 @@
|
||||||
+loadaddr=0x48000000
|
+loadaddr=0x48000000
|
||||||
+bootargs=root=/dev/ubiblock0_2p1
|
+bootargs=root=/dev/ubiblock0_2p1
|
||||||
+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi
|
+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi
|
||||||
+bootconf=config-mt7622-bananapi-bpi-r64-pcie1
|
+bootconf=config-1#mt7622-bananapi-bpi-r64-pcie1
|
||||||
+bootconf_pcie=config-mt7622-bananapi-bpi-r64-pcie1
|
+bootconf_pcie=config-1#mt7622-bananapi-bpi-r64-pcie1
|
||||||
+bootconf_sata=config-mt7622-bananapi-bpi-r64-sata
|
+bootconf_sata=config-1#mt7622-bananapi-bpi-r64-sata
|
||||||
+bootdelay=0
|
+bootdelay=0
|
||||||
+bootfile=openwrt-mediatek-mt7622-bananapi_bpi-r64-initramfs-recovery.itb
|
+bootfile=openwrt-mediatek-mt7622-bananapi_bpi-r64-initramfs-recovery.itb
|
||||||
+bootfile_fip=openwrt-mediatek-mt7622-bananapi_bpi-r64-snand-bl31-uboot.fip
|
+bootfile_fip=openwrt-mediatek-mt7622-bananapi_bpi-r64-snand-bl31-uboot.fip
|
||||||
|
|
|
@ -1118,7 +1118,7 @@
|
||||||
+
|
+
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/bananapi_bpi-r3_sdmmc_env
|
+++ b/bananapi_bpi-r3_sdmmc_env
|
||||||
@@ -0,0 +1,75 @@
|
@@ -0,0 +1,80 @@
|
||||||
+ipaddr=192.168.1.1
|
+ipaddr=192.168.1.1
|
||||||
+serverip=192.168.1.254
|
+serverip=192.168.1.254
|
||||||
+loadaddr=0x46000000
|
+loadaddr=0x46000000
|
||||||
|
@ -1126,6 +1126,11 @@
|
||||||
+bootargs=root=/dev/mmcblk0p65
|
+bootargs=root=/dev/mmcblk0p65
|
||||||
+bootcmd=if pstore check ; then run boot_recovery ; else run boot_sdmmc ; fi
|
+bootcmd=if pstore check ; then run boot_recovery ; else run boot_sdmmc ; fi
|
||||||
+bootconf=config-mt7986a-bananapi-bpi-r3
|
+bootconf=config-mt7986a-bananapi-bpi-r3
|
||||||
|
+bootconf_base=config-mt7986a-bananapi-bpi-r3
|
||||||
|
+bootconf_nor=mt7986a-bananapi-bpi-r3-nor
|
||||||
|
+bootconf_nand=mt7986a-bananapi-bpi-r3-nand
|
||||||
|
+bootconf_sd=mt7986a-bananapi-bpi-r3-sd
|
||||||
|
+bootconf_emmc=mt7986a-bananapi-bpi-r3-emmc
|
||||||
+bootdelay=0
|
+bootdelay=0
|
||||||
+bootfile=openwrt-mediatek-filogic-bananapi_bpi-r3-initramfs-recovery.itb
|
+bootfile=openwrt-mediatek-filogic-bananapi_bpi-r3-initramfs-recovery.itb
|
||||||
+bootfile_upg=openwrt-mediatek-filogic-bananapi_bpi-r3-squashfs-sysupgrade.itb
|
+bootfile_upg=openwrt-mediatek-filogic-bananapi_bpi-r3-squashfs-sysupgrade.itb
|
||||||
|
@ -1146,7 +1151,7 @@
|
||||||
+bootmenu_7=[31mInstall bootloader, recovery and production to NAND.[0m=if nand info ; then run ubi_init ; else echo "NAND not detected" ; fi ; run bootmenu_confirm_return
|
+bootmenu_7=[31mInstall bootloader, recovery and production to NAND.[0m=if nand info ; then run ubi_init ; else echo "NAND not detected" ; fi ; run bootmenu_confirm_return
|
||||||
+bootmenu_8=Reboot.=reset
|
+bootmenu_8=Reboot.=reset
|
||||||
+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset
|
+bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset
|
||||||
+boot_update_conf=if nand info ; then setenv bootconf config-mt7986a-bananapi-bpi-r3-snand ; else if sf probe ; then setenv bootconf config-mt7986a-bananapi-bpi-r3-nor ; else setenv bootconf config-mt7986a-bananapi-bpi-r3 ; fi ; fi
|
+boot_update_conf=if nand info ; then setenv bootconf $bootconf_base#$bootconf_sd#$bootconf_nand ; else if sf probe ; then setenv bootconf $bootconf_base#$bootconf_sd#$bootconf_nor ; else setenv bootconf $bootconf_base#$bootconf_sd ; fi ; fi
|
||||||
+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu
|
+boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu
|
||||||
+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever
|
+boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever
|
||||||
+boot_production=led $bootled_pwr on ; run boot_update_conf ; run sdmmc_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off
|
+boot_production=led $bootled_pwr on ; run boot_update_conf ; run sdmmc_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off
|
||||||
|
@ -1196,14 +1201,19 @@
|
||||||
+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title [33m$ver[0m"
|
+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title [33m$ver[0m"
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/bananapi_bpi-r3_nor_env
|
+++ b/bananapi_bpi-r3_nor_env
|
||||||
@@ -0,0 +1,55 @@
|
@@ -0,0 +1,60 @@
|
||||||
+ipaddr=192.168.1.1
|
+ipaddr=192.168.1.1
|
||||||
+serverip=192.168.1.254
|
+serverip=192.168.1.254
|
||||||
+loadaddr=0x46000000
|
+loadaddr=0x46000000
|
||||||
+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0
|
+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0
|
||||||
+bootargs=root=/dev/mtdblock0p1
|
+bootargs=root=/dev/mtdblock0p1
|
||||||
+bootcmd=if pstore check ; then run boot_recovery ; else run boot_nor ; fi
|
+bootcmd=if pstore check ; then run boot_recovery ; else run boot_nor ; fi
|
||||||
+bootconf=config-mt7986a-bananapi-bpi-r3-emmc-nor
|
+bootconf=config-mt7986a-bananapi-bpi-r3
|
||||||
|
+bootconf_base=config-mt7986a-bananapi-bpi-r3
|
||||||
|
+bootconf_nor=mt7986a-bananapi-bpi-r3-nor
|
||||||
|
+bootconf_nand=mt7986a-bananapi-bpi-r3-nand
|
||||||
|
+bootconf_sd=mt7986a-bananapi-bpi-r3-sd
|
||||||
|
+bootconf_emmc=mt7986a-bananapi-bpi-r3-emmc
|
||||||
+bootdelay=0
|
+bootdelay=0
|
||||||
+bootfile=openwrt-mediatek-filogic-bananapi_bpi-r3-initramfs-recovery.itb
|
+bootfile=openwrt-mediatek-filogic-bananapi_bpi-r3-initramfs-recovery.itb
|
||||||
+bootfile_bl2=openwrt-mediatek-filogic-bananapi_bpi-r3-nor-preloader.bin
|
+bootfile_bl2=openwrt-mediatek-filogic-bananapi_bpi-r3-nor-preloader.bin
|
||||||
|
@ -1238,7 +1248,7 @@
|
||||||
+boot_tftp=run boot_update_conf ; tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf
|
+boot_tftp=run boot_update_conf ; tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf
|
||||||
+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run boot_write_fip
|
+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run boot_write_fip
|
||||||
+boot_tftp_write_preloader=tftpboot $loadaddr $bootfile_bl2 && run boot_write_preloader
|
+boot_tftp_write_preloader=tftpboot $loadaddr $bootfile_bl2 && run boot_write_preloader
|
||||||
+boot_update_conf=if mmc partconf 0 ; then setenv bootconf config-mt7986a-bananapi-bpi-r3-emmc-nor ; else setenv bootconf config-mt7986a-bananapi-bpi-r3-nor ; fi
|
+boot_update_conf=if mmc partconf 0 ; then setenv bootconf $bootconf_base#$bootconf_nor#$bootconf_emmc ; else setenv bootconf $bootconf_base#$bootconf_nor#$bootconf_sd ; fi
|
||||||
+boot_nor=run boot_production ; run boot_recovery
|
+boot_nor=run boot_production ; run boot_recovery
|
||||||
+boot_write_fip=mtd erase fip && mtd write fip $loadaddr
|
+boot_write_fip=mtd erase fip && mtd write fip $loadaddr
|
||||||
+boot_write_preloader=mtd erase bl2 && mtd write bl2 $loadaddr
|
+boot_write_preloader=mtd erase bl2 && mtd write bl2 $loadaddr
|
||||||
|
@ -1254,13 +1264,18 @@
|
||||||
+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title [33m$ver[0m"
|
+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title [33m$ver[0m"
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/bananapi_bpi-r3_snand_env
|
+++ b/bananapi_bpi-r3_snand_env
|
||||||
@@ -0,0 +1,69 @@
|
@@ -0,0 +1,74 @@
|
||||||
+ipaddr=192.168.1.1
|
+ipaddr=192.168.1.1
|
||||||
+serverip=192.168.1.254
|
+serverip=192.168.1.254
|
||||||
+loadaddr=0x46000000
|
+loadaddr=0x46000000
|
||||||
+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0
|
+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0
|
||||||
+bootargs=root=/dev/ubiblock0_2p1
|
+bootargs=root=/dev/ubiblock0_2p1
|
||||||
+bootconf=config-mt7986a-bananapi-bpi-r3-snand
|
+bootconf=config-mt7986a-bananapi-bpi-r3
|
||||||
|
+bootconf_base=config-mt7986a-bananapi-bpi-r3
|
||||||
|
+bootconf_nor=mt7986a-bananapi-bpi-r3-nor
|
||||||
|
+bootconf_nand=mt7986a-bananapi-bpi-r3-nand
|
||||||
|
+bootconf_sd=mt7986a-bananapi-bpi-r3-sd
|
||||||
|
+bootconf_emmc=mt7986a-bananapi-bpi-r3-emmc
|
||||||
+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi
|
+bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi
|
||||||
+bootdelay=0
|
+bootdelay=0
|
||||||
+bootfile=openwrt-mediatek-filogic-bananapi_bpi-r3-initramfs-recovery.itb
|
+bootfile=openwrt-mediatek-filogic-bananapi_bpi-r3-initramfs-recovery.itb
|
||||||
|
@ -1296,7 +1311,7 @@
|
||||||
+boot_tftp=run boot_update_conf ; tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf
|
+boot_tftp=run boot_update_conf ; tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf
|
||||||
+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run mtd_write_fip && run reset_factory
|
+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run mtd_write_fip && run reset_factory
|
||||||
+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run mtd_write_bl2
|
+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run mtd_write_bl2
|
||||||
+boot_update_conf=if mmc partconf 0 ; then setenv bootconf config-mt7986a-bananapi-bpi-r3-emmc-snand ; else setenv bootconf config-mt7986a-bananapi-bpi-r3-snand ; fi
|
+boot_update_conf=if mmc partconf 0 ; then setenv bootconf $bootconf_base#$bootconf_nand#$bootconf_emmc ; else setenv bootconf $bootconf_base#$bootconf_nand#$bootconf_sd ; fi
|
||||||
+part_default=production
|
+part_default=production
|
||||||
+part_recovery=recovery
|
+part_recovery=recovery
|
||||||
+reset_factory=ubi part ubi ; mw $loadaddr 0x0 0x800 ; ubi write $loadaddr ubootenv 0x800 ; ubi write $loadaddr ubootenv2 0x800
|
+reset_factory=ubi part ubi ; mw $loadaddr 0x0 0x800 ; ubi write $loadaddr ubootenv 0x800 ; ubi write $loadaddr ubootenv2 0x800
|
||||||
|
@ -1326,14 +1341,19 @@
|
||||||
+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title [33m$ver[0m"
|
+_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title [33m$ver[0m"
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/bananapi_bpi-r3_emmc_env
|
+++ b/bananapi_bpi-r3_emmc_env
|
||||||
@@ -0,0 +1,56 @@
|
@@ -0,0 +1,61 @@
|
||||||
+ipaddr=192.168.1.1
|
+ipaddr=192.168.1.1
|
||||||
+serverip=192.168.1.254
|
+serverip=192.168.1.254
|
||||||
+loadaddr=0x46000000
|
+loadaddr=0x46000000
|
||||||
+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0
|
+console=earlycon=uart8250,mmio32,0x11002000 console=ttyS0
|
||||||
+bootargs=root=/dev/mmcblk0p65
|
+bootargs=root=/dev/mmcblk0p65
|
||||||
+bootcmd=if pstore check ; then run boot_recovery ; else run boot_emmc ; fi
|
+bootcmd=if pstore check ; then run boot_recovery ; else run boot_emmc ; fi
|
||||||
+bootconf=config-mt7986a-bananapi-bpi-r3-emmc
|
+bootconf=config-mt7986a-bananapi-bpi-r3
|
||||||
|
+bootconf_base=config-mt7986a-bananapi-bpi-r3
|
||||||
|
+bootconf_nor=mt7986a-bananapi-bpi-r3-nor
|
||||||
|
+bootconf_nand=mt7986a-bananapi-bpi-r3-nand
|
||||||
|
+bootconf_sd=mt7986a-bananapi-bpi-r3-sd
|
||||||
|
+bootconf_emmc=mt7986a-bananapi-bpi-r3-emmc
|
||||||
+bootdelay=0
|
+bootdelay=0
|
||||||
+bootfile=openwrt-mediatek-filogic-bananapi_bpi-r3-initramfs-recovery.itb
|
+bootfile=openwrt-mediatek-filogic-bananapi_bpi-r3-initramfs-recovery.itb
|
||||||
+bootfile_bl2=openwrt-mediatek-filogic-bananapi_bpi-r3-emmc-preloader.bin
|
+bootfile_bl2=openwrt-mediatek-filogic-bananapi_bpi-r3-emmc-preloader.bin
|
||||||
|
@ -1367,7 +1387,7 @@
|
||||||
+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run emmc_write_fip
|
+boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run emmc_write_fip
|
||||||
+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run emmc_write_bl2
|
+boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run emmc_write_bl2
|
||||||
+boot_tftp=run boot_update_conf ; tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf
|
+boot_tftp=run boot_update_conf ; tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf
|
||||||
+boot_update_conf=if nand info ; then setenv bootconf config-mt7986a-bananapi-bpi-r3-emmc-snand ; else setenv bootconf config-mt7986a-bananapi-bpi-r3-emmc-nor ; fi
|
+boot_update_conf=if nand info ; then setenv bootconf $bootconf_base#$bootconf_emmc#$bootconf_nand ; else setenv bootconf $bootconf_base#$bootconf_emmc#$bootconf_nor ; fi
|
||||||
+mmc_write_vol=imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc erase 0x$part_addr 0x$image_size && mmc write $loadaddr 0x$part_addr 0x$image_size
|
+mmc_write_vol=imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc erase 0x$part_addr 0x$image_size && mmc write $loadaddr 0x$part_addr 0x$image_size
|
||||||
+mmc_read_vol=mmc read $loadaddr $part_addr 0x8 && imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc read $loadaddr 0x$part_addr 0x$image_size && setexpr filesize $image_size * 0x200
|
+mmc_read_vol=mmc read $loadaddr $part_addr 0x8 && imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc read $loadaddr 0x$part_addr 0x$image_size && setexpr filesize $image_size * 0x200
|
||||||
+part_default=production
|
+part_default=production
|
||||||
|
|
|
@ -146,6 +146,8 @@ unsigned int ifx_ptm_dbg_enable = DBG_ENABLE_MASK_ERR;
|
||||||
|
|
||||||
static void ptm_setup(struct net_device *dev, int ndev)
|
static void ptm_setup(struct net_device *dev, int ndev)
|
||||||
{
|
{
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
|
||||||
netif_carrier_off(dev);
|
netif_carrier_off(dev);
|
||||||
|
|
||||||
dev->netdev_ops = &g_ptm_netdev_ops;
|
dev->netdev_ops = &g_ptm_netdev_ops;
|
||||||
|
@ -154,12 +156,13 @@ static void ptm_setup(struct net_device *dev, int ndev)
|
||||||
netif_napi_add(dev, &g_ptm_priv_data.itf[ndev].napi, ptm_napi_poll, 16);
|
netif_napi_add(dev, &g_ptm_priv_data.itf[ndev].napi, ptm_napi_poll, 16);
|
||||||
dev->watchdog_timeo = ETH_WATCHDOG_TIMEOUT;
|
dev->watchdog_timeo = ETH_WATCHDOG_TIMEOUT;
|
||||||
|
|
||||||
dev->dev_addr[0] = 0x00;
|
addr[0] = 0x00;
|
||||||
dev->dev_addr[1] = 0x20;
|
addr[1] = 0x20;
|
||||||
dev->dev_addr[2] = 0xda;
|
addr[2] = 0xda;
|
||||||
dev->dev_addr[3] = 0x86;
|
addr[3] = 0x86;
|
||||||
dev->dev_addr[4] = 0x23;
|
addr[4] = 0x23;
|
||||||
dev->dev_addr[5] = 0x75 + ndev;
|
addr[5] = 0x75 + ndev;
|
||||||
|
eth_hw_addr_set(dev, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct net_device_stats *ptm_get_stats(struct net_device *dev)
|
static struct net_device_stats *ptm_get_stats(struct net_device *dev)
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
From 695df2f417d25202bdac9cde3c82d2acb6492b4d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Arnd Bergmann <arnd@arndb.de>
|
||||||
|
Date: Fri, 5 May 2023 16:11:25 +0300
|
||||||
|
Subject: [PATCH] wifi: ath: work around false-positive stringop-overread
|
||||||
|
warning
|
||||||
|
|
||||||
|
In a rare arm64 randconfig build, I got multiple warnings for ath11k
|
||||||
|
and ath12k:
|
||||||
|
|
||||||
|
In function 'ath11k_peer_assoc_h_ht',
|
||||||
|
inlined from 'ath11k_peer_assoc_prepare' at drivers/net/wireless/ath/ath11k/mac.c:2665:2:
|
||||||
|
drivers/net/wireless/ath/ath11k/mac.c:1709:13: error: 'ath11k_peer_assoc_h_ht_masked' reading 10 bytes from a region of size 0 [-Werror=stringop-overread]
|
||||||
|
1709 | if (ath11k_peer_assoc_h_ht_masked(ht_mcs_mask))
|
||||||
|
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
This happens whenever gcc-13 fails to inline one of the functions
|
||||||
|
that take a fixed-length array argument but gets passed a pointer.
|
||||||
|
|
||||||
|
Change these functions to all take a regular pointer argument
|
||||||
|
instead.
|
||||||
|
|
||||||
|
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230417205447.1800912-1-arnd@kernel.org
|
||||||
|
---
|
||||||
|
drivers/net/wireless/ath/ath11k/mac.c | 12 ++++++------
|
||||||
|
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
@@ -433,7 +433,7 @@ u8 ath11k_mac_bitrate_to_idx(const struc
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32
|
||||||
|
-ath11k_mac_max_ht_nss(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
|
||||||
|
+ath11k_mac_max_ht_nss(const u8 *ht_mcs_mask)
|
||||||
|
{
|
||||||
|
int nss;
|
||||||
|
|
||||||
|
@@ -445,7 +445,7 @@ ath11k_mac_max_ht_nss(const u8 ht_mcs_ma
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32
|
||||||
|
-ath11k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
|
||||||
|
+ath11k_mac_max_vht_nss(const u16 *vht_mcs_mask)
|
||||||
|
{
|
||||||
|
int nss;
|
||||||
|
|
||||||
|
@@ -457,7 +457,7 @@ ath11k_mac_max_vht_nss(const u16 vht_mcs
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32
|
||||||
|
-ath11k_mac_max_he_nss(const u16 he_mcs_mask[NL80211_HE_NSS_MAX])
|
||||||
|
+ath11k_mac_max_he_nss(const u16 *he_mcs_mask)
|
||||||
|
{
|
||||||
|
int nss;
|
||||||
|
|
||||||
|
@@ -1658,7 +1658,7 @@ static void ath11k_peer_assoc_h_rates(st
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
-ath11k_peer_assoc_h_ht_masked(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
|
||||||
|
+ath11k_peer_assoc_h_ht_masked(const u8 *ht_mcs_mask)
|
||||||
|
{
|
||||||
|
int nss;
|
||||||
|
|
||||||
|
@@ -1670,7 +1670,7 @@ ath11k_peer_assoc_h_ht_masked(const u8 h
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
-ath11k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[])
|
||||||
|
+ath11k_peer_assoc_h_vht_masked(const u16 *vht_mcs_mask)
|
||||||
|
{
|
||||||
|
int nss;
|
||||||
|
|
||||||
|
@@ -2065,7 +2065,7 @@ static u16 ath11k_peer_assoc_h_he_limit(
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
-ath11k_peer_assoc_h_he_masked(const u16 he_mcs_mask[NL80211_HE_NSS_MAX])
|
||||||
|
+ath11k_peer_assoc_h_he_masked(const u16 *he_mcs_mask)
|
||||||
|
{
|
||||||
|
int nss;
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
From a08dbb04d7365a04d52882143cf196005bfc88c3 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Date: Fri, 5 May 2023 16:11:27 +0300
|
||||||
|
Subject: [PATCH 71/77] wifi: ath11k: driver settings for MBSSID and EMA
|
||||||
|
|
||||||
|
Advertise the driver support for multiple BSSID (MBSSID) and
|
||||||
|
enhanced multi-BSSID advertisements (EMA) by setting extended
|
||||||
|
capabilities.
|
||||||
|
|
||||||
|
Configure mbssid_max_interfaces and ema_max_profile_periodicity
|
||||||
|
fields in structure wiphy which are used to advertise maximum number
|
||||||
|
of interfaces and profile periodicity supported by the driver.
|
||||||
|
|
||||||
|
Add new WMI fields to configure maximum vdev count supported for
|
||||||
|
MBSSID and profile periodicity in case of EMA.
|
||||||
|
Setting WMI_RSRC_CFG_FLAG2_CALC_NEXT_DTIM_COUNT_SET flag
|
||||||
|
indicates that the firmware should track and update the DTIM counts
|
||||||
|
for each non-transmitted profile.
|
||||||
|
|
||||||
|
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
||||||
|
|
||||||
|
Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Co-developed-by: John Crispin <john@phrozen.org>
|
||||||
|
Signed-off-by: John Crispin <john@phrozen.org>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230405221648.17950-2-quic_alokad@quicinc.com
|
||||||
|
---
|
||||||
|
drivers/net/wireless/ath/ath11k/hw.c | 3 +++
|
||||||
|
drivers/net/wireless/ath/ath11k/hw.h | 1 +
|
||||||
|
drivers/net/wireless/ath/ath11k/mac.c | 7 +++++++
|
||||||
|
drivers/net/wireless/ath/ath11k/wmi.c | 3 +++
|
||||||
|
drivers/net/wireless/ath/ath11k/wmi.h | 6 ++++++
|
||||||
|
5 files changed, 20 insertions(+)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/hw.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/hw.c
|
||||||
|
@@ -202,6 +202,9 @@ static void ath11k_init_wmi_config_ipq80
|
||||||
|
config->twt_ap_sta_count = 1000;
|
||||||
|
config->flag1 |= WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64;
|
||||||
|
config->flag1 |= WMI_RSRC_CFG_FLAG1_ACK_RSSI;
|
||||||
|
+ config->ema_max_vap_cnt = ab->num_radios;
|
||||||
|
+ config->ema_max_profile_period = TARGET_EMA_MAX_PROFILE_PERIOD;
|
||||||
|
+ config->beacon_tx_offload_max_vdev += config->ema_max_vap_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ath11k_hw_mac_id_to_pdev_id_ipq8074(struct ath11k_hw_params *hw,
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/hw.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/hw.h
|
||||||
|
@@ -64,6 +64,7 @@
|
||||||
|
#define TARGET_NUM_WDS_ENTRIES 32
|
||||||
|
#define TARGET_DMA_BURST_SIZE 1
|
||||||
|
#define TARGET_RX_BATCHMODE 1
|
||||||
|
+#define TARGET_EMA_MAX_PROFILE_PERIOD 8
|
||||||
|
|
||||||
|
#define ATH11K_HW_MAX_QUEUES 4
|
||||||
|
#define ATH11K_QUEUE_LEN 4096
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
@@ -9001,19 +9001,23 @@ static int ath11k_mac_setup_iface_combin
|
||||||
|
|
||||||
|
static const u8 ath11k_if_types_ext_capa[] = {
|
||||||
|
[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
|
||||||
|
+ [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
|
||||||
|
[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 ath11k_if_types_ext_capa_sta[] = {
|
||||||
|
[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
|
||||||
|
+ [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
|
||||||
|
[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
|
||||||
|
[9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 ath11k_if_types_ext_capa_ap[] = {
|
||||||
|
[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
|
||||||
|
+ [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
|
||||||
|
[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
|
||||||
|
[9] = WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT,
|
||||||
|
+ [10] = WLAN_EXT_CAPA11_EMA_SUPPORT,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wiphy_iftype_ext_capab ath11k_iftypes_ext_capa[] = {
|
||||||
|
@@ -9251,6 +9255,9 @@ static int __ath11k_mac_register(struct
|
||||||
|
wiphy_ext_feature_set(ar->hw->wiphy,
|
||||||
|
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER);
|
||||||
|
|
||||||
|
+ ar->hw->wiphy->mbssid_max_interfaces = TARGET_NUM_VDEVS(ab);
|
||||||
|
+ ar->hw->wiphy->ema_max_profile_periodicity = TARGET_EMA_MAX_PROFILE_PERIOD;
|
||||||
|
+
|
||||||
|
ath11k_reg_init(ar);
|
||||||
|
|
||||||
|
if (!test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) {
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
|
@@ -3987,6 +3987,9 @@ ath11k_wmi_copy_resource_config(struct w
|
||||||
|
~(1 << WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT);
|
||||||
|
wmi_cfg->host_service_flags |= (tg_cfg->is_reg_cc_ext_event_supported <<
|
||||||
|
WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT);
|
||||||
|
+ wmi_cfg->flags2 = WMI_RSRC_CFG_FLAG2_CALC_NEXT_DTIM_COUNT_SET;
|
||||||
|
+ wmi_cfg->ema_max_vap_cnt = tg_cfg->ema_max_vap_cnt;
|
||||||
|
+ wmi_cfg->ema_max_profile_period = tg_cfg->ema_max_profile_period;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi,
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/wmi.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
|
||||||
|
@@ -2317,6 +2317,7 @@ struct wmi_init_cmd {
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5)
|
||||||
|
+#define WMI_RSRC_CFG_FLAG2_CALC_NEXT_DTIM_COUNT_SET BIT(9)
|
||||||
|
#define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18)
|
||||||
|
|
||||||
|
#define WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT 4
|
||||||
|
@@ -2389,6 +2390,9 @@ struct wmi_resource_config {
|
||||||
|
u32 msdu_flow_override_config1;
|
||||||
|
u32 flags2;
|
||||||
|
u32 host_service_flags;
|
||||||
|
+ u32 max_rnr_neighbours;
|
||||||
|
+ u32 ema_max_vap_cnt;
|
||||||
|
+ u32 ema_max_profile_period;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_service_ready_event {
|
||||||
|
@@ -5646,6 +5650,8 @@ struct target_resource_config {
|
||||||
|
u32 twt_ap_pdev_count;
|
||||||
|
u32 twt_ap_sta_count;
|
||||||
|
u8 is_reg_cc_ext_event_supported;
|
||||||
|
+ u32 ema_max_vap_cnt;
|
||||||
|
+ u32 ema_max_profile_period;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wmi_debug_log_param {
|
|
@ -0,0 +1,215 @@
|
||||||
|
From 5a81610acf66c4ad6e1a1fbd09f3f555fca863b1 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Date: Fri, 5 May 2023 16:11:27 +0300
|
||||||
|
Subject: [PATCH 72/77] wifi: ath11k: MBSSID configuration during vdev
|
||||||
|
create/start
|
||||||
|
|
||||||
|
Configure multiple BSSID flags and index of the transmitting interface
|
||||||
|
in vdev create/start commands depending on the service bit
|
||||||
|
WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT.
|
||||||
|
|
||||||
|
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
||||||
|
|
||||||
|
Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Co-developed-by: John Crispin <john@phrozen.org>
|
||||||
|
Signed-off-by: John Crispin <john@phrozen.org>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230405221648.17950-3-quic_alokad@quicinc.com
|
||||||
|
---
|
||||||
|
drivers/net/wireless/ath/ath11k/mac.c | 70 +++++++++++++++++++++++++--
|
||||||
|
drivers/net/wireless/ath/ath11k/wmi.c | 5 ++
|
||||||
|
drivers/net/wireless/ath/ath11k/wmi.h | 19 ++++++++
|
||||||
|
3 files changed, 90 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
@@ -6181,17 +6181,62 @@ static void ath11k_mac_op_stop(struct ie
|
||||||
|
atomic_set(&ar->num_pending_mgmt_tx, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static void
|
||||||
|
-ath11k_mac_setup_vdev_create_params(struct ath11k_vif *arvif,
|
||||||
|
- struct vdev_create_params *params)
|
||||||
|
+static int ath11k_mac_setup_vdev_params_mbssid(struct ath11k_vif *arvif,
|
||||||
|
+ u32 *flags, u32 *tx_vdev_id)
|
||||||
|
+{
|
||||||
|
+ struct ath11k *ar = arvif->ar;
|
||||||
|
+ struct ath11k_vif *tx_arvif;
|
||||||
|
+ struct ieee80211_vif *tx_vif;
|
||||||
|
+
|
||||||
|
+ *tx_vdev_id = 0;
|
||||||
|
+ tx_vif = arvif->vif->mbssid_tx_vif;
|
||||||
|
+ if (!tx_vif) {
|
||||||
|
+ *flags = WMI_HOST_VDEV_FLAGS_NON_MBSSID_AP;
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ tx_arvif = (void *)tx_vif->drv_priv;
|
||||||
|
+
|
||||||
|
+ if (arvif->vif->bss_conf.nontransmitted) {
|
||||||
|
+ if (ar->hw->wiphy != ieee80211_vif_to_wdev(tx_vif)->wiphy)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ *flags = WMI_HOST_VDEV_FLAGS_NON_TRANSMIT_AP;
|
||||||
|
+ *tx_vdev_id = ath11k_vif_to_arvif(tx_vif)->vdev_id;
|
||||||
|
+ } else if (tx_arvif == arvif) {
|
||||||
|
+ *flags = WMI_HOST_VDEV_FLAGS_TRANSMIT_AP;
|
||||||
|
+ } else {
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (arvif->vif->bss_conf.ema_ap)
|
||||||
|
+ *flags |= WMI_HOST_VDEV_FLAGS_EMA_MODE;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ath11k_mac_setup_vdev_create_params(struct ath11k_vif *arvif,
|
||||||
|
+ struct vdev_create_params *params)
|
||||||
|
{
|
||||||
|
struct ath11k *ar = arvif->ar;
|
||||||
|
struct ath11k_pdev *pdev = ar->pdev;
|
||||||
|
+ int ret;
|
||||||
|
|
||||||
|
params->if_id = arvif->vdev_id;
|
||||||
|
params->type = arvif->vdev_type;
|
||||||
|
params->subtype = arvif->vdev_subtype;
|
||||||
|
params->pdev_id = pdev->pdev_id;
|
||||||
|
+ params->mbssid_flags = 0;
|
||||||
|
+ params->mbssid_tx_vdev_id = 0;
|
||||||
|
+
|
||||||
|
+ if (!test_bit(WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT,
|
||||||
|
+ ar->ab->wmi_ab.svc_map)) {
|
||||||
|
+ ret = ath11k_mac_setup_vdev_params_mbssid(arvif,
|
||||||
|
+ ¶ms->mbssid_flags,
|
||||||
|
+ ¶ms->mbssid_tx_vdev_id);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) {
|
||||||
|
params->chains[NL80211_BAND_2GHZ].tx = ar->num_tx_chains;
|
||||||
|
@@ -6206,6 +6251,7 @@ ath11k_mac_setup_vdev_create_params(stru
|
||||||
|
params->chains[NL80211_BAND_6GHZ].tx = ar->num_tx_chains;
|
||||||
|
params->chains[NL80211_BAND_6GHZ].rx = ar->num_rx_chains;
|
||||||
|
}
|
||||||
|
+ return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
|
||||||
|
@@ -6500,7 +6546,12 @@ static int ath11k_mac_op_add_interface(s
|
||||||
|
for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++)
|
||||||
|
vif->hw_queue[i] = i % (ATH11K_HW_MAX_QUEUES - 1);
|
||||||
|
|
||||||
|
- ath11k_mac_setup_vdev_create_params(arvif, &vdev_param);
|
||||||
|
+ ret = ath11k_mac_setup_vdev_create_params(arvif, &vdev_param);
|
||||||
|
+ if (ret) {
|
||||||
|
+ ath11k_warn(ab, "failed to create vdev parameters %d: %d\n",
|
||||||
|
+ arvif->vdev_id, ret);
|
||||||
|
+ goto err;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
ret = ath11k_wmi_vdev_create(ar, vif->addr, &vdev_param);
|
||||||
|
if (ret) {
|
||||||
|
@@ -6905,6 +6956,17 @@ ath11k_mac_vdev_start_restart(struct ath
|
||||||
|
arg.pref_tx_streams = ar->num_tx_chains;
|
||||||
|
arg.pref_rx_streams = ar->num_rx_chains;
|
||||||
|
|
||||||
|
+ arg.mbssid_flags = 0;
|
||||||
|
+ arg.mbssid_tx_vdev_id = 0;
|
||||||
|
+ if (test_bit(WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT,
|
||||||
|
+ ar->ab->wmi_ab.svc_map)) {
|
||||||
|
+ ret = ath11k_mac_setup_vdev_params_mbssid(arvif,
|
||||||
|
+ &arg.mbssid_flags,
|
||||||
|
+ &arg.mbssid_tx_vdev_id);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
||||||
|
arg.ssid = arvif->u.ap.ssid;
|
||||||
|
arg.ssid_len = arvif->u.ap.ssid_len;
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
|
@@ -724,6 +724,9 @@ int ath11k_wmi_vdev_create(struct ath11k
|
||||||
|
cmd->vdev_subtype = param->subtype;
|
||||||
|
cmd->num_cfg_txrx_streams = WMI_NUM_SUPPORTED_BAND_MAX;
|
||||||
|
cmd->pdev_id = param->pdev_id;
|
||||||
|
+ cmd->mbssid_flags = param->mbssid_flags;
|
||||||
|
+ cmd->mbssid_tx_vdev_id = param->mbssid_tx_vdev_id;
|
||||||
|
+
|
||||||
|
ether_addr_copy(cmd->vdev_macaddr.addr, macaddr);
|
||||||
|
|
||||||
|
ptr = skb->data + sizeof(*cmd);
|
||||||
|
@@ -941,6 +944,8 @@ int ath11k_wmi_vdev_start(struct ath11k
|
||||||
|
cmd->cac_duration_ms = arg->cac_duration_ms;
|
||||||
|
cmd->regdomain = arg->regdomain;
|
||||||
|
cmd->he_ops = arg->he_ops;
|
||||||
|
+ cmd->mbssid_flags = arg->mbssid_flags;
|
||||||
|
+ cmd->mbssid_tx_vdev_id = arg->mbssid_tx_vdev_id;
|
||||||
|
|
||||||
|
if (!restart) {
|
||||||
|
if (arg->ssid) {
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/wmi.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
|
||||||
|
@@ -137,6 +137,14 @@ enum {
|
||||||
|
WMI_AUTORATE_3200NS_GI = BIT(11),
|
||||||
|
};
|
||||||
|
|
||||||
|
+enum {
|
||||||
|
+ WMI_HOST_VDEV_FLAGS_NON_MBSSID_AP = 0x00000001,
|
||||||
|
+ WMI_HOST_VDEV_FLAGS_TRANSMIT_AP = 0x00000002,
|
||||||
|
+ WMI_HOST_VDEV_FLAGS_NON_TRANSMIT_AP = 0x00000004,
|
||||||
|
+ WMI_HOST_VDEV_FLAGS_EMA_MODE = 0x00000008,
|
||||||
|
+ WMI_HOST_VDEV_FLAGS_SCAN_MODE_VAP = 0x00000010,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* wmi command groups.
|
||||||
|
*/
|
||||||
|
@@ -2096,6 +2104,7 @@ enum wmi_tlv_service {
|
||||||
|
WMI_TLV_SERVICE_EXT2_MSG = 220,
|
||||||
|
WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT = 246,
|
||||||
|
WMI_TLV_SERVICE_SRG_SRP_SPATIAL_REUSE_SUPPORT = 249,
|
||||||
|
+ WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT = 253,
|
||||||
|
WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE = 263,
|
||||||
|
|
||||||
|
/* The second 128 bits */
|
||||||
|
@@ -2583,6 +2592,8 @@ struct vdev_create_params {
|
||||||
|
u8 rx;
|
||||||
|
} chains[NUM_NL80211_BANDS];
|
||||||
|
u32 pdev_id;
|
||||||
|
+ u32 mbssid_flags;
|
||||||
|
+ u32 mbssid_tx_vdev_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wmi_vdev_create_cmd {
|
||||||
|
@@ -2593,6 +2604,8 @@ struct wmi_vdev_create_cmd {
|
||||||
|
struct wmi_mac_addr vdev_macaddr;
|
||||||
|
u32 num_cfg_txrx_streams;
|
||||||
|
u32 pdev_id;
|
||||||
|
+ u32 mbssid_flags;
|
||||||
|
+ u32 mbssid_tx_vdev_id;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_vdev_txrx_streams {
|
||||||
|
@@ -2656,6 +2669,9 @@ struct wmi_vdev_start_request_cmd {
|
||||||
|
u32 he_ops;
|
||||||
|
u32 cac_duration_ms;
|
||||||
|
u32 regdomain;
|
||||||
|
+ u32 min_data_rate;
|
||||||
|
+ u32 mbssid_flags;
|
||||||
|
+ u32 mbssid_tx_vdev_id;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define MGMT_TX_DL_FRM_LEN 64
|
||||||
|
@@ -2825,6 +2841,9 @@ struct wmi_vdev_start_req_arg {
|
||||||
|
u32 pref_rx_streams;
|
||||||
|
u32 pref_tx_streams;
|
||||||
|
u32 num_noa_descriptors;
|
||||||
|
+ u32 min_data_rate;
|
||||||
|
+ u32 mbssid_flags;
|
||||||
|
+ u32 mbssid_tx_vdev_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct peer_create_params {
|
|
@ -0,0 +1,52 @@
|
||||||
|
From cf604e72bc6e6db68c7fcaa8779b03ec14b8d2fa Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Date: Fri, 5 May 2023 16:11:27 +0300
|
||||||
|
Subject: [PATCH 73/77] wifi: ath11k: rename MBSSID fields in wmi_vdev_up_cmd
|
||||||
|
|
||||||
|
Rename trans_bssid to tx_vdev_bssid to make it similar to vdev_bssid.
|
||||||
|
|
||||||
|
Rename profile_num to nontx_profile_cnt, and profile_idx to
|
||||||
|
nontx_profile_idx which makes it clear that these store configurations
|
||||||
|
related to MBSSID non-transmitting profiles.
|
||||||
|
|
||||||
|
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
||||||
|
|
||||||
|
Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230405221648.17950-4-quic_alokad@quicinc.com
|
||||||
|
---
|
||||||
|
drivers/net/wireless/ath/ath11k/wmi.c | 6 +++---
|
||||||
|
drivers/net/wireless/ath/ath11k/wmi.h | 6 +++---
|
||||||
|
2 files changed, 6 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
|
@@ -1029,10 +1029,10 @@ int ath11k_wmi_vdev_up(struct ath11k *ar
|
||||||
|
bss_conf = &arvif->vif->bss_conf;
|
||||||
|
|
||||||
|
if (bss_conf->nontransmitted) {
|
||||||
|
- ether_addr_copy(cmd->trans_bssid.addr,
|
||||||
|
+ ether_addr_copy(cmd->tx_vdev_bssid.addr,
|
||||||
|
bss_conf->transmitter_bssid);
|
||||||
|
- cmd->profile_idx = bss_conf->bssid_index;
|
||||||
|
- cmd->profile_num = bss_conf->bssid_indicator;
|
||||||
|
+ cmd->nontx_profile_idx = bss_conf->bssid_index;
|
||||||
|
+ cmd->nontx_profile_cnt = bss_conf->bssid_indicator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/wmi.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
|
||||||
|
@@ -2625,9 +2625,9 @@ struct wmi_vdev_up_cmd {
|
||||||
|
u32 vdev_id;
|
||||||
|
u32 vdev_assoc_id;
|
||||||
|
struct wmi_mac_addr vdev_bssid;
|
||||||
|
- struct wmi_mac_addr trans_bssid;
|
||||||
|
- u32 profile_idx;
|
||||||
|
- u32 profile_num;
|
||||||
|
+ struct wmi_mac_addr tx_vdev_bssid;
|
||||||
|
+ u32 nontx_profile_idx;
|
||||||
|
+ u32 nontx_profile_cnt;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_vdev_stop_cmd {
|
|
@ -0,0 +1,138 @@
|
||||||
|
From c82dc33f252fd8883be66f2d0230af0fd734c683 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Date: Fri, 5 May 2023 16:11:27 +0300
|
||||||
|
Subject: [PATCH 74/77] wifi: ath11k: MBSSID parameter configuration in AP mode
|
||||||
|
|
||||||
|
Include MBSSID parameters in WMI vdev up operation.
|
||||||
|
|
||||||
|
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
||||||
|
|
||||||
|
Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Co-developed-by: John Crispin <john@phrozen.org>
|
||||||
|
Signed-off-by: John Crispin <john@phrozen.org>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230405221648.17950-5-quic_alokad@quicinc.com
|
||||||
|
---
|
||||||
|
drivers/net/wireless/ath/ath11k/mac.c | 29 +++++++++++++++++++++------
|
||||||
|
drivers/net/wireless/ath/ath11k/wmi.c | 8 +++++++-
|
||||||
|
drivers/net/wireless/ath/ath11k/wmi.h | 3 ++-
|
||||||
|
3 files changed, 32 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
@@ -964,7 +964,7 @@ static int ath11k_mac_monitor_vdev_start
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
- ret = ath11k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr);
|
||||||
|
+ ret = ath11k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr, NULL, 0, 0);
|
||||||
|
if (ret) {
|
||||||
|
ath11k_warn(ar->ab, "failed to put up monitor vdev %i: %d\n",
|
||||||
|
vdev_id, ret);
|
||||||
|
@@ -1423,6 +1423,7 @@ static void ath11k_control_beaconing(str
|
||||||
|
struct ieee80211_bss_conf *info)
|
||||||
|
{
|
||||||
|
struct ath11k *ar = arvif->ar;
|
||||||
|
+ struct ath11k_vif *tx_arvif = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
lockdep_assert_held(&arvif->ar->conf_mutex);
|
||||||
|
@@ -1451,8 +1452,14 @@ static void ath11k_control_beaconing(str
|
||||||
|
|
||||||
|
ether_addr_copy(arvif->bssid, info->bssid);
|
||||||
|
|
||||||
|
+ if (arvif->vif->mbssid_tx_vif)
|
||||||
|
+ tx_arvif = (struct ath11k_vif *)arvif->vif->mbssid_tx_vif->drv_priv;
|
||||||
|
+
|
||||||
|
ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
|
||||||
|
- arvif->bssid);
|
||||||
|
+ arvif->bssid,
|
||||||
|
+ tx_arvif ? tx_arvif->bssid : NULL,
|
||||||
|
+ info->bssid_index,
|
||||||
|
+ 1 << info->bssid_indicator);
|
||||||
|
if (ret) {
|
||||||
|
ath11k_warn(ar->ab, "failed to bring up vdev %d: %i\n",
|
||||||
|
arvif->vdev_id, ret);
|
||||||
|
@@ -2879,7 +2886,8 @@ static void ath11k_bss_assoc(struct ieee
|
||||||
|
arvif->aid = vif->cfg.aid;
|
||||||
|
ether_addr_copy(arvif->bssid, bss_conf->bssid);
|
||||||
|
|
||||||
|
- ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
|
||||||
|
+ ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid,
|
||||||
|
+ NULL, 0, 0);
|
||||||
|
if (ret) {
|
||||||
|
ath11k_warn(ar->ab, "failed to set vdev %d up: %d\n",
|
||||||
|
arvif->vdev_id, ret);
|
||||||
|
@@ -7133,7 +7141,8 @@ ath11k_mac_update_vif_chan(struct ath11k
|
||||||
|
int n_vifs)
|
||||||
|
{
|
||||||
|
struct ath11k_base *ab = ar->ab;
|
||||||
|
- struct ath11k_vif *arvif;
|
||||||
|
+ struct ath11k_vif *arvif, *tx_arvif = NULL;
|
||||||
|
+ struct ieee80211_vif *mbssid_tx_vif;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
bool monitor_vif = false;
|
||||||
|
@@ -7187,8 +7196,15 @@ ath11k_mac_update_vif_chan(struct ath11k
|
||||||
|
ath11k_warn(ab, "failed to update bcn tmpl during csa: %d\n",
|
||||||
|
ret);
|
||||||
|
|
||||||
|
+ mbssid_tx_vif = arvif->vif->mbssid_tx_vif;
|
||||||
|
+ if (mbssid_tx_vif)
|
||||||
|
+ tx_arvif = (struct ath11k_vif *)mbssid_tx_vif->drv_priv;
|
||||||
|
+
|
||||||
|
ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
|
||||||
|
- arvif->bssid);
|
||||||
|
+ arvif->bssid,
|
||||||
|
+ tx_arvif ? tx_arvif->bssid : NULL,
|
||||||
|
+ arvif->vif->bss_conf.bssid_index,
|
||||||
|
+ 1 << arvif->vif->bss_conf.bssid_indicator);
|
||||||
|
if (ret) {
|
||||||
|
ath11k_warn(ab, "failed to bring vdev up %d: %d\n",
|
||||||
|
arvif->vdev_id, ret);
|
||||||
|
@@ -7306,7 +7322,8 @@ static int ath11k_start_vdev_delay(struc
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
|
||||||
|
- ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, 0, ar->mac_addr);
|
||||||
|
+ ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, 0, ar->mac_addr,
|
||||||
|
+ NULL, 0, 0);
|
||||||
|
if (ret) {
|
||||||
|
ath11k_warn(ab, "failed put monitor up: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
|
@@ -1001,7 +1001,8 @@ int ath11k_wmi_vdev_start(struct ath11k
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
-int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
|
||||||
|
+int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid,
|
||||||
|
+ u8 *tx_bssid, u32 nontx_profile_idx, u32 nontx_profile_cnt)
|
||||||
|
{
|
||||||
|
struct ath11k_pdev_wmi *wmi = ar->wmi;
|
||||||
|
struct wmi_vdev_up_cmd *cmd;
|
||||||
|
@@ -1025,6 +1026,11 @@ int ath11k_wmi_vdev_up(struct ath11k *ar
|
||||||
|
|
||||||
|
ether_addr_copy(cmd->vdev_bssid.addr, bssid);
|
||||||
|
|
||||||
|
+ cmd->nontx_profile_idx = nontx_profile_idx;
|
||||||
|
+ cmd->nontx_profile_cnt = nontx_profile_cnt;
|
||||||
|
+ if (tx_bssid)
|
||||||
|
+ ether_addr_copy(cmd->tx_vdev_bssid.addr, tx_bssid);
|
||||||
|
+
|
||||||
|
if (arvif && arvif->vif->type == NL80211_IFTYPE_STATION) {
|
||||||
|
bss_conf = &arvif->vif->bss_conf;
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/wmi.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
|
||||||
|
@@ -6301,7 +6301,8 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *a
|
||||||
|
struct sk_buff *bcn);
|
||||||
|
int ath11k_wmi_vdev_down(struct ath11k *ar, u8 vdev_id);
|
||||||
|
int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid,
|
||||||
|
- const u8 *bssid);
|
||||||
|
+ const u8 *bssid, u8 *tx_bssid, u32 nontx_profile_idx,
|
||||||
|
+ u32 nontx_profile_cnt);
|
||||||
|
int ath11k_wmi_vdev_stop(struct ath11k *ar, u8 vdev_id);
|
||||||
|
int ath11k_wmi_vdev_start(struct ath11k *ar, struct wmi_vdev_start_req_arg *arg,
|
||||||
|
bool restart);
|
|
@ -0,0 +1,86 @@
|
||||||
|
From cb9bea773c85e372931cd7a177db4165adf29d95 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Date: Fri, 5 May 2023 16:11:28 +0300
|
||||||
|
Subject: [PATCH 75/77] wifi: ath11k: refactor vif parameter configurations
|
||||||
|
|
||||||
|
Security parameters for each non-transmitting profile can be
|
||||||
|
different when MBSSID is enabled and this information is included
|
||||||
|
in the MBSSID element in the Beacon frame. Current implementation
|
||||||
|
to set rsnie_present and wpaie_present does not parse this element
|
||||||
|
hence it applies only to the transmitting interface.
|
||||||
|
|
||||||
|
Move the code to a separate function to make additions for
|
||||||
|
non-transmitting interfaces cleaner.
|
||||||
|
|
||||||
|
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
||||||
|
|
||||||
|
Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230405221648.17950-6-quic_alokad@quicinc.com
|
||||||
|
---
|
||||||
|
drivers/net/wireless/ath/ath11k/mac.c | 41 ++++++++++++++++-----------
|
||||||
|
1 file changed, 24 insertions(+), 17 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
@@ -1351,28 +1351,14 @@ err_mon_del:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif)
|
||||||
|
+static void ath11k_mac_set_vif_params(struct ath11k_vif *arvif,
|
||||||
|
+ struct sk_buff *bcn)
|
||||||
|
{
|
||||||
|
- struct ath11k *ar = arvif->ar;
|
||||||
|
- struct ath11k_base *ab = ar->ab;
|
||||||
|
- struct ieee80211_hw *hw = ar->hw;
|
||||||
|
- struct ieee80211_vif *vif = arvif->vif;
|
||||||
|
- struct ieee80211_mutable_offsets offs = {};
|
||||||
|
- struct sk_buff *bcn;
|
||||||
|
struct ieee80211_mgmt *mgmt;
|
||||||
|
u8 *ies;
|
||||||
|
- int ret;
|
||||||
|
-
|
||||||
|
- if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
|
||||||
|
- return 0;
|
||||||
|
-
|
||||||
|
- bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0);
|
||||||
|
- if (!bcn) {
|
||||||
|
- ath11k_warn(ab, "failed to get beacon template from mac80211\n");
|
||||||
|
- return -EPERM;
|
||||||
|
- }
|
||||||
|
|
||||||
|
ies = bcn->data + ieee80211_get_hdrlen_from_skb(bcn);
|
||||||
|
+ mgmt = (struct ieee80211_mgmt *)bcn->data;
|
||||||
|
ies += sizeof(mgmt->u.beacon);
|
||||||
|
|
||||||
|
if (cfg80211_find_ie(WLAN_EID_RSN, ies, (skb_tail_pointer(bcn) - ies)))
|
||||||
|
@@ -1386,7 +1372,28 @@ static int ath11k_mac_setup_bcn_tmpl(str
|
||||||
|
arvif->wpaie_present = true;
|
||||||
|
else
|
||||||
|
arvif->wpaie_present = false;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif)
|
||||||
|
+{
|
||||||
|
+ struct ath11k *ar = arvif->ar;
|
||||||
|
+ struct ath11k_base *ab = ar->ab;
|
||||||
|
+ struct ieee80211_hw *hw = ar->hw;
|
||||||
|
+ struct ieee80211_vif *vif = arvif->vif;
|
||||||
|
+ struct ieee80211_mutable_offsets offs = {};
|
||||||
|
+ struct sk_buff *bcn;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0);
|
||||||
|
+ if (!bcn) {
|
||||||
|
+ ath11k_warn(ab, "failed to get beacon template from mac80211\n");
|
||||||
|
+ return -EPERM;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
+ ath11k_mac_set_vif_params(arvif, bcn);
|
||||||
|
ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn);
|
||||||
|
|
||||||
|
kfree_skb(bcn);
|
|
@ -0,0 +1,190 @@
|
||||||
|
From 335a92765d308dfe22826f5562cd4b4389b45e71 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Date: Fri, 5 May 2023 16:11:28 +0300
|
||||||
|
Subject: [PATCH 76/77] wifi: ath11k: MBSSID beacon support
|
||||||
|
|
||||||
|
- Split ath11k_mac_setup_bcn_tmpl() to move the beacon retrieval and
|
||||||
|
WMI command to a new function, ath11k_mac_setup_bcn_tmpl_legacy().
|
||||||
|
In the original function add checks to use the transmitting interface
|
||||||
|
when MBSSID is enabled.
|
||||||
|
- Set rsnie_present and wpaie_present fields for the non-transmitting
|
||||||
|
interfaces when MBSSID is enabled.
|
||||||
|
|
||||||
|
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
||||||
|
|
||||||
|
Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Co-developed-by: John Crispin <john@phrozen.org>
|
||||||
|
Signed-off-by: John Crispin <john@phrozen.org>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230405221648.17950-7-quic_alokad@quicinc.com
|
||||||
|
---
|
||||||
|
drivers/net/wireless/ath/ath11k/mac.c | 116 ++++++++++++++++++++++++--
|
||||||
|
drivers/net/wireless/ath/ath11k/wmi.c | 1 +
|
||||||
|
2 files changed, 112 insertions(+), 5 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
@@ -1351,6 +1351,84 @@ err_mon_del:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void ath11k_mac_setup_nontx_vif_rsnie(struct ath11k_vif *arvif,
|
||||||
|
+ bool tx_arvif_rsnie_present,
|
||||||
|
+ const u8 *profile, u8 profile_len)
|
||||||
|
+{
|
||||||
|
+ if (cfg80211_find_ie(WLAN_EID_RSN, profile, profile_len)) {
|
||||||
|
+ arvif->rsnie_present = true;
|
||||||
|
+ } else if (tx_arvif_rsnie_present) {
|
||||||
|
+ int i;
|
||||||
|
+ u8 nie_len;
|
||||||
|
+ const u8 *nie = cfg80211_find_ext_ie(WLAN_EID_EXT_NON_INHERITANCE,
|
||||||
|
+ profile, profile_len);
|
||||||
|
+ if (!nie)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ nie_len = nie[1];
|
||||||
|
+ nie += 2;
|
||||||
|
+ for (i = 0; i < nie_len; i++) {
|
||||||
|
+ if (nie[i] == WLAN_EID_RSN) {
|
||||||
|
+ arvif->rsnie_present = false;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static bool ath11k_mac_set_nontx_vif_params(struct ath11k_vif *tx_arvif,
|
||||||
|
+ struct ath11k_vif *arvif,
|
||||||
|
+ struct sk_buff *bcn)
|
||||||
|
+{
|
||||||
|
+ struct ieee80211_mgmt *mgmt;
|
||||||
|
+ const u8 *ies, *profile, *next_profile;
|
||||||
|
+ int ies_len;
|
||||||
|
+
|
||||||
|
+ ies = bcn->data + ieee80211_get_hdrlen_from_skb(bcn);
|
||||||
|
+ mgmt = (struct ieee80211_mgmt *)bcn->data;
|
||||||
|
+ ies += sizeof(mgmt->u.beacon);
|
||||||
|
+ ies_len = skb_tail_pointer(bcn) - ies;
|
||||||
|
+
|
||||||
|
+ ies = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ies, ies_len);
|
||||||
|
+ arvif->rsnie_present = tx_arvif->rsnie_present;
|
||||||
|
+
|
||||||
|
+ while (ies) {
|
||||||
|
+ u8 mbssid_len;
|
||||||
|
+
|
||||||
|
+ ies_len -= (2 + ies[1]);
|
||||||
|
+ mbssid_len = ies[1] - 1;
|
||||||
|
+ profile = &ies[3];
|
||||||
|
+
|
||||||
|
+ while (mbssid_len) {
|
||||||
|
+ u8 profile_len;
|
||||||
|
+
|
||||||
|
+ profile_len = profile[1];
|
||||||
|
+ next_profile = profile + (2 + profile_len);
|
||||||
|
+ mbssid_len -= (2 + profile_len);
|
||||||
|
+
|
||||||
|
+ profile += 2;
|
||||||
|
+ profile_len -= (2 + profile[1]);
|
||||||
|
+ profile += (2 + profile[1]); /* nontx capabilities */
|
||||||
|
+ profile_len -= (2 + profile[1]);
|
||||||
|
+ profile += (2 + profile[1]); /* SSID */
|
||||||
|
+ if (profile[2] == arvif->vif->bss_conf.bssid_index) {
|
||||||
|
+ profile_len -= 5;
|
||||||
|
+ profile = profile + 5;
|
||||||
|
+ ath11k_mac_setup_nontx_vif_rsnie(arvif,
|
||||||
|
+ tx_arvif->rsnie_present,
|
||||||
|
+ profile,
|
||||||
|
+ profile_len);
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+ profile = next_profile;
|
||||||
|
+ }
|
||||||
|
+ ies = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, profile,
|
||||||
|
+ ies_len);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return false;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void ath11k_mac_set_vif_params(struct ath11k_vif *arvif,
|
||||||
|
struct sk_buff *bcn)
|
||||||
|
{
|
||||||
|
@@ -1374,18 +1452,26 @@ static void ath11k_mac_set_vif_params(st
|
||||||
|
arvif->wpaie_present = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif)
|
||||||
|
+static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif)
|
||||||
|
{
|
||||||
|
struct ath11k *ar = arvif->ar;
|
||||||
|
struct ath11k_base *ab = ar->ab;
|
||||||
|
+ struct ath11k_vif *tx_arvif = arvif;
|
||||||
|
struct ieee80211_hw *hw = ar->hw;
|
||||||
|
struct ieee80211_vif *vif = arvif->vif;
|
||||||
|
struct ieee80211_mutable_offsets offs = {};
|
||||||
|
struct sk_buff *bcn;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
- if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
|
||||||
|
- return 0;
|
||||||
|
+ if (arvif->vif->mbssid_tx_vif) {
|
||||||
|
+ tx_arvif = (void *)arvif->vif->mbssid_tx_vif->drv_priv;
|
||||||
|
+ if (tx_arvif != arvif) {
|
||||||
|
+ ar = tx_arvif->ar;
|
||||||
|
+ ab = ar->ab;
|
||||||
|
+ hw = ar->hw;
|
||||||
|
+ vif = tx_arvif->vif;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
|
||||||
|
bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0);
|
||||||
|
if (!bcn) {
|
||||||
|
@@ -1393,9 +1479,12 @@ static int ath11k_mac_setup_bcn_tmpl(str
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
- ath11k_mac_set_vif_params(arvif, bcn);
|
||||||
|
- ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn);
|
||||||
|
+ if (tx_arvif == arvif)
|
||||||
|
+ ath11k_mac_set_vif_params(tx_arvif, bcn);
|
||||||
|
+ else if (!ath11k_mac_set_nontx_vif_params(tx_arvif, arvif, bcn))
|
||||||
|
+ return -EINVAL;
|
||||||
|
|
||||||
|
+ ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn);
|
||||||
|
kfree_skb(bcn);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
@@ -1405,6 +1494,23 @@ static int ath11k_mac_setup_bcn_tmpl(str
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif)
|
||||||
|
+{
|
||||||
|
+ struct ieee80211_vif *vif = arvif->vif;
|
||||||
|
+
|
||||||
|
+ if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ /* Target does not expect beacon templates for the already up
|
||||||
|
+ * non-transmitting interfaces, and results in a crash if sent.
|
||||||
|
+ */
|
||||||
|
+ if (vif->mbssid_tx_vif &&
|
||||||
|
+ arvif != (void *)vif->mbssid_tx_vif->drv_priv && arvif->is_up)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ return ath11k_mac_setup_bcn_tmpl_mbssid(arvif);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif)
|
||||||
|
{
|
||||||
|
struct ieee80211_vif *vif = arvif->vif;
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
|
@@ -1737,6 +1737,7 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *a
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd->buf_len = bcn->len;
|
||||||
|
+ cmd->mbssid_ie_offset = offs->mbssid_off;
|
||||||
|
|
||||||
|
ptr = skb->data + sizeof(*cmd);
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
From 87bd401138161008fdb82fbca6e213af117bfeb9 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Date: Fri, 5 May 2023 16:11:28 +0300
|
||||||
|
Subject: [PATCH 77/77] wifi: ath11k: EMA beacon support
|
||||||
|
|
||||||
|
Add new function ath11k_mac_setup_bcn_tmpl_ema() which invokes the new
|
||||||
|
API provided by MAC80211 to retrieve EMA beacons.
|
||||||
|
|
||||||
|
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
||||||
|
|
||||||
|
Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Co-developed-by: John Crispin <john@phrozen.org>
|
||||||
|
Signed-off-by: John Crispin <john@phrozen.org>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230405221648.17950-8-quic_alokad@quicinc.com
|
||||||
|
---
|
||||||
|
drivers/net/wireless/ath/ath11k/mac.c | 59 ++++++++++++++++++++++++++-
|
||||||
|
drivers/net/wireless/ath/ath11k/wmi.c | 3 +-
|
||||||
|
drivers/net/wireless/ath/ath11k/wmi.h | 11 ++++-
|
||||||
|
3 files changed, 70 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
@@ -1452,6 +1452,60 @@ static void ath11k_mac_set_vif_params(st
|
||||||
|
arvif->wpaie_present = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif)
|
||||||
|
+{
|
||||||
|
+ struct ath11k_vif *tx_arvif;
|
||||||
|
+ struct ieee80211_ema_beacons *beacons;
|
||||||
|
+ int ret = 0;
|
||||||
|
+ bool nontx_vif_params_set = false;
|
||||||
|
+ u32 params = 0;
|
||||||
|
+ u8 i = 0;
|
||||||
|
+
|
||||||
|
+ tx_arvif = (void *)arvif->vif->mbssid_tx_vif->drv_priv;
|
||||||
|
+
|
||||||
|
+ beacons = ieee80211_beacon_get_template_ema_list(tx_arvif->ar->hw,
|
||||||
|
+ tx_arvif->vif, 0);
|
||||||
|
+ if (!beacons || !beacons->cnt) {
|
||||||
|
+ ath11k_warn(arvif->ar->ab,
|
||||||
|
+ "failed to get ema beacon templates from mac80211\n");
|
||||||
|
+ return -EPERM;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (tx_arvif == arvif)
|
||||||
|
+ ath11k_mac_set_vif_params(tx_arvif, beacons->bcn[0].skb);
|
||||||
|
+ else
|
||||||
|
+ arvif->wpaie_present = tx_arvif->wpaie_present;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < beacons->cnt; i++) {
|
||||||
|
+ if (tx_arvif != arvif && !nontx_vif_params_set)
|
||||||
|
+ nontx_vif_params_set =
|
||||||
|
+ ath11k_mac_set_nontx_vif_params(tx_arvif, arvif,
|
||||||
|
+ beacons->bcn[i].skb);
|
||||||
|
+
|
||||||
|
+ params = beacons->cnt;
|
||||||
|
+ params |= (i << WMI_EMA_TMPL_IDX_SHIFT);
|
||||||
|
+ params |= ((!i ? 1 : 0) << WMI_EMA_FIRST_TMPL_SHIFT);
|
||||||
|
+ params |= ((i + 1 == beacons->cnt ? 1 : 0) << WMI_EMA_LAST_TMPL_SHIFT);
|
||||||
|
+
|
||||||
|
+ ret = ath11k_wmi_bcn_tmpl(tx_arvif->ar, tx_arvif->vdev_id,
|
||||||
|
+ &beacons->bcn[i].offs,
|
||||||
|
+ beacons->bcn[i].skb, params);
|
||||||
|
+ if (ret) {
|
||||||
|
+ ath11k_warn(tx_arvif->ar->ab,
|
||||||
|
+ "failed to set ema beacon template id %i error %d\n",
|
||||||
|
+ i, ret);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ieee80211_beacon_free_ema_list(beacons);
|
||||||
|
+
|
||||||
|
+ if (tx_arvif != arvif && !nontx_vif_params_set)
|
||||||
|
+ return -EINVAL; /* Profile not found in the beacons */
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif)
|
||||||
|
{
|
||||||
|
struct ath11k *ar = arvif->ar;
|
||||||
|
@@ -1484,7 +1538,7 @@ static int ath11k_mac_setup_bcn_tmpl_mbs
|
||||||
|
else if (!ath11k_mac_set_nontx_vif_params(tx_arvif, arvif, bcn))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
- ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn);
|
||||||
|
+ ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn, 0);
|
||||||
|
kfree_skb(bcn);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
@@ -1508,6 +1562,9 @@ static int ath11k_mac_setup_bcn_tmpl(str
|
||||||
|
arvif != (void *)vif->mbssid_tx_vif->drv_priv && arvif->is_up)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
+ if (vif->bss_conf.ema_ap && vif->mbssid_tx_vif)
|
||||||
|
+ return ath11k_mac_setup_bcn_tmpl_ema(arvif);
|
||||||
|
+
|
||||||
|
return ath11k_mac_setup_bcn_tmpl_mbssid(arvif);
|
||||||
|
}
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
|
@@ -1699,7 +1699,7 @@ int ath11k_wmi_send_bcn_offload_control_
|
||||||
|
|
||||||
|
int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id,
|
||||||
|
struct ieee80211_mutable_offsets *offs,
|
||||||
|
- struct sk_buff *bcn)
|
||||||
|
+ struct sk_buff *bcn, u32 ema_params)
|
||||||
|
{
|
||||||
|
struct ath11k_pdev_wmi *wmi = ar->wmi;
|
||||||
|
struct wmi_bcn_tmpl_cmd *cmd;
|
||||||
|
@@ -1738,6 +1738,7 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *a
|
||||||
|
|
||||||
|
cmd->buf_len = bcn->len;
|
||||||
|
cmd->mbssid_ie_offset = offs->mbssid_off;
|
||||||
|
+ cmd->ema_params = ema_params;
|
||||||
|
|
||||||
|
ptr = skb->data + sizeof(*cmd);
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/wmi.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
|
||||||
|
@@ -3566,6 +3566,10 @@ struct wmi_get_pdev_temperature_cmd {
|
||||||
|
|
||||||
|
#define WMI_BEACON_TX_BUFFER_SIZE 512
|
||||||
|
|
||||||
|
+#define WMI_EMA_TMPL_IDX_SHIFT 8
|
||||||
|
+#define WMI_EMA_FIRST_TMPL_SHIFT 16
|
||||||
|
+#define WMI_EMA_LAST_TMPL_SHIFT 24
|
||||||
|
+
|
||||||
|
struct wmi_bcn_tmpl_cmd {
|
||||||
|
u32 tlv_header;
|
||||||
|
u32 vdev_id;
|
||||||
|
@@ -3576,6 +3580,11 @@ struct wmi_bcn_tmpl_cmd {
|
||||||
|
u32 csa_event_bitmap;
|
||||||
|
u32 mbssid_ie_offset;
|
||||||
|
u32 esp_ie_offset;
|
||||||
|
+ u32 csc_switch_count_offset;
|
||||||
|
+ u32 csc_event_bitmap;
|
||||||
|
+ u32 mu_edca_ie_offset;
|
||||||
|
+ u32 feature_enable_bitmap;
|
||||||
|
+ u32 ema_params;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_key_seq_counter {
|
||||||
|
@@ -6298,7 +6307,7 @@ int ath11k_wmi_mgmt_send(struct ath11k *
|
||||||
|
struct sk_buff *frame);
|
||||||
|
int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id,
|
||||||
|
struct ieee80211_mutable_offsets *offs,
|
||||||
|
- struct sk_buff *bcn);
|
||||||
|
+ struct sk_buff *bcn, u32 ema_param);
|
||||||
|
int ath11k_wmi_vdev_down(struct ath11k *ar, u8 vdev_id);
|
||||||
|
int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid,
|
||||||
|
const u8 *bssid, u8 *tx_bssid, u32 nontx_profile_idx,
|
|
@ -0,0 +1,75 @@
|
||||||
|
From 570eec3d40505c30babbe3b8f85a38496c975ab2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Maharaja Kennadyrajan <quic_mkenna@quicinc.com>
|
||||||
|
Date: Tue, 9 May 2023 20:07:23 +0300
|
||||||
|
Subject: [PATCH] wifi: ath11k: Relocate the func
|
||||||
|
ath11k_mac_bitrate_mask_num_ht_rates() and change hweight16 to hweight8
|
||||||
|
|
||||||
|
Relocate the function ath11k_mac_bitrate_mask_num_ht_rates() definition
|
||||||
|
to call this function from other functions which helps to avoid the
|
||||||
|
compilation error (function not defined).
|
||||||
|
|
||||||
|
ht_mcs[] is 1 byte array and it is enough to use hweight8() instead
|
||||||
|
of hweight16(). Hence, fixed the same.
|
||||||
|
|
||||||
|
Tested on: Compile tested only.
|
||||||
|
|
||||||
|
Signed-off-by: Maharaja Kennadyrajan <quic_mkenna@quicinc.com>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230504092033.3542456-2-quic_mkenna@quicinc.com
|
||||||
|
---
|
||||||
|
drivers/net/wireless/ath/ath11k/mac.c | 30 +++++++++++++--------------
|
||||||
|
1 file changed, 15 insertions(+), 15 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||||
|
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <net/mac80211.h>
|
||||||
|
@@ -4338,6 +4338,20 @@ exit:
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
+ath11k_mac_bitrate_mask_num_ht_rates(struct ath11k *ar,
|
||||||
|
+ enum nl80211_band band,
|
||||||
|
+ const struct cfg80211_bitrate_mask *mask)
|
||||||
|
+{
|
||||||
|
+ int num_rates = 0;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++)
|
||||||
|
+ num_rates += hweight8(mask->control[band].ht_mcs[i]);
|
||||||
|
+
|
||||||
|
+ return num_rates;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
ath11k_mac_bitrate_mask_num_vht_rates(struct ath11k *ar,
|
||||||
|
enum nl80211_band band,
|
||||||
|
const struct cfg80211_bitrate_mask *mask)
|
||||||
|
@@ -7791,20 +7805,6 @@ static void ath11k_mac_op_flush(struct i
|
||||||
|
ath11k_mac_flush_tx_complete(ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int
|
||||||
|
-ath11k_mac_bitrate_mask_num_ht_rates(struct ath11k *ar,
|
||||||
|
- enum nl80211_band band,
|
||||||
|
- const struct cfg80211_bitrate_mask *mask)
|
||||||
|
-{
|
||||||
|
- int num_rates = 0;
|
||||||
|
- int i;
|
||||||
|
-
|
||||||
|
- for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++)
|
||||||
|
- num_rates += hweight16(mask->control[band].ht_mcs[i]);
|
||||||
|
-
|
||||||
|
- return num_rates;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static bool
|
||||||
|
ath11k_mac_has_single_legacy_rate(struct ath11k *ar,
|
||||||
|
enum nl80211_band band,
|
|
@ -0,0 +1,141 @@
|
||||||
|
From df8e3729ffc0aa645839693f74ee7b6d999cdf64 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Maharaja Kennadyrajan <quic_mkenna@quicinc.com>
|
||||||
|
Date: Tue, 9 May 2023 20:07:24 +0300
|
||||||
|
Subject: [PATCH] wifi: ath11k: Send HT fixed rate in WMI peer fixed param
|
||||||
|
|
||||||
|
Due to the firmware behavior with HT fixed rate setting,
|
||||||
|
HT fixed rate MCS with NSS > 1 are treated as NSS = 1
|
||||||
|
HT rates in the firmware and enables the HT fixed rate of
|
||||||
|
NSS = 1.
|
||||||
|
|
||||||
|
This leads to HT fixed rate is always configured for NSS = 1
|
||||||
|
even though the user sets NSS = 2 or > 1 HT fixed MCS in the
|
||||||
|
set bitrate command.
|
||||||
|
|
||||||
|
Currently HT fixed MCS is sent via WMI peer assoc command.
|
||||||
|
Fix this issue, by sending the HT fixed rate MCS in WMI peer
|
||||||
|
fixed param instead of sending in peer assoc command.
|
||||||
|
|
||||||
|
Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
||||||
|
|
||||||
|
Signed-off-by: Maharaja Kennadyrajan <quic_mkenna@quicinc.com>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230504092033.3542456-3-quic_mkenna@quicinc.com
|
||||||
|
---
|
||||||
|
drivers/net/wireless/ath/ath11k/mac.c | 63 ++++++++++++++++++++++++++-
|
||||||
|
1 file changed, 61 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
@@ -4480,6 +4480,54 @@ ath11k_mac_set_peer_he_fixed_rate(struct
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int
|
||||||
|
+ath11k_mac_set_peer_ht_fixed_rate(struct ath11k_vif *arvif,
|
||||||
|
+ struct ieee80211_sta *sta,
|
||||||
|
+ const struct cfg80211_bitrate_mask *mask,
|
||||||
|
+ enum nl80211_band band)
|
||||||
|
+{
|
||||||
|
+ struct ath11k *ar = arvif->ar;
|
||||||
|
+ u8 ht_rate, nss = 0;
|
||||||
|
+ u32 rate_code;
|
||||||
|
+ int ret, i;
|
||||||
|
+
|
||||||
|
+ lockdep_assert_held(&ar->conf_mutex);
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) {
|
||||||
|
+ if (hweight8(mask->control[band].ht_mcs[i]) == 1) {
|
||||||
|
+ nss = i + 1;
|
||||||
|
+ ht_rate = ffs(mask->control[band].ht_mcs[i]) - 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!nss) {
|
||||||
|
+ ath11k_warn(ar->ab, "No single HT Fixed rate found to set for %pM",
|
||||||
|
+ sta->addr);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Avoid updating invalid nss as fixed rate*/
|
||||||
|
+ if (nss > sta->deflink.rx_nss)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
|
||||||
|
+ "Setting Fixed HT Rate for peer %pM. Device will not switch to any other selected rates",
|
||||||
|
+ sta->addr);
|
||||||
|
+
|
||||||
|
+ rate_code = ATH11K_HW_RATE_CODE(ht_rate, nss - 1,
|
||||||
|
+ WMI_RATE_PREAMBLE_HT);
|
||||||
|
+ ret = ath11k_wmi_set_peer_param(ar, sta->addr,
|
||||||
|
+ arvif->vdev_id,
|
||||||
|
+ WMI_PEER_PARAM_FIXED_RATE,
|
||||||
|
+ rate_code);
|
||||||
|
+ if (ret)
|
||||||
|
+ ath11k_warn(ar->ab,
|
||||||
|
+ "failed to update STA %pM HT Fixed Rate %d: %d\n",
|
||||||
|
+ sta->addr, rate_code, ret);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ath11k_station_assoc(struct ath11k *ar,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
|
struct ieee80211_sta *sta,
|
||||||
|
@@ -4491,7 +4539,7 @@ static int ath11k_station_assoc(struct a
|
||||||
|
struct cfg80211_chan_def def;
|
||||||
|
enum nl80211_band band;
|
||||||
|
struct cfg80211_bitrate_mask *mask;
|
||||||
|
- u8 num_vht_rates, num_he_rates;
|
||||||
|
+ u8 num_ht_rates, num_vht_rates, num_he_rates;
|
||||||
|
|
||||||
|
lockdep_assert_held(&ar->conf_mutex);
|
||||||
|
|
||||||
|
@@ -4519,6 +4567,7 @@ static int ath11k_station_assoc(struct a
|
||||||
|
|
||||||
|
num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask);
|
||||||
|
num_he_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, mask);
|
||||||
|
+ num_ht_rates = ath11k_mac_bitrate_mask_num_ht_rates(ar, band, mask);
|
||||||
|
|
||||||
|
/* If single VHT/HE rate is configured (by set_bitrate_mask()),
|
||||||
|
* peer_assoc will disable VHT/HE. This is now enabled by a peer specific
|
||||||
|
@@ -4535,6 +4584,11 @@ static int ath11k_station_assoc(struct a
|
||||||
|
band);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
+ } else if (sta->deflink.ht_cap.ht_supported && num_ht_rates == 1) {
|
||||||
|
+ ret = ath11k_mac_set_peer_ht_fixed_rate(arvif, sta, mask,
|
||||||
|
+ band);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Re-assoc is run only to update supported rates for given station. It
|
||||||
|
@@ -4608,7 +4662,7 @@ static void ath11k_sta_rc_update_wk(stru
|
||||||
|
const u16 *vht_mcs_mask;
|
||||||
|
const u16 *he_mcs_mask;
|
||||||
|
u32 changed, bw, nss, smps, bw_prev;
|
||||||
|
- int err, num_vht_rates, num_he_rates;
|
||||||
|
+ int err, num_ht_rates, num_vht_rates, num_he_rates;
|
||||||
|
const struct cfg80211_bitrate_mask *mask;
|
||||||
|
struct peer_assoc_params peer_arg;
|
||||||
|
enum wmi_phy_mode peer_phymode;
|
||||||
|
@@ -4724,6 +4778,8 @@ static void ath11k_sta_rc_update_wk(stru
|
||||||
|
|
||||||
|
if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
|
||||||
|
mask = &arvif->bitrate_mask;
|
||||||
|
+ num_ht_rates = ath11k_mac_bitrate_mask_num_ht_rates(ar, band,
|
||||||
|
+ mask);
|
||||||
|
num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band,
|
||||||
|
mask);
|
||||||
|
num_he_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band,
|
||||||
|
@@ -4746,6 +4802,9 @@ static void ath11k_sta_rc_update_wk(stru
|
||||||
|
} else if (sta->deflink.he_cap.has_he && num_he_rates == 1) {
|
||||||
|
ath11k_mac_set_peer_he_fixed_rate(arvif, sta, mask,
|
||||||
|
band);
|
||||||
|
+ } else if (sta->deflink.ht_cap.ht_supported && num_ht_rates == 1) {
|
||||||
|
+ ath11k_mac_set_peer_ht_fixed_rate(arvif, sta, mask,
|
||||||
|
+ band);
|
||||||
|
} else {
|
||||||
|
/* If the peer is non-VHT/HE or no fixed VHT/HE rate
|
||||||
|
* is provided in the new bitrate mask we set the
|
|
@ -0,0 +1,127 @@
|
||||||
|
From 88ca89202f8e8afb5225eb5244d79cd67c15d744 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Wen Gong <quic_wgong@quicinc.com>
|
||||||
|
Date: Fri, 26 May 2023 12:41:06 +0300
|
||||||
|
Subject: [PATCH] wifi: ath11k: add support default regdb while searching
|
||||||
|
board-2.bin for WCN6855
|
||||||
|
|
||||||
|
Sometimes board-2.bin does not have the regdb data which matched the
|
||||||
|
parameters such as vendor, device, subsystem-vendor, subsystem-device
|
||||||
|
and etc. Add default regdb data with 'bus=%s' into board-2.bin for
|
||||||
|
WCN6855, then ath11k use 'bus=pci' to search regdb data in board-2.bin
|
||||||
|
for WCN6855.
|
||||||
|
|
||||||
|
kernel: [ 122.515808] ath11k_pci 0000:03:00.0: boot using board name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262'
|
||||||
|
kernel: [ 122.517240] ath11k_pci 0000:03:00.0: boot firmware request ath11k/WCN6855/hw2.0/board-2.bin size 6179564
|
||||||
|
kernel: [ 122.517280] ath11k_pci 0000:03:00.0: failed to fetch regdb data for bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262 from ath11k/WCN6855/hw2.0/board-2.bin
|
||||||
|
kernel: [ 122.517464] ath11k_pci 0000:03:00.0: boot using board name 'bus=pci'
|
||||||
|
kernel: [ 122.518901] ath11k_pci 0000:03:00.0: boot firmware request ath11k/WCN6855/hw2.0/board-2.bin size 6179564
|
||||||
|
kernel: [ 122.518915] ath11k_pci 0000:03:00.0: board name
|
||||||
|
kernel: [ 122.518917] ath11k_pci 0000:03:00.0: 00000000: 62 75 73 3d 70 63 69 bus=pci
|
||||||
|
kernel: [ 122.518918] ath11k_pci 0000:03:00.0: boot found match regdb data for name 'bus=pci'
|
||||||
|
kernel: [ 122.518920] ath11k_pci 0000:03:00.0: boot found regdb data for 'bus=pci'
|
||||||
|
kernel: [ 122.518921] ath11k_pci 0000:03:00.0: fetched regdb
|
||||||
|
|
||||||
|
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3
|
||||||
|
|
||||||
|
Signed-off-by: Wen Gong <quic_wgong@quicinc.com>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230517133959.8224-1-quic_wgong@quicinc.com
|
||||||
|
---
|
||||||
|
drivers/net/wireless/ath/ath11k/core.c | 53 +++++++++++++++++++-------
|
||||||
|
1 file changed, 40 insertions(+), 13 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/core.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/core.c
|
||||||
|
@@ -961,7 +961,8 @@ int ath11k_core_check_dt(struct ath11k_b
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __ath11k_core_create_board_name(struct ath11k_base *ab, char *name,
|
||||||
|
- size_t name_len, bool with_variant)
|
||||||
|
+ size_t name_len, bool with_variant,
|
||||||
|
+ bool bus_type_mode)
|
||||||
|
{
|
||||||
|
/* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */
|
||||||
|
char variant[9 + ATH11K_QMI_BDF_EXT_STR_LENGTH] = { 0 };
|
||||||
|
@@ -972,15 +973,20 @@ static int __ath11k_core_create_board_na
|
||||||
|
|
||||||
|
switch (ab->id.bdf_search) {
|
||||||
|
case ATH11K_BDF_SEARCH_BUS_AND_BOARD:
|
||||||
|
- scnprintf(name, name_len,
|
||||||
|
- "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x,qmi-chip-id=%d,qmi-board-id=%d%s",
|
||||||
|
- ath11k_bus_str(ab->hif.bus),
|
||||||
|
- ab->id.vendor, ab->id.device,
|
||||||
|
- ab->id.subsystem_vendor,
|
||||||
|
- ab->id.subsystem_device,
|
||||||
|
- ab->qmi.target.chip_id,
|
||||||
|
- ab->qmi.target.board_id,
|
||||||
|
- variant);
|
||||||
|
+ if (bus_type_mode)
|
||||||
|
+ scnprintf(name, name_len,
|
||||||
|
+ "bus=%s",
|
||||||
|
+ ath11k_bus_str(ab->hif.bus));
|
||||||
|
+ else
|
||||||
|
+ scnprintf(name, name_len,
|
||||||
|
+ "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x,qmi-chip-id=%d,qmi-board-id=%d%s",
|
||||||
|
+ ath11k_bus_str(ab->hif.bus),
|
||||||
|
+ ab->id.vendor, ab->id.device,
|
||||||
|
+ ab->id.subsystem_vendor,
|
||||||
|
+ ab->id.subsystem_device,
|
||||||
|
+ ab->qmi.target.chip_id,
|
||||||
|
+ ab->qmi.target.board_id,
|
||||||
|
+ variant);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
scnprintf(name, name_len,
|
||||||
|
@@ -999,13 +1005,19 @@ static int __ath11k_core_create_board_na
|
||||||
|
static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name,
|
||||||
|
size_t name_len)
|
||||||
|
{
|
||||||
|
- return __ath11k_core_create_board_name(ab, name, name_len, true);
|
||||||
|
+ return __ath11k_core_create_board_name(ab, name, name_len, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ath11k_core_create_fallback_board_name(struct ath11k_base *ab, char *name,
|
||||||
|
size_t name_len)
|
||||||
|
{
|
||||||
|
- return __ath11k_core_create_board_name(ab, name, name_len, false);
|
||||||
|
+ return __ath11k_core_create_board_name(ab, name, name_len, false, false);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ath11k_core_create_bus_type_board_name(struct ath11k_base *ab, char *name,
|
||||||
|
+ size_t name_len)
|
||||||
|
+{
|
||||||
|
+ return __ath11k_core_create_board_name(ab, name, name_len, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab,
|
||||||
|
@@ -1309,7 +1321,7 @@ success:
|
||||||
|
|
||||||
|
int ath11k_core_fetch_regdb(struct ath11k_base *ab, struct ath11k_board_data *bd)
|
||||||
|
{
|
||||||
|
- char boardname[BOARD_NAME_SIZE];
|
||||||
|
+ char boardname[BOARD_NAME_SIZE], default_boardname[BOARD_NAME_SIZE];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = ath11k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE);
|
||||||
|
@@ -1323,6 +1335,21 @@ int ath11k_core_fetch_regdb(struct ath11
|
||||||
|
ATH11K_BD_IE_REGDB,
|
||||||
|
ATH11K_BD_IE_REGDB_NAME,
|
||||||
|
ATH11K_BD_IE_REGDB_DATA);
|
||||||
|
+ if (!ret)
|
||||||
|
+ goto exit;
|
||||||
|
+
|
||||||
|
+ ret = ath11k_core_create_bus_type_board_name(ab, default_boardname,
|
||||||
|
+ BOARD_NAME_SIZE);
|
||||||
|
+ if (ret) {
|
||||||
|
+ ath11k_dbg(ab, ATH11K_DBG_BOOT,
|
||||||
|
+ "failed to create default board name for regdb: %d", ret);
|
||||||
|
+ goto exit;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ret = ath11k_core_fetch_board_data_api_n(ab, bd, default_boardname,
|
||||||
|
+ ATH11K_BD_IE_REGDB,
|
||||||
|
+ ATH11K_BD_IE_REGDB_NAME,
|
||||||
|
+ ATH11K_BD_IE_REGDB_DATA);
|
||||||
|
if (!ret)
|
||||||
|
goto exit;
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
From 86f85575a3f6a20cef1c8bb98e78585fe3a53ccc Mon Sep 17 00:00:00 2001
|
||||||
|
From: Govindaraj Saminathan <quic_gsaminat@quicinc.com>
|
||||||
|
Date: Fri, 26 May 2023 12:41:06 +0300
|
||||||
|
Subject: [PATCH 82/84] wifi: ath11k: remove unused function
|
||||||
|
ath11k_tm_event_wmi()
|
||||||
|
|
||||||
|
The function ath11k_tm_event_wmi() is only defined and it is not used
|
||||||
|
anywhere. Hence remove the unused.
|
||||||
|
|
||||||
|
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
||||||
|
|
||||||
|
Signed-off-by: Govindaraj Saminathan <quic_gsaminat@quicinc.com>
|
||||||
|
Signed-off-by: Raj Kumar Bhagat <quic_rajkbhag@quicinc.com>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230517135934.16408-2-quic_rajkbhag@quicinc.com
|
||||||
|
---
|
||||||
|
drivers/net/wireless/ath/ath11k/testmode.c | 64 +---------------------
|
||||||
|
drivers/net/wireless/ath/ath11k/testmode.h | 8 +--
|
||||||
|
2 files changed, 2 insertions(+), 70 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/testmode.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/testmode.c
|
||||||
|
@@ -1,6 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||||
|
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "testmode.h"
|
||||||
|
@@ -20,69 +21,6 @@ static const struct nla_policy ath11k_tm
|
||||||
|
[ATH11K_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 },
|
||||||
|
};
|
||||||
|
|
||||||
|
-/* Returns true if callee consumes the skb and the skb should be discarded.
|
||||||
|
- * Returns false if skb is not used. Does not sleep.
|
||||||
|
- */
|
||||||
|
-bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id, struct sk_buff *skb)
|
||||||
|
-{
|
||||||
|
- struct sk_buff *nl_skb;
|
||||||
|
- bool consumed;
|
||||||
|
- int ret;
|
||||||
|
-
|
||||||
|
- ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
|
||||||
|
- "testmode event wmi cmd_id %d skb %pK skb->len %d\n",
|
||||||
|
- cmd_id, skb, skb->len);
|
||||||
|
-
|
||||||
|
- ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
|
||||||
|
-
|
||||||
|
- spin_lock_bh(&ar->data_lock);
|
||||||
|
-
|
||||||
|
- consumed = true;
|
||||||
|
-
|
||||||
|
- nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
|
||||||
|
- 2 * sizeof(u32) + skb->len,
|
||||||
|
- GFP_ATOMIC);
|
||||||
|
- if (!nl_skb) {
|
||||||
|
- ath11k_warn(ar->ab,
|
||||||
|
- "failed to allocate skb for testmode wmi event\n");
|
||||||
|
- goto out;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- ret = nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD, ATH11K_TM_CMD_WMI);
|
||||||
|
- if (ret) {
|
||||||
|
- ath11k_warn(ar->ab,
|
||||||
|
- "failed to put testmode wmi event cmd attribute: %d\n",
|
||||||
|
- ret);
|
||||||
|
- kfree_skb(nl_skb);
|
||||||
|
- goto out;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- ret = nla_put_u32(nl_skb, ATH11K_TM_ATTR_WMI_CMDID, cmd_id);
|
||||||
|
- if (ret) {
|
||||||
|
- ath11k_warn(ar->ab,
|
||||||
|
- "failed to put testmode wmi even cmd_id: %d\n",
|
||||||
|
- ret);
|
||||||
|
- kfree_skb(nl_skb);
|
||||||
|
- goto out;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- ret = nla_put(nl_skb, ATH11K_TM_ATTR_DATA, skb->len, skb->data);
|
||||||
|
- if (ret) {
|
||||||
|
- ath11k_warn(ar->ab,
|
||||||
|
- "failed to copy skb to testmode wmi event: %d\n",
|
||||||
|
- ret);
|
||||||
|
- kfree_skb(nl_skb);
|
||||||
|
- goto out;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
|
||||||
|
-
|
||||||
|
-out:
|
||||||
|
- spin_unlock_bh(&ar->data_lock);
|
||||||
|
-
|
||||||
|
- return consumed;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static int ath11k_tm_cmd_get_version(struct ath11k *ar, struct nlattr *tb[])
|
||||||
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/testmode.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/testmode.h
|
||||||
|
@@ -1,24 +1,18 @@
|
||||||
|
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||||
|
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
|
#ifdef CPTCFG_NL80211_TESTMODE
|
||||||
|
|
||||||
|
-bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id, struct sk_buff *skb);
|
||||||
|
int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
|
void *data, int len);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
-static inline bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id,
|
||||||
|
- struct sk_buff *skb)
|
||||||
|
-{
|
||||||
|
- return false;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static inline int ath11k_tm_cmd(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
|
void *data, int len)
|
|
@ -0,0 +1,850 @@
|
||||||
|
From b43310e44edc823a7f02af1e1e2b4e8a9abc7d91 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Govindaraj Saminathan <quic_gsaminat@quicinc.com>
|
||||||
|
Date: Fri, 26 May 2023 12:41:07 +0300
|
||||||
|
Subject: [PATCH 83/84] wifi: ath11k: factory test mode support
|
||||||
|
|
||||||
|
Add support to process factory test mode commands (FTM) for calibration.
|
||||||
|
By default firmware start with NORMAL mode and to process the FTM commands
|
||||||
|
firmware needs to be restarted in FTM mode using module parameter ftm_mode.
|
||||||
|
The pre-request is all the radios should be down before starting the test.
|
||||||
|
|
||||||
|
When start command ATH11K_TM_CMD_TESTMODE_START is received, ar->state
|
||||||
|
is set to Test Mode. If the FTM command or event length is greater
|
||||||
|
than 256 bytes, it will be broken down into multiple segments and
|
||||||
|
encoded with TLV header if it is segmented commands, else it is sent
|
||||||
|
to firmware as it is.
|
||||||
|
|
||||||
|
On receiving UTF event from firmware, if it is segmented event, the driver
|
||||||
|
will wait until it receives all the segments and notify the complete
|
||||||
|
data to user application. In case the segmented sequence are missed or
|
||||||
|
lost from the firmware, driver will skip the already received partial data.
|
||||||
|
|
||||||
|
In case of unsegmented UTF event from firmware, driver notifies the
|
||||||
|
data to the user application as it comes. Applications handles
|
||||||
|
the data further.
|
||||||
|
|
||||||
|
Command to boot in ftm mode:
|
||||||
|
|
||||||
|
insmod ath11k ftm_mode=1
|
||||||
|
|
||||||
|
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
||||||
|
|
||||||
|
Signed-off-by: Govindaraj Saminathan <quic_gsaminat@quicinc.com>
|
||||||
|
Co-developed-by: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>
|
||||||
|
Signed-off-by: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>
|
||||||
|
Signed-off-by: Raj Kumar Bhagat <quic_rajkbhag@quicinc.com>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230517135934.16408-4-quic_rajkbhag@quicinc.com
|
||||||
|
---
|
||||||
|
drivers/net/wireless/ath/ath11k/ahb.c | 3 +-
|
||||||
|
drivers/net/wireless/ath/ath11k/core.c | 21 +-
|
||||||
|
drivers/net/wireless/ath/ath11k/core.h | 16 +-
|
||||||
|
drivers/net/wireless/ath/ath11k/debug.h | 1 +
|
||||||
|
drivers/net/wireless/ath/ath11k/mac.c | 11 +-
|
||||||
|
drivers/net/wireless/ath/ath11k/pci.c | 3 +-
|
||||||
|
drivers/net/wireless/ath/ath11k/testmode.c | 350 ++++++++++++++++++-
|
||||||
|
drivers/net/wireless/ath/ath11k/testmode.h | 6 +
|
||||||
|
drivers/net/wireless/ath/ath11k/testmode_i.h | 18 +-
|
||||||
|
drivers/net/wireless/ath/ath11k/wmi.c | 11 +-
|
||||||
|
drivers/net/wireless/ath/ath11k/wmi.h | 22 ++
|
||||||
|
drivers/net/wireless/ath/ath11k/wow.c | 3 +-
|
||||||
|
12 files changed, 444 insertions(+), 21 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/ahb.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||||
|
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
@@ -1155,6 +1155,7 @@ static int ath11k_ahb_probe(struct platf
|
||||||
|
ab->hif.ops = hif_ops;
|
||||||
|
ab->pdev = pdev;
|
||||||
|
ab->hw_rev = hw_rev;
|
||||||
|
+ ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL;
|
||||||
|
platform_set_drvdata(pdev, ab);
|
||||||
|
|
||||||
|
ret = ath11k_pcic_register_pci_ops(ab, pci_ops);
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/core.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/core.c
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||||
|
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
@@ -32,6 +32,10 @@ module_param_named(frame_mode, ath11k_fr
|
||||||
|
MODULE_PARM_DESC(frame_mode,
|
||||||
|
"Datapath frame mode (0: raw, 1: native wifi (default), 2: ethernet)");
|
||||||
|
|
||||||
|
+bool ath11k_ftm_mode;
|
||||||
|
+module_param_named(ftm_mode, ath11k_ftm_mode, bool, 0444);
|
||||||
|
+MODULE_PARM_DESC(ftm_mode, "Boots up in factory test mode");
|
||||||
|
+
|
||||||
|
static const struct ath11k_hw_params ath11k_hw_params[] = {
|
||||||
|
{
|
||||||
|
.hw_rev = ATH11K_HW_IPQ8074,
|
||||||
|
@@ -1381,6 +1385,11 @@ static int ath11k_core_soc_create(struct
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
+ if (ath11k_ftm_mode) {
|
||||||
|
+ ab->fw_mode = ATH11K_FIRMWARE_MODE_FTM;
|
||||||
|
+ ath11k_info(ab, "Booting in factory test mode\n");
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
ret = ath11k_qmi_init_service(ab);
|
||||||
|
if (ret) {
|
||||||
|
ath11k_err(ab, "failed to initialize qmi :%d\n", ret);
|
||||||
|
@@ -1607,7 +1616,7 @@ int ath11k_core_qmi_firmware_ready(struc
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
- ret = ath11k_core_start_firmware(ab, ATH11K_FIRMWARE_MODE_NORMAL);
|
||||||
|
+ ret = ath11k_core_start_firmware(ab, ab->fw_mode);
|
||||||
|
if (ret) {
|
||||||
|
ath11k_err(ab, "failed to start firmware: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
@@ -1772,7 +1781,8 @@ void ath11k_core_pre_reconfigure_recover
|
||||||
|
for (i = 0; i < ab->num_radios; i++) {
|
||||||
|
pdev = &ab->pdevs[i];
|
||||||
|
ar = pdev->ar;
|
||||||
|
- if (!ar || ar->state == ATH11K_STATE_OFF)
|
||||||
|
+ if (!ar || ar->state == ATH11K_STATE_OFF ||
|
||||||
|
+ ar->state == ATH11K_STATE_FTM)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ieee80211_stop_queues(ar->hw);
|
||||||
|
@@ -1841,7 +1851,12 @@ static void ath11k_core_post_reconfigure
|
||||||
|
ath11k_warn(ab,
|
||||||
|
"device is wedged, will not restart radio %d\n", i);
|
||||||
|
break;
|
||||||
|
+ case ATH11K_STATE_FTM:
|
||||||
|
+ ath11k_dbg(ab, ATH11K_DBG_TESTMODE,
|
||||||
|
+ "fw mode reset done radio %d\n", i);
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
mutex_unlock(&ar->conf_mutex);
|
||||||
|
}
|
||||||
|
complete(&ab->driver_recovery);
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/core.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/core.h
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||||
|
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ATH11K_CORE_H
|
||||||
|
@@ -52,6 +52,7 @@
|
||||||
|
#define ATH11K_SMBIOS_BDF_EXT_MAGIC "BDF_"
|
||||||
|
|
||||||
|
extern unsigned int ath11k_frame_mode;
|
||||||
|
+extern bool ath11k_ftm_mode;
|
||||||
|
|
||||||
|
#define ATH11K_SCAN_TIMEOUT_HZ (20 * HZ)
|
||||||
|
|
||||||
|
@@ -277,6 +278,7 @@ enum ath11k_dev_flags {
|
||||||
|
ATH11K_FLAG_FIXED_MEM_RGN,
|
||||||
|
ATH11K_FLAG_DEVICE_INIT_DONE,
|
||||||
|
ATH11K_FLAG_MULTI_MSI_VECTORS,
|
||||||
|
+ ATH11K_FLAG_FTM_SEGMENTED,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ath11k_monitor_flags {
|
||||||
|
@@ -530,6 +532,7 @@ enum ath11k_state {
|
||||||
|
ATH11K_STATE_RESTARTING,
|
||||||
|
ATH11K_STATE_RESTARTED,
|
||||||
|
ATH11K_STATE_WEDGED,
|
||||||
|
+ ATH11K_STATE_FTM,
|
||||||
|
/* Add other states as required */
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -709,6 +712,8 @@ struct ath11k {
|
||||||
|
u32 last_ppdu_id;
|
||||||
|
u32 cached_ppdu_id;
|
||||||
|
int monitor_vdev_id;
|
||||||
|
+ struct completion fw_mode_reset;
|
||||||
|
+ u8 ftm_msgref;
|
||||||
|
#ifdef CPTCFG_ATH11K_DEBUGFS
|
||||||
|
struct ath11k_debug debug;
|
||||||
|
#endif
|
||||||
|
@@ -838,6 +843,7 @@ struct ath11k_msi_config {
|
||||||
|
/* Master structure to hold the hw data which may be used in core module */
|
||||||
|
struct ath11k_base {
|
||||||
|
enum ath11k_hw_rev hw_rev;
|
||||||
|
+ enum ath11k_firmware_mode fw_mode;
|
||||||
|
struct platform_device *pdev;
|
||||||
|
struct device *dev;
|
||||||
|
struct ath11k_qmi qmi;
|
||||||
|
@@ -978,6 +984,14 @@ struct ath11k_base {
|
||||||
|
const struct ath11k_pci_ops *ops;
|
||||||
|
} pci;
|
||||||
|
|
||||||
|
+#ifdef CPTCFG_NL80211_TESTMODE
|
||||||
|
+ struct {
|
||||||
|
+ u32 data_pos;
|
||||||
|
+ u32 expected_seq;
|
||||||
|
+ u8 *eventdata;
|
||||||
|
+ } testmode;
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/* must be last */
|
||||||
|
u8 drv_priv[] __aligned(sizeof(void *));
|
||||||
|
};
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/debug.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/debug.h
|
||||||
|
@@ -1,6 +1,7 @@
|
||||||
|
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||||
|
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ATH11K_DEBUG_H_
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
||||||
|
@@ -643,7 +643,10 @@ struct ath11k *ath11k_mac_get_ar_by_pdev
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < ab->num_radios; i++) {
|
||||||
|
- pdev = rcu_dereference(ab->pdevs_active[i]);
|
||||||
|
+ if (ab->fw_mode == ATH11K_FIRMWARE_MODE_FTM)
|
||||||
|
+ pdev = &ab->pdevs[i];
|
||||||
|
+ else
|
||||||
|
+ pdev = rcu_dereference(ab->pdevs_active[i]);
|
||||||
|
|
||||||
|
if (pdev && pdev->pdev_id == pdev_id)
|
||||||
|
return (pdev->ar ? pdev->ar : NULL);
|
||||||
|
@@ -6271,6 +6274,11 @@ static int ath11k_mac_op_start(struct ie
|
||||||
|
struct ath11k_pdev *pdev = ar->pdev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
+ if (ath11k_ftm_mode) {
|
||||||
|
+ ath11k_warn(ab, "mac operations not supported in factory test mode\n");
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
ath11k_mac_drain_tx(ar);
|
||||||
|
mutex_lock(&ar->conf_mutex);
|
||||||
|
|
||||||
|
@@ -6285,6 +6293,7 @@ static int ath11k_mac_op_start(struct ie
|
||||||
|
case ATH11K_STATE_RESTARTED:
|
||||||
|
case ATH11K_STATE_WEDGED:
|
||||||
|
case ATH11K_STATE_ON:
|
||||||
|
+ case ATH11K_STATE_FTM:
|
||||||
|
WARN_ON(1);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto err;
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/pci.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/pci.c
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
|
||||||
|
- * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
@@ -745,6 +745,7 @@ static int ath11k_pci_probe(struct pci_d
|
||||||
|
ab_pci->ab = ab;
|
||||||
|
ab_pci->pdev = pdev;
|
||||||
|
ab->hif.ops = &ath11k_pci_hif_ops;
|
||||||
|
+ ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL;
|
||||||
|
pci_set_drvdata(pdev, ab);
|
||||||
|
spin_lock_init(&ab_pci->window_lock);
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/testmode.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/testmode.c
|
||||||
|
@@ -12,6 +12,9 @@
|
||||||
|
#include "core.h"
|
||||||
|
#include "testmode_i.h"
|
||||||
|
|
||||||
|
+#define ATH11K_FTM_SEGHDR_CURRENT_SEQ GENMASK(3, 0)
|
||||||
|
+#define ATH11K_FTM_SEGHDR_TOTAL_SEGMENTS GENMASK(7, 4)
|
||||||
|
+
|
||||||
|
static const struct nla_policy ath11k_tm_policy[ATH11K_TM_ATTR_MAX + 1] = {
|
||||||
|
[ATH11K_TM_ATTR_CMD] = { .type = NLA_U32 },
|
||||||
|
[ATH11K_TM_ATTR_DATA] = { .type = NLA_BINARY,
|
||||||
|
@@ -21,13 +24,217 @@ static const struct nla_policy ath11k_tm
|
||||||
|
[ATH11K_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 },
|
||||||
|
};
|
||||||
|
|
||||||
|
+static struct ath11k *ath11k_tm_get_ar(struct ath11k_base *ab)
|
||||||
|
+{
|
||||||
|
+ struct ath11k_pdev *pdev;
|
||||||
|
+ struct ath11k *ar = NULL;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < ab->num_radios; i++) {
|
||||||
|
+ pdev = &ab->pdevs[i];
|
||||||
|
+ ar = pdev->ar;
|
||||||
|
+
|
||||||
|
+ if (ar && ar->state == ATH11K_STATE_FTM)
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return ar;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* This function handles unsegmented events. Data in various events are aggregated
|
||||||
|
+ * in application layer, this event is unsegmented from host perspective.
|
||||||
|
+ */
|
||||||
|
+static void ath11k_tm_wmi_event_unsegmented(struct ath11k_base *ab, u32 cmd_id,
|
||||||
|
+ struct sk_buff *skb)
|
||||||
|
+{
|
||||||
|
+ struct sk_buff *nl_skb;
|
||||||
|
+ struct ath11k *ar;
|
||||||
|
+
|
||||||
|
+ ath11k_dbg(ab, ATH11K_DBG_TESTMODE,
|
||||||
|
+ "event wmi cmd_id %d skb length %d\n",
|
||||||
|
+ cmd_id, skb->len);
|
||||||
|
+ ath11k_dbg_dump(ab, ATH11K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
|
||||||
|
+
|
||||||
|
+ ar = ath11k_tm_get_ar(ab);
|
||||||
|
+ if (!ar) {
|
||||||
|
+ ath11k_warn(ab, "testmode event not handled due to invalid pdev\n");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ spin_lock_bh(&ar->data_lock);
|
||||||
|
+
|
||||||
|
+ nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
|
||||||
|
+ 2 * nla_total_size(sizeof(u32)) +
|
||||||
|
+ nla_total_size(skb->len),
|
||||||
|
+ GFP_ATOMIC);
|
||||||
|
+ if (!nl_skb) {
|
||||||
|
+ ath11k_warn(ab,
|
||||||
|
+ "failed to allocate skb for unsegmented testmode wmi event\n");
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD, ATH11K_TM_CMD_WMI) ||
|
||||||
|
+ nla_put_u32(nl_skb, ATH11K_TM_ATTR_WMI_CMDID, cmd_id) ||
|
||||||
|
+ nla_put(nl_skb, ATH11K_TM_ATTR_DATA, skb->len, skb->data)) {
|
||||||
|
+ ath11k_warn(ab, "failed to populate testmode unsegmented event\n");
|
||||||
|
+ kfree_skb(nl_skb);
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
|
||||||
|
+ spin_unlock_bh(&ar->data_lock);
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+out:
|
||||||
|
+ spin_unlock_bh(&ar->data_lock);
|
||||||
|
+ ath11k_warn(ab, "Failed to send testmode event to higher layers\n");
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* This function handles segmented events. Data of various events received
|
||||||
|
+ * from firmware is aggregated and sent to application layer
|
||||||
|
+ */
|
||||||
|
+static int ath11k_tm_process_event(struct ath11k_base *ab, u32 cmd_id,
|
||||||
|
+ const struct wmi_ftm_event_msg *ftm_msg,
|
||||||
|
+ u16 length)
|
||||||
|
+{
|
||||||
|
+ struct sk_buff *nl_skb;
|
||||||
|
+ int ret = 0;
|
||||||
|
+ struct ath11k *ar;
|
||||||
|
+ u8 const *buf_pos;
|
||||||
|
+ u16 datalen;
|
||||||
|
+ u8 total_segments, current_seq;
|
||||||
|
+ u32 data_pos;
|
||||||
|
+ u32 pdev_id;
|
||||||
|
+
|
||||||
|
+ ath11k_dbg(ab, ATH11K_DBG_TESTMODE,
|
||||||
|
+ "event wmi cmd_id %d ftm event msg %pK datalen %d\n",
|
||||||
|
+ cmd_id, ftm_msg, length);
|
||||||
|
+ ath11k_dbg_dump(ab, ATH11K_DBG_TESTMODE, NULL, "", ftm_msg, length);
|
||||||
|
+ pdev_id = DP_HW2SW_MACID(ftm_msg->seg_hdr.pdev_id);
|
||||||
|
+
|
||||||
|
+ if (pdev_id >= ab->num_radios) {
|
||||||
|
+ ath11k_warn(ab, "testmode event not handled due to invalid pdev id: %d\n",
|
||||||
|
+ pdev_id);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ar = ab->pdevs[pdev_id].ar;
|
||||||
|
+ if (!ar) {
|
||||||
|
+ ath11k_warn(ab, "testmode event not handled due to absence of pdev\n");
|
||||||
|
+ return -ENODEV;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ current_seq = FIELD_GET(ATH11K_FTM_SEGHDR_CURRENT_SEQ,
|
||||||
|
+ ftm_msg->seg_hdr.segmentinfo);
|
||||||
|
+ total_segments = FIELD_GET(ATH11K_FTM_SEGHDR_TOTAL_SEGMENTS,
|
||||||
|
+ ftm_msg->seg_hdr.segmentinfo);
|
||||||
|
+ datalen = length - (sizeof(struct wmi_ftm_seg_hdr));
|
||||||
|
+ buf_pos = ftm_msg->data;
|
||||||
|
+
|
||||||
|
+ spin_lock_bh(&ar->data_lock);
|
||||||
|
+
|
||||||
|
+ if (current_seq == 0) {
|
||||||
|
+ ab->testmode.expected_seq = 0;
|
||||||
|
+ ab->testmode.data_pos = 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ data_pos = ab->testmode.data_pos;
|
||||||
|
+
|
||||||
|
+ if ((data_pos + datalen) > ATH11K_FTM_EVENT_MAX_BUF_LENGTH) {
|
||||||
|
+ ath11k_warn(ab, "Invalid ftm event length at %d: %d\n",
|
||||||
|
+ data_pos, datalen);
|
||||||
|
+ ret = -EINVAL;
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ memcpy(&ab->testmode.eventdata[data_pos], buf_pos, datalen);
|
||||||
|
+ data_pos += datalen;
|
||||||
|
+
|
||||||
|
+ if (++ab->testmode.expected_seq != total_segments) {
|
||||||
|
+ ab->testmode.data_pos = data_pos;
|
||||||
|
+ ath11k_dbg(ab, ATH11K_DBG_TESTMODE,
|
||||||
|
+ "partial data received current_seq %d total_seg %d\n",
|
||||||
|
+ current_seq, total_segments);
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ath11k_dbg(ab, ATH11K_DBG_TESTMODE,
|
||||||
|
+ "total data length pos %d len %d\n",
|
||||||
|
+ data_pos, ftm_msg->seg_hdr.len);
|
||||||
|
+ nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
|
||||||
|
+ 2 * nla_total_size(sizeof(u32)) +
|
||||||
|
+ nla_total_size(data_pos),
|
||||||
|
+ GFP_ATOMIC);
|
||||||
|
+ if (!nl_skb) {
|
||||||
|
+ ath11k_warn(ab,
|
||||||
|
+ "failed to allocate skb for segmented testmode wmi event\n");
|
||||||
|
+ ret = -ENOMEM;
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD,
|
||||||
|
+ ATH11K_TM_CMD_WMI_FTM) ||
|
||||||
|
+ nla_put_u32(nl_skb, ATH11K_TM_ATTR_WMI_CMDID, cmd_id) ||
|
||||||
|
+ nla_put(nl_skb, ATH11K_TM_ATTR_DATA, data_pos,
|
||||||
|
+ &ab->testmode.eventdata[0])) {
|
||||||
|
+ ath11k_warn(ab, "failed to populate segmented testmode event");
|
||||||
|
+ kfree_skb(nl_skb);
|
||||||
|
+ ret = -ENOBUFS;
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
|
||||||
|
+
|
||||||
|
+out:
|
||||||
|
+ spin_unlock_bh(&ar->data_lock);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void ath11k_tm_wmi_event_segmented(struct ath11k_base *ab, u32 cmd_id,
|
||||||
|
+ struct sk_buff *skb)
|
||||||
|
+{
|
||||||
|
+ const void **tb;
|
||||||
|
+ const struct wmi_ftm_event_msg *ev;
|
||||||
|
+ u16 length;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
|
||||||
|
+ if (IS_ERR(tb)) {
|
||||||
|
+ ret = PTR_ERR(tb);
|
||||||
|
+ ath11k_warn(ab, "failed to parse ftm event tlv: %d\n", ret);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ev = tb[WMI_TAG_ARRAY_BYTE];
|
||||||
|
+ if (!ev) {
|
||||||
|
+ ath11k_warn(ab, "failed to fetch ftm msg\n");
|
||||||
|
+ kfree(tb);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ length = skb->len - TLV_HDR_SIZE;
|
||||||
|
+ ret = ath11k_tm_process_event(ab, cmd_id, ev, length);
|
||||||
|
+ if (ret)
|
||||||
|
+ ath11k_warn(ab, "Failed to process ftm event\n");
|
||||||
|
+
|
||||||
|
+ kfree(tb);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void ath11k_tm_wmi_event(struct ath11k_base *ab, u32 cmd_id, struct sk_buff *skb)
|
||||||
|
+{
|
||||||
|
+ if (test_bit(ATH11K_FLAG_FTM_SEGMENTED, &ab->dev_flags))
|
||||||
|
+ ath11k_tm_wmi_event_segmented(ab, cmd_id, skb);
|
||||||
|
+ else
|
||||||
|
+ ath11k_tm_wmi_event_unsegmented(ab, cmd_id, skb);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ath11k_tm_cmd_get_version(struct ath11k *ar, struct nlattr *tb[])
|
||||||
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
|
||||||
|
- "testmode cmd get version_major %d version_minor %d\n",
|
||||||
|
+ "cmd get version_major %d version_minor %d\n",
|
||||||
|
ATH11K_TESTMODE_VERSION_MAJOR,
|
||||||
|
ATH11K_TESTMODE_VERSION_MINOR);
|
||||||
|
|
||||||
|
@@ -53,6 +260,43 @@ static int ath11k_tm_cmd_get_version(str
|
||||||
|
return cfg80211_testmode_reply(skb);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int ath11k_tm_cmd_testmode_start(struct ath11k *ar, struct nlattr *tb[])
|
||||||
|
+{
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ mutex_lock(&ar->conf_mutex);
|
||||||
|
+
|
||||||
|
+ if (ar->state == ATH11K_STATE_FTM) {
|
||||||
|
+ ret = -EALREADY;
|
||||||
|
+ goto err;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* start utf only when the driver is not in use */
|
||||||
|
+ if (ar->state != ATH11K_STATE_OFF) {
|
||||||
|
+ ret = -EBUSY;
|
||||||
|
+ goto err;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ar->ab->testmode.eventdata = kzalloc(ATH11K_FTM_EVENT_MAX_BUF_LENGTH,
|
||||||
|
+ GFP_KERNEL);
|
||||||
|
+ if (!ar->ab->testmode.eventdata) {
|
||||||
|
+ ret = -ENOMEM;
|
||||||
|
+ goto err;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ar->state = ATH11K_STATE_FTM;
|
||||||
|
+ ar->ftm_msgref = 0;
|
||||||
|
+
|
||||||
|
+ mutex_unlock(&ar->conf_mutex);
|
||||||
|
+
|
||||||
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE, "cmd start\n");
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+err:
|
||||||
|
+ mutex_unlock(&ar->conf_mutex);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[])
|
||||||
|
{
|
||||||
|
struct ath11k_pdev_wmi *wmi = ar->wmi;
|
||||||
|
@@ -63,11 +307,6 @@ static int ath11k_tm_cmd_wmi(struct ath1
|
||||||
|
|
||||||
|
mutex_lock(&ar->conf_mutex);
|
||||||
|
|
||||||
|
- if (ar->state != ATH11K_STATE_ON) {
|
||||||
|
- ret = -ENETDOWN;
|
||||||
|
- goto out;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
if (!tb[ATH11K_TM_ATTR_DATA]) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
@@ -80,11 +319,17 @@ static int ath11k_tm_cmd_wmi(struct ath1
|
||||||
|
|
||||||
|
buf = nla_data(tb[ATH11K_TM_ATTR_DATA]);
|
||||||
|
buf_len = nla_len(tb[ATH11K_TM_ATTR_DATA]);
|
||||||
|
+ if (!buf_len) {
|
||||||
|
+ ath11k_warn(ar->ab, "No data present in testmode wmi command\n");
|
||||||
|
+ ret = -EINVAL;
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
cmd_id = nla_get_u32(tb[ATH11K_TM_ATTR_WMI_CMDID]);
|
||||||
|
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
|
||||||
|
- "testmode cmd wmi cmd_id %d buf %pK buf_len %d\n",
|
||||||
|
- cmd_id, buf, buf_len);
|
||||||
|
+ "cmd wmi cmd_id %d buf length %d\n",
|
||||||
|
+ cmd_id, buf_len);
|
||||||
|
|
||||||
|
ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", buf, buf_len);
|
||||||
|
|
||||||
|
@@ -111,6 +356,91 @@ out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int ath11k_tm_cmd_wmi_ftm(struct ath11k *ar, struct nlattr *tb[])
|
||||||
|
+{
|
||||||
|
+ struct ath11k_pdev_wmi *wmi = ar->wmi;
|
||||||
|
+ struct ath11k_base *ab = ar->ab;
|
||||||
|
+ struct sk_buff *skb;
|
||||||
|
+ u32 cmd_id, buf_len, hdr_info;
|
||||||
|
+ int ret;
|
||||||
|
+ void *buf;
|
||||||
|
+ u8 segnumber = 0, seginfo;
|
||||||
|
+ u16 chunk_len, total_bytes, num_segments;
|
||||||
|
+ u8 *bufpos;
|
||||||
|
+ struct wmi_ftm_cmd *ftm_cmd;
|
||||||
|
+
|
||||||
|
+ set_bit(ATH11K_FLAG_FTM_SEGMENTED, &ab->dev_flags);
|
||||||
|
+
|
||||||
|
+ mutex_lock(&ar->conf_mutex);
|
||||||
|
+
|
||||||
|
+ if (ar->state != ATH11K_STATE_FTM) {
|
||||||
|
+ ret = -ENETDOWN;
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!tb[ATH11K_TM_ATTR_DATA]) {
|
||||||
|
+ ret = -EINVAL;
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ buf = nla_data(tb[ATH11K_TM_ATTR_DATA]);
|
||||||
|
+ buf_len = nla_len(tb[ATH11K_TM_ATTR_DATA]);
|
||||||
|
+ cmd_id = WMI_PDEV_UTF_CMDID;
|
||||||
|
+
|
||||||
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
|
||||||
|
+ "cmd wmi ftm cmd_id %d buffer length %d\n",
|
||||||
|
+ cmd_id, buf_len);
|
||||||
|
+ ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", buf, buf_len);
|
||||||
|
+
|
||||||
|
+ bufpos = buf;
|
||||||
|
+ total_bytes = buf_len;
|
||||||
|
+ num_segments = total_bytes / MAX_WMI_UTF_LEN;
|
||||||
|
+
|
||||||
|
+ if (buf_len - (num_segments * MAX_WMI_UTF_LEN))
|
||||||
|
+ num_segments++;
|
||||||
|
+
|
||||||
|
+ while (buf_len) {
|
||||||
|
+ chunk_len = min_t(u16, buf_len, MAX_WMI_UTF_LEN);
|
||||||
|
+
|
||||||
|
+ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, (chunk_len +
|
||||||
|
+ sizeof(struct wmi_ftm_cmd)));
|
||||||
|
+ if (!skb) {
|
||||||
|
+ ret = -ENOMEM;
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ftm_cmd = (struct wmi_ftm_cmd *)skb->data;
|
||||||
|
+ hdr_info = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
|
||||||
|
+ FIELD_PREP(WMI_TLV_LEN, (chunk_len +
|
||||||
|
+ sizeof(struct wmi_ftm_seg_hdr)));
|
||||||
|
+ ftm_cmd->tlv_header = hdr_info;
|
||||||
|
+ ftm_cmd->seg_hdr.len = total_bytes;
|
||||||
|
+ ftm_cmd->seg_hdr.msgref = ar->ftm_msgref;
|
||||||
|
+ seginfo = FIELD_PREP(ATH11K_FTM_SEGHDR_TOTAL_SEGMENTS, num_segments) |
|
||||||
|
+ FIELD_PREP(ATH11K_FTM_SEGHDR_CURRENT_SEQ, segnumber);
|
||||||
|
+ ftm_cmd->seg_hdr.segmentinfo = seginfo;
|
||||||
|
+ segnumber++;
|
||||||
|
+
|
||||||
|
+ memcpy(&ftm_cmd->data, bufpos, chunk_len);
|
||||||
|
+
|
||||||
|
+ ret = ath11k_wmi_cmd_send(wmi, skb, cmd_id);
|
||||||
|
+ if (ret) {
|
||||||
|
+ ath11k_warn(ar->ab, "failed to send wmi ftm command: %d\n", ret);
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ buf_len -= chunk_len;
|
||||||
|
+ bufpos += chunk_len;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ar->ftm_msgref++;
|
||||||
|
+ ret = 0;
|
||||||
|
+
|
||||||
|
+out:
|
||||||
|
+ mutex_unlock(&ar->conf_mutex);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
|
void *data, int len)
|
||||||
|
{
|
||||||
|
@@ -131,6 +461,10 @@ int ath11k_tm_cmd(struct ieee80211_hw *h
|
||||||
|
return ath11k_tm_cmd_get_version(ar, tb);
|
||||||
|
case ATH11K_TM_CMD_WMI:
|
||||||
|
return ath11k_tm_cmd_wmi(ar, tb);
|
||||||
|
+ case ATH11K_TM_CMD_TESTMODE_START:
|
||||||
|
+ return ath11k_tm_cmd_testmode_start(ar, tb);
|
||||||
|
+ case ATH11K_TM_CMD_WMI_FTM:
|
||||||
|
+ return ath11k_tm_cmd_wmi_ftm(ar, tb);
|
||||||
|
default:
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/testmode.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/testmode.h
|
||||||
|
@@ -8,11 +8,17 @@
|
||||||
|
|
||||||
|
#ifdef CPTCFG_NL80211_TESTMODE
|
||||||
|
|
||||||
|
+void ath11k_tm_wmi_event(struct ath11k_base *ab, u32 cmd_id, struct sk_buff *skb);
|
||||||
|
int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
|
void *data, int len);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
+static inline void ath11k_tm_wmi_event(struct ath11k_base *ab, u32 cmd_id,
|
||||||
|
+ struct sk_buff *skb)
|
||||||
|
+{
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static inline int ath11k_tm_cmd(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
|
void *data, int len)
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/testmode_i.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/testmode_i.h
|
||||||
|
@@ -1,6 +1,7 @@
|
||||||
|
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||||
|
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* "API" level of the ath11k testmode interface. Bump it after every
|
||||||
|
@@ -11,9 +12,10 @@
|
||||||
|
/* Bump this after every _compatible_ interface change, for example
|
||||||
|
* addition of a new command or an attribute.
|
||||||
|
*/
|
||||||
|
-#define ATH11K_TESTMODE_VERSION_MINOR 0
|
||||||
|
+#define ATH11K_TESTMODE_VERSION_MINOR 1
|
||||||
|
|
||||||
|
#define ATH11K_TM_DATA_MAX_LEN 5000
|
||||||
|
+#define ATH11K_FTM_EVENT_MAX_BUF_LENGTH 2048
|
||||||
|
|
||||||
|
enum ath11k_tm_attr {
|
||||||
|
__ATH11K_TM_ATTR_INVALID = 0,
|
||||||
|
@@ -47,4 +49,18 @@ enum ath11k_tm_cmd {
|
||||||
|
* ATH11K_TM_ATTR_DATA.
|
||||||
|
*/
|
||||||
|
ATH11K_TM_CMD_WMI = 1,
|
||||||
|
+
|
||||||
|
+ /* Boots the UTF firmware, the netdev interface must be down at the
|
||||||
|
+ * time.
|
||||||
|
+ */
|
||||||
|
+ ATH11K_TM_CMD_TESTMODE_START = 2,
|
||||||
|
+
|
||||||
|
+ /* The command used to transmit a FTM WMI command to the firmware
|
||||||
|
+ * and the event to receive WMI events from the firmware. The data
|
||||||
|
+ * received only contain the payload, need to add the tlv header
|
||||||
|
+ * and send the cmd to firmware with command id WMI_PDEV_UTF_CMDID.
|
||||||
|
+ * The data payload size could be large and the driver needs to
|
||||||
|
+ * send segmented data to firmware.
|
||||||
|
+ */
|
||||||
|
+ ATH11K_TM_CMD_WMI_FTM = 3,
|
||||||
|
};
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||||
|
- * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
+ * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
|
@@ -19,6 +19,7 @@
|
||||||
|
#include "mac.h"
|
||||||
|
#include "hw.h"
|
||||||
|
#include "peer.h"
|
||||||
|
+#include "testmode.h"
|
||||||
|
|
||||||
|
struct wmi_tlv_policy {
|
||||||
|
size_t min_len;
|
||||||
|
@@ -237,9 +238,8 @@ static int ath11k_wmi_tlv_parse(struct a
|
||||||
|
(void *)tb);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static const void **
|
||||||
|
-ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr,
|
||||||
|
- size_t len, gfp_t gfp)
|
||||||
|
+const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr,
|
||||||
|
+ size_t len, gfp_t gfp)
|
||||||
|
{
|
||||||
|
const void **tb;
|
||||||
|
int ret;
|
||||||
|
@@ -8628,6 +8628,9 @@ static void ath11k_wmi_tlv_op_rx(struct
|
||||||
|
case WMI_PDEV_CSA_SWITCH_COUNT_STATUS_EVENTID:
|
||||||
|
ath11k_wmi_pdev_csa_switch_count_status_event(ab, skb);
|
||||||
|
break;
|
||||||
|
+ case WMI_PDEV_UTF_EVENTID:
|
||||||
|
+ ath11k_tm_wmi_event(ab, id, skb);
|
||||||
|
+ break;
|
||||||
|
case WMI_PDEV_TEMPERATURE_EVENTID:
|
||||||
|
ath11k_wmi_pdev_temperature_event(ab, skb);
|
||||||
|
break;
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/wmi.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
|
||||||
|
@@ -1,6 +1,7 @@
|
||||||
|
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||||
|
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ATH11K_WMI_H
|
||||||
|
@@ -68,6 +69,7 @@ struct wmi_tlv {
|
||||||
|
|
||||||
|
#define WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG 1
|
||||||
|
|
||||||
|
+#define MAX_WMI_UTF_LEN 252
|
||||||
|
#define WMI_BA_MODE_BUFFER_SIZE_256 3
|
||||||
|
/*
|
||||||
|
* HW mode config type replicated from FW header
|
||||||
|
@@ -3564,6 +3566,24 @@ struct wmi_get_pdev_temperature_cmd {
|
||||||
|
u32 pdev_id;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
+struct wmi_ftm_seg_hdr {
|
||||||
|
+ u32 len;
|
||||||
|
+ u32 msgref;
|
||||||
|
+ u32 segmentinfo;
|
||||||
|
+ u32 pdev_id;
|
||||||
|
+} __packed;
|
||||||
|
+
|
||||||
|
+struct wmi_ftm_cmd {
|
||||||
|
+ u32 tlv_header;
|
||||||
|
+ struct wmi_ftm_seg_hdr seg_hdr;
|
||||||
|
+ u8 data[];
|
||||||
|
+} __packed;
|
||||||
|
+
|
||||||
|
+struct wmi_ftm_event_msg {
|
||||||
|
+ struct wmi_ftm_seg_hdr seg_hdr;
|
||||||
|
+ u8 data[];
|
||||||
|
+} __packed;
|
||||||
|
+
|
||||||
|
#define WMI_BEACON_TX_BUFFER_SIZE 512
|
||||||
|
|
||||||
|
#define WMI_EMA_TMPL_IDX_SHIFT 8
|
||||||
|
@@ -6300,6 +6320,8 @@ enum wmi_sta_keepalive_method {
|
||||||
|
#define WMI_STA_KEEPALIVE_INTERVAL_DEFAULT 30
|
||||||
|
#define WMI_STA_KEEPALIVE_INTERVAL_DISABLE 0
|
||||||
|
|
||||||
|
+const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr,
|
||||||
|
+ size_t len, gfp_t gfp);
|
||||||
|
int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
|
||||||
|
u32 cmd_id);
|
||||||
|
struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len);
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/wow.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/wow.c
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
|
||||||
|
- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
|
@@ -838,6 +838,7 @@ exit:
|
||||||
|
case ATH11K_STATE_RESTARTING:
|
||||||
|
case ATH11K_STATE_RESTARTED:
|
||||||
|
case ATH11K_STATE_WEDGED:
|
||||||
|
+ case ATH11K_STATE_FTM:
|
||||||
|
ath11k_warn(ar->ab, "encountered unexpected device state %d on resume, cannot recover\n",
|
||||||
|
ar->state);
|
||||||
|
ret = -EIO;
|
|
@ -0,0 +1,47 @@
|
||||||
|
From 8aeba427296bff6a6051686f1d139c89a0b00e4c Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>
|
||||||
|
Date: Fri, 26 May 2023 12:41:07 +0300
|
||||||
|
Subject: [PATCH 84/84] wifi: ath11k: Allow ath11k to boot without caldata in
|
||||||
|
ftm mode
|
||||||
|
|
||||||
|
Currently, if ath11k is unable to load the calibration data file it will
|
||||||
|
always exit. However the calibration data may not be present in factory
|
||||||
|
test mode, so update the logic to allow the driver to execute in FTM mode
|
||||||
|
even if downloading the calibration data fails.
|
||||||
|
|
||||||
|
Tested-on : IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
||||||
|
|
||||||
|
Signed-off-by: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>
|
||||||
|
Signed-off-by: Raj Kumar Bhagat <quic_rajkbhag@quicinc.com>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230517135934.16408-5-quic_rajkbhag@quicinc.com
|
||||||
|
---
|
||||||
|
drivers/net/wireless/ath/ath11k/qmi.c | 10 +++++++++-
|
||||||
|
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/qmi.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||||
|
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/elf.h>
|
||||||
|
@@ -2460,6 +2460,14 @@ static int ath11k_qmi_load_bdf_qmi(struc
|
||||||
|
|
||||||
|
fw_entry = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_CAL_FILE);
|
||||||
|
if (IS_ERR(fw_entry)) {
|
||||||
|
+ /* Caldata may not be present during first time calibration in
|
||||||
|
+ * factory hence allow to boot without loading caldata in ftm mode
|
||||||
|
+ */
|
||||||
|
+ if (ath11k_ftm_mode) {
|
||||||
|
+ ath11k_info(ab,
|
||||||
|
+ "Booting without cal data file in factory test mode\n");
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
ret = PTR_ERR(fw_entry);
|
||||||
|
ath11k_warn(ab,
|
||||||
|
"qmi failed to load CAL data file:%s\n",
|
|
@ -0,0 +1,261 @@
|
||||||
|
From 2d4f9093e2d8531ad0a2bb98fe5b36dc8addf2a2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Nidhi Jain <quic_nidhjain@quicinc.com>
|
||||||
|
Date: Fri, 26 May 2023 12:41:07 +0300
|
||||||
|
Subject: [PATCH] wifi: ath11k: Add HTT stats for PHY reset case
|
||||||
|
|
||||||
|
New HTT stats are added with stats type 37 to
|
||||||
|
provide PHY reset stats and PHY reset counter stats.
|
||||||
|
|
||||||
|
PHY reset stats are used to display the current
|
||||||
|
PHY-related operation information such as band, CCA
|
||||||
|
threshold, current operating channel etc.,
|
||||||
|
|
||||||
|
PHY reset counter stats are used to display the
|
||||||
|
PHY reset counter values like calibration counts,
|
||||||
|
temperature based recalibration counts etc.,
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
echo 37 > /sys/kernel/debug/ieee80211/phyX/ath11k/htt_stats_type
|
||||||
|
cat /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
HTT_PHY_RESET_STATS_TLV:
|
||||||
|
pdev_id = 0
|
||||||
|
chan_mhz = 5180
|
||||||
|
chan_band_center_freq1 = 5210
|
||||||
|
chan_band_center_freq2 = 0
|
||||||
|
chan_phy_mode = 18
|
||||||
|
chan_flags = 0x8
|
||||||
|
chan_num = 36
|
||||||
|
reset_cause = 0x50000
|
||||||
|
prev_reset_cause = 0x50000
|
||||||
|
phy_warm_reset_src = 0x0
|
||||||
|
rx_gain_tbl_mode = 0
|
||||||
|
xbar_val = 0xfac688
|
||||||
|
force_calibration = 0
|
||||||
|
phyrf_mode = 0
|
||||||
|
phy_homechan = 0
|
||||||
|
phy_tx_ch_mask = 0x3
|
||||||
|
phy_rx_ch_mask = 0x3
|
||||||
|
phybb_ini_mask = 0x5
|
||||||
|
phyrf_ini_mask = 0x0
|
||||||
|
phy_dfs_en_mask = 0x0
|
||||||
|
phy_sscan_en_mask = 0x0
|
||||||
|
phy_synth_sel_mask = 0x0
|
||||||
|
phy_adfs_freq = 0
|
||||||
|
cck_fir_settings = 0x0
|
||||||
|
phy_dyn_pri_chan = 6
|
||||||
|
cca_thresh = 0x26232020
|
||||||
|
dyn_cca_status = 0
|
||||||
|
rxdesense_thresh_hw = 0xcfe0afe
|
||||||
|
rxdesense_thresh_sw = 0xcfe0afe
|
||||||
|
|
||||||
|
HTT_PHY_RESET_COUNTERS_TLV:
|
||||||
|
pdev_id = 0
|
||||||
|
cf_active_low_fail_cnt = 0
|
||||||
|
cf_active_low_pass_cnt = 0
|
||||||
|
phy_off_through_vreg_cnt = 0
|
||||||
|
force_calibration_cnt = 0
|
||||||
|
rf_mode_switch_phy_off_cnt = 0
|
||||||
|
|
||||||
|
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
||||||
|
|
||||||
|
Signed-off-by: Nidhi Jain <quic_nidhjain@quicinc.com>
|
||||||
|
Signed-off-by: Maharaja Kennadyrajan <quic_mkenna@quicinc.com>
|
||||||
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230517141242.2754293-1-quic_mkenna@quicinc.com
|
||||||
|
---
|
||||||
|
.../wireless/ath/ath11k/debugfs_htt_stats.c | 114 ++++++++++++++++++
|
||||||
|
.../wireless/ath/ath11k/debugfs_htt_stats.h | 43 +++++++
|
||||||
|
2 files changed, 157 insertions(+)
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
|
||||||
|
@@ -4011,6 +4011,114 @@ void htt_print_phy_stats_tlv(const void
|
||||||
|
stats_req->buf_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static inline void
|
||||||
|
+htt_print_phy_reset_counters_tlv(const void *tag_buf,
|
||||||
|
+ u16 tag_len,
|
||||||
|
+ struct debug_htt_stats_req *stats_req)
|
||||||
|
+{
|
||||||
|
+ const struct htt_phy_reset_counters_tlv *htt_stats_buf = tag_buf;
|
||||||
|
+ u8 *buf = stats_req->buf;
|
||||||
|
+ u32 len = stats_req->buf_len;
|
||||||
|
+ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
|
||||||
|
+
|
||||||
|
+ if (tag_len < sizeof(*htt_stats_buf))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "HTT_PHY_RESET_COUNTERS_TLV:\n");
|
||||||
|
+
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n",
|
||||||
|
+ htt_stats_buf->pdev_id);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "cf_active_low_fail_cnt = %u\n",
|
||||||
|
+ htt_stats_buf->cf_active_low_fail_cnt);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "cf_active_low_pass_cnt = %u\n",
|
||||||
|
+ htt_stats_buf->cf_active_low_pass_cnt);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "phy_off_through_vreg_cnt = %u\n",
|
||||||
|
+ htt_stats_buf->phy_off_through_vreg_cnt);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "force_calibration_cnt = %u\n",
|
||||||
|
+ htt_stats_buf->force_calibration_cnt);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "rf_mode_switch_phy_off_cnt = %u\n",
|
||||||
|
+ htt_stats_buf->rf_mode_switch_phy_off_cnt);
|
||||||
|
+
|
||||||
|
+ stats_req->buf_len = len;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void
|
||||||
|
+htt_print_phy_reset_stats_tlv(const void *tag_buf,
|
||||||
|
+ u16 tag_len,
|
||||||
|
+ struct debug_htt_stats_req *stats_req)
|
||||||
|
+{
|
||||||
|
+ const struct htt_phy_reset_stats_tlv *htt_stats_buf = tag_buf;
|
||||||
|
+ u8 *buf = stats_req->buf;
|
||||||
|
+ u32 len = stats_req->buf_len;
|
||||||
|
+ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
|
||||||
|
+
|
||||||
|
+ if (tag_len < sizeof(*htt_stats_buf))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "HTT_PHY_RESET_STATS_TLV:\n");
|
||||||
|
+
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n",
|
||||||
|
+ htt_stats_buf->pdev_id);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "chan_mhz = %u\n",
|
||||||
|
+ htt_stats_buf->chan_mhz);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "chan_band_center_freq1 = %u\n",
|
||||||
|
+ htt_stats_buf->chan_band_center_freq1);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "chan_band_center_freq2 = %u\n",
|
||||||
|
+ htt_stats_buf->chan_band_center_freq2);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "chan_phy_mode = %u\n",
|
||||||
|
+ htt_stats_buf->chan_phy_mode);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "chan_flags = 0x%0x\n",
|
||||||
|
+ htt_stats_buf->chan_flags);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "chan_num = %u\n",
|
||||||
|
+ htt_stats_buf->chan_num);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "reset_cause = 0x%0x\n",
|
||||||
|
+ htt_stats_buf->reset_cause);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "prev_reset_cause = 0x%0x\n",
|
||||||
|
+ htt_stats_buf->prev_reset_cause);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "phy_warm_reset_src = 0x%0x\n",
|
||||||
|
+ htt_stats_buf->phy_warm_reset_src);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "rx_gain_tbl_mode = %d\n",
|
||||||
|
+ htt_stats_buf->rx_gain_tbl_mode);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "xbar_val = 0x%0x\n",
|
||||||
|
+ htt_stats_buf->xbar_val);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "force_calibration = %u\n",
|
||||||
|
+ htt_stats_buf->force_calibration);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "phyrf_mode = %u\n",
|
||||||
|
+ htt_stats_buf->phyrf_mode);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "phy_homechan = %u\n",
|
||||||
|
+ htt_stats_buf->phy_homechan);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "phy_tx_ch_mask = 0x%0x\n",
|
||||||
|
+ htt_stats_buf->phy_tx_ch_mask);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "phy_rx_ch_mask = 0x%0x\n",
|
||||||
|
+ htt_stats_buf->phy_rx_ch_mask);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "phybb_ini_mask = 0x%0x\n",
|
||||||
|
+ htt_stats_buf->phybb_ini_mask);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "phyrf_ini_mask = 0x%0x\n",
|
||||||
|
+ htt_stats_buf->phyrf_ini_mask);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "phy_dfs_en_mask = 0x%0x\n",
|
||||||
|
+ htt_stats_buf->phy_dfs_en_mask);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "phy_sscan_en_mask = 0x%0x\n",
|
||||||
|
+ htt_stats_buf->phy_sscan_en_mask);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "phy_synth_sel_mask = 0x%0x\n",
|
||||||
|
+ htt_stats_buf->phy_synth_sel_mask);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "phy_adfs_freq = %u\n",
|
||||||
|
+ htt_stats_buf->phy_adfs_freq);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "cck_fir_settings = 0x%0x\n",
|
||||||
|
+ htt_stats_buf->cck_fir_settings);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "phy_dyn_pri_chan = %u\n",
|
||||||
|
+ htt_stats_buf->phy_dyn_pri_chan);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "cca_thresh = 0x%0x\n",
|
||||||
|
+ htt_stats_buf->cca_thresh);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "dyn_cca_status = %u\n",
|
||||||
|
+ htt_stats_buf->dyn_cca_status);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "rxdesense_thresh_hw = 0x%x\n",
|
||||||
|
+ htt_stats_buf->rxdesense_thresh_hw);
|
||||||
|
+ len += scnprintf(buf + len, buf_len - len, "rxdesense_thresh_sw = 0x%x\n",
|
||||||
|
+ htt_stats_buf->rxdesense_thresh_sw);
|
||||||
|
+
|
||||||
|
+ stats_req->buf_len = len;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static inline
|
||||||
|
void htt_print_peer_ctrl_path_txrx_stats_tlv(const void *tag_buf,
|
||||||
|
struct debug_htt_stats_req *stats_req)
|
||||||
|
@@ -4425,6 +4533,12 @@ static int ath11k_dbg_htt_ext_stats_pars
|
||||||
|
case HTT_STATS_PHY_STATS_TAG:
|
||||||
|
htt_print_phy_stats_tlv(tag_buf, stats_req);
|
||||||
|
break;
|
||||||
|
+ case HTT_STATS_PHY_RESET_COUNTERS_TAG:
|
||||||
|
+ htt_print_phy_reset_counters_tlv(tag_buf, len, stats_req);
|
||||||
|
+ break;
|
||||||
|
+ case HTT_STATS_PHY_RESET_STATS_TAG:
|
||||||
|
+ htt_print_phy_reset_stats_tlv(tag_buf, len, stats_req);
|
||||||
|
+ break;
|
||||||
|
case HTT_STATS_PEER_CTRL_PATH_TXRX_STATS_TAG:
|
||||||
|
htt_print_peer_ctrl_path_txrx_stats_tlv(tag_buf, stats_req);
|
||||||
|
break;
|
||||||
|
--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h
|
||||||
|
@@ -111,6 +111,8 @@ enum htt_tlv_tag_t {
|
||||||
|
HTT_STATS_TXBF_OFDMA_STEER_STATS_TAG = 116,
|
||||||
|
HTT_STATS_PHY_COUNTERS_TAG = 121,
|
||||||
|
HTT_STATS_PHY_STATS_TAG = 122,
|
||||||
|
+ HTT_STATS_PHY_RESET_COUNTERS_TAG = 123,
|
||||||
|
+ HTT_STATS_PHY_RESET_STATS_TAG = 124,
|
||||||
|
|
||||||
|
HTT_STATS_MAX_TAG,
|
||||||
|
};
|
||||||
|
@@ -1964,6 +1966,47 @@ struct htt_phy_stats_tlv {
|
||||||
|
u32 fw_run_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
+struct htt_phy_reset_counters_tlv {
|
||||||
|
+ u32 pdev_id;
|
||||||
|
+ u32 cf_active_low_fail_cnt;
|
||||||
|
+ u32 cf_active_low_pass_cnt;
|
||||||
|
+ u32 phy_off_through_vreg_cnt;
|
||||||
|
+ u32 force_calibration_cnt;
|
||||||
|
+ u32 rf_mode_switch_phy_off_cnt;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct htt_phy_reset_stats_tlv {
|
||||||
|
+ u32 pdev_id;
|
||||||
|
+ u32 chan_mhz;
|
||||||
|
+ u32 chan_band_center_freq1;
|
||||||
|
+ u32 chan_band_center_freq2;
|
||||||
|
+ u32 chan_phy_mode;
|
||||||
|
+ u32 chan_flags;
|
||||||
|
+ u32 chan_num;
|
||||||
|
+ u32 reset_cause;
|
||||||
|
+ u32 prev_reset_cause;
|
||||||
|
+ u32 phy_warm_reset_src;
|
||||||
|
+ u32 rx_gain_tbl_mode;
|
||||||
|
+ u32 xbar_val;
|
||||||
|
+ u32 force_calibration;
|
||||||
|
+ u32 phyrf_mode;
|
||||||
|
+ u32 phy_homechan;
|
||||||
|
+ u32 phy_tx_ch_mask;
|
||||||
|
+ u32 phy_rx_ch_mask;
|
||||||
|
+ u32 phybb_ini_mask;
|
||||||
|
+ u32 phyrf_ini_mask;
|
||||||
|
+ u32 phy_dfs_en_mask;
|
||||||
|
+ u32 phy_sscan_en_mask;
|
||||||
|
+ u32 phy_synth_sel_mask;
|
||||||
|
+ u32 phy_adfs_freq;
|
||||||
|
+ u32 cck_fir_settings;
|
||||||
|
+ u32 phy_dyn_pri_chan;
|
||||||
|
+ u32 cca_thresh;
|
||||||
|
+ u32 dyn_cca_status;
|
||||||
|
+ u32 rxdesense_thresh_hw;
|
||||||
|
+ u32 rxdesense_thresh_sw;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
struct htt_peer_ctrl_path_txrx_stats_tlv {
|
||||||
|
/* peer mac address */
|
||||||
|
u8 peer_mac_addr[ETH_ALEN];
|
|
@ -13,7 +13,7 @@ Signed-off-by: Robert Marko <robimarko@gmail.com>
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath11k/core.c
|
--- a/drivers/net/wireless/ath/ath11k/core.c
|
||||||
+++ b/drivers/net/wireless/ath/ath11k/core.c
|
+++ b/drivers/net/wireless/ath/ath11k/core.c
|
||||||
@@ -82,7 +82,7 @@ static const struct ath11k_hw_params ath
|
@@ -86,7 +86,7 @@ static const struct ath11k_hw_params ath
|
||||||
.supports_shadow_regs = false,
|
.supports_shadow_regs = false,
|
||||||
.idle_ps = false,
|
.idle_ps = false,
|
||||||
.supports_sta_ps = false,
|
.supports_sta_ps = false,
|
||||||
|
|
|
@ -22,16 +22,16 @@ Signed-off-by: Robert Marko <robimarko@gmail.com>
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath11k/core.c
|
--- a/drivers/net/wireless/ath/ath11k/core.c
|
||||||
+++ b/drivers/net/wireless/ath/ath11k/core.c
|
+++ b/drivers/net/wireless/ath/ath11k/core.c
|
||||||
@@ -32,7 +32,7 @@ module_param_named(frame_mode, ath11k_fr
|
@@ -36,7 +36,7 @@ bool ath11k_ftm_mode;
|
||||||
MODULE_PARM_DESC(frame_mode,
|
module_param_named(ftm_mode, ath11k_ftm_mode, bool, 0444);
|
||||||
"Datapath frame mode (0: raw, 1: native wifi (default), 2: ethernet)");
|
MODULE_PARM_DESC(ftm_mode, "Boots up in factory test mode");
|
||||||
|
|
||||||
-static const struct ath11k_hw_params ath11k_hw_params[] = {
|
-static const struct ath11k_hw_params ath11k_hw_params[] = {
|
||||||
+static struct ath11k_hw_params ath11k_hw_params[] = {
|
+static struct ath11k_hw_params ath11k_hw_params[] = {
|
||||||
{
|
{
|
||||||
.hw_rev = ATH11K_HW_IPQ8074,
|
.hw_rev = ATH11K_HW_IPQ8074,
|
||||||
.name = "ipq8074 hw2.0",
|
.name = "ipq8074 hw2.0",
|
||||||
@@ -1911,7 +1911,8 @@ static void ath11k_core_reset(struct wor
|
@@ -1953,7 +1953,8 @@ static void ath11k_core_reset(struct wor
|
||||||
static int ath11k_init_hw_params(struct ath11k_base *ab)
|
static int ath11k_init_hw_params(struct ath11k_base *ab)
|
||||||
{
|
{
|
||||||
const struct ath11k_hw_params *hw_params = NULL;
|
const struct ath11k_hw_params *hw_params = NULL;
|
||||||
|
@ -41,7 +41,7 @@ Signed-off-by: Robert Marko <robimarko@gmail.com>
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(ath11k_hw_params); i++) {
|
for (i = 0; i < ARRAY_SIZE(ath11k_hw_params); i++) {
|
||||||
hw_params = &ath11k_hw_params[i];
|
hw_params = &ath11k_hw_params[i];
|
||||||
@@ -1927,7 +1928,30 @@ static int ath11k_init_hw_params(struct
|
@@ -1969,7 +1970,30 @@ static int ath11k_init_hw_params(struct
|
||||||
|
|
||||||
ab->hw_params = *hw_params;
|
ab->hw_params = *hw_params;
|
||||||
|
|
||||||
|
|
|
@ -271,7 +271,7 @@ Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||||
#endif
|
#endif
|
||||||
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
||||||
@@ -6980,24 +6980,12 @@ static void ath11k_wmi_htc_tx_complete(s
|
@@ -6996,24 +6996,12 @@ static void ath11k_wmi_htc_tx_complete(s
|
||||||
wake_up(&wmi->tx_ce_desc_wq);
|
wake_up(&wmi->tx_ce_desc_wq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,7 +296,7 @@ Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||||||
int ret = 0, pdev_idx, i, j;
|
int ret = 0, pdev_idx, i, j;
|
||||||
struct ath11k *ar;
|
struct ath11k *ar;
|
||||||
|
|
||||||
@@ -7059,17 +7047,7 @@ static int ath11k_reg_chan_list_event(st
|
@@ -7075,17 +7063,7 @@ static int ath11k_reg_chan_list_event(st
|
||||||
(char *)reg_info->alpha2, 2))
|
(char *)reg_info->alpha2, 2))
|
||||||
goto mem_free;
|
goto mem_free;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,372 @@
|
||||||
|
From bd54f3c29077f23dad92ef82a78061b40be30c65 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Date: Mon, 5 Dec 2022 16:50:37 -0800
|
||||||
|
Subject: [PATCH] wifi: mac80211: generate EMA beacons in AP mode
|
||||||
|
|
||||||
|
Add APIs to generate an array of beacons for an EMA AP (enhanced
|
||||||
|
multiple BSSID advertisements), each including a single MBSSID element.
|
||||||
|
EMA profile periodicity equals the count of elements.
|
||||||
|
|
||||||
|
- ieee80211_beacon_get_template_ema_list() - Generate and return all
|
||||||
|
EMA beacon templates. Drivers must call ieee80211_beacon_free_ema_list()
|
||||||
|
to free the memory. No change in the prototype for the existing API,
|
||||||
|
ieee80211_beacon_get_template(), which should be used for non-EMA AP.
|
||||||
|
|
||||||
|
- ieee80211_beacon_get_template_ema_index() - Generate a beacon which
|
||||||
|
includes the multiple BSSID element at the given index. Drivers can use
|
||||||
|
this function in a loop until NULL is returned which indicates end of
|
||||||
|
available MBSSID elements.
|
||||||
|
|
||||||
|
- ieee80211_beacon_free_ema_list() - free the memory allocated for the
|
||||||
|
list of EMA beacon templates.
|
||||||
|
|
||||||
|
Modify existing functions ieee80211_beacon_get_ap(),
|
||||||
|
ieee80211_get_mbssid_beacon_len() and ieee80211_beacon_add_mbssid()
|
||||||
|
to accept a new parameter for EMA index.
|
||||||
|
|
||||||
|
Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
|
||||||
|
Co-developed-by: John Crispin <john@phrozen.org>
|
||||||
|
Signed-off-by: John Crispin <john@phrozen.org>
|
||||||
|
Link: https://lore.kernel.org/r/20221206005040.3177-2-quic_alokad@quicinc.com
|
||||||
|
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||||
|
---
|
||||||
|
include/net/mac80211.h | 68 +++++++++++++++++++
|
||||||
|
net/mac80211/cfg.c | 11 +--
|
||||||
|
net/mac80211/ieee80211_i.h | 10 ++-
|
||||||
|
net/mac80211/tx.c | 134 ++++++++++++++++++++++++++++++++++---
|
||||||
|
4 files changed, 205 insertions(+), 18 deletions(-)
|
||||||
|
|
||||||
|
--- a/include/net/mac80211.h
|
||||||
|
+++ b/include/net/mac80211.h
|
||||||
|
@@ -5252,6 +5252,74 @@ ieee80211_beacon_get_template(struct iee
|
||||||
|
unsigned int link_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
+ * ieee80211_beacon_get_template_ema_index - EMA beacon template generation
|
||||||
|
+ * @hw: pointer obtained from ieee80211_alloc_hw().
|
||||||
|
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||||
|
+ * @offs: &struct ieee80211_mutable_offsets pointer to struct that will
|
||||||
|
+ * receive the offsets that may be updated by the driver.
|
||||||
|
+ * @link_id: the link id to which the beacon belongs (or 0 for a non-MLD AP).
|
||||||
|
+ * @ema_index: index of the beacon in the EMA set.
|
||||||
|
+ *
|
||||||
|
+ * This function follows the same rules as ieee80211_beacon_get_template()
|
||||||
|
+ * but returns a beacon template which includes multiple BSSID element at the
|
||||||
|
+ * requested index.
|
||||||
|
+ *
|
||||||
|
+ * Return: The beacon template. %NULL indicates the end of EMA templates.
|
||||||
|
+ */
|
||||||
|
+struct sk_buff *
|
||||||
|
+ieee80211_beacon_get_template_ema_index(struct ieee80211_hw *hw,
|
||||||
|
+ struct ieee80211_vif *vif,
|
||||||
|
+ struct ieee80211_mutable_offsets *offs,
|
||||||
|
+ unsigned int link_id, u8 ema_index);
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * struct ieee80211_ema_beacons - List of EMA beacons
|
||||||
|
+ * @cnt: count of EMA beacons.
|
||||||
|
+ *
|
||||||
|
+ * @bcn: array of EMA beacons.
|
||||||
|
+ * @bcn.skb: the skb containing this specific beacon
|
||||||
|
+ * @bcn.offs: &struct ieee80211_mutable_offsets pointer to struct that will
|
||||||
|
+ * receive the offsets that may be updated by the driver.
|
||||||
|
+ */
|
||||||
|
+struct ieee80211_ema_beacons {
|
||||||
|
+ u8 cnt;
|
||||||
|
+ struct {
|
||||||
|
+ struct sk_buff *skb;
|
||||||
|
+ struct ieee80211_mutable_offsets offs;
|
||||||
|
+ } bcn[];
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * ieee80211_beacon_get_template_ema_list - EMA beacon template generation
|
||||||
|
+ * @hw: pointer obtained from ieee80211_alloc_hw().
|
||||||
|
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||||
|
+ * @link_id: the link id to which the beacon belongs (or 0 for a non-MLD AP)
|
||||||
|
+ *
|
||||||
|
+ * This function follows the same rules as ieee80211_beacon_get_template()
|
||||||
|
+ * but allocates and returns a pointer to list of all beacon templates required
|
||||||
|
+ * to cover all profiles in the multiple BSSID set. Each template includes only
|
||||||
|
+ * one multiple BSSID element.
|
||||||
|
+ *
|
||||||
|
+ * Driver must call ieee80211_beacon_free_ema_list() to free the memory.
|
||||||
|
+ *
|
||||||
|
+ * Return: EMA beacon templates of type struct ieee80211_ema_beacons *.
|
||||||
|
+ * %NULL on error.
|
||||||
|
+ */
|
||||||
|
+struct ieee80211_ema_beacons *
|
||||||
|
+ieee80211_beacon_get_template_ema_list(struct ieee80211_hw *hw,
|
||||||
|
+ struct ieee80211_vif *vif,
|
||||||
|
+ unsigned int link_id);
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * ieee80211_beacon_free_ema_list - free an EMA beacon template list
|
||||||
|
+ * @ema_beacons: list of EMA beacons of type &struct ieee80211_ema_beacons pointers.
|
||||||
|
+ *
|
||||||
|
+ * This function will free a list previously acquired by calling
|
||||||
|
+ * ieee80211_beacon_get_template_ema_list()
|
||||||
|
+ */
|
||||||
|
+void ieee80211_beacon_free_ema_list(struct ieee80211_ema_beacons *ema_beacons);
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
* ieee80211_beacon_get_tim - beacon generation function
|
||||||
|
* @hw: pointer obtained from ieee80211_alloc_hw().
|
||||||
|
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||||
|
--- a/net/mac80211/cfg.c
|
||||||
|
+++ b/net/mac80211/cfg.c
|
||||||
|
@@ -1122,11 +1122,11 @@ static int ieee80211_assign_beacon(struc
|
||||||
|
if (params->mbssid_ies) {
|
||||||
|
mbssid = params->mbssid_ies;
|
||||||
|
size += struct_size(new->mbssid_ies, elem, mbssid->cnt);
|
||||||
|
- size += ieee80211_get_mbssid_beacon_len(mbssid);
|
||||||
|
+ size += ieee80211_get_mbssid_beacon_len(mbssid, mbssid->cnt);
|
||||||
|
} else if (old && old->mbssid_ies) {
|
||||||
|
mbssid = old->mbssid_ies;
|
||||||
|
size += struct_size(new->mbssid_ies, elem, mbssid->cnt);
|
||||||
|
- size += ieee80211_get_mbssid_beacon_len(mbssid);
|
||||||
|
+ size += ieee80211_get_mbssid_beacon_len(mbssid, mbssid->cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
new = kzalloc(size, GFP_KERNEL);
|
||||||
|
@@ -3384,8 +3384,11 @@ cfg80211_beacon_dup(struct cfg80211_beac
|
||||||
|
|
||||||
|
len = beacon->head_len + beacon->tail_len + beacon->beacon_ies_len +
|
||||||
|
beacon->proberesp_ies_len + beacon->assocresp_ies_len +
|
||||||
|
- beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len +
|
||||||
|
- ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies);
|
||||||
|
+ beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len;
|
||||||
|
+
|
||||||
|
+ if (beacon->mbssid_ies)
|
||||||
|
+ len += ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies,
|
||||||
|
+ beacon->mbssid_ies->cnt);
|
||||||
|
|
||||||
|
new_beacon = kzalloc(sizeof(*new_beacon) + len, GFP_KERNEL);
|
||||||
|
if (!new_beacon)
|
||||||
|
--- a/net/mac80211/ieee80211_i.h
|
||||||
|
+++ b/net/mac80211/ieee80211_i.h
|
||||||
|
@@ -1182,13 +1182,17 @@ ieee80211_vif_get_shift(struct ieee80211
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
-ieee80211_get_mbssid_beacon_len(struct cfg80211_mbssid_elems *elems)
|
||||||
|
+ieee80211_get_mbssid_beacon_len(struct cfg80211_mbssid_elems *elems, u8 i)
|
||||||
|
{
|
||||||
|
- int i, len = 0;
|
||||||
|
+ int len = 0;
|
||||||
|
|
||||||
|
- if (!elems)
|
||||||
|
+ if (!elems || !elems->cnt || i > elems->cnt)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
+ if (i < elems->cnt)
|
||||||
|
+ return elems->elem[i].len;
|
||||||
|
+
|
||||||
|
+ /* i == elems->cnt, calculate total length of all MBSSID elements */
|
||||||
|
for (i = 0; i < elems->cnt; i++)
|
||||||
|
len += elems->elem[i].len;
|
||||||
|
|
||||||
|
--- a/net/mac80211/tx.c
|
||||||
|
+++ b/net/mac80211/tx.c
|
||||||
|
@@ -5205,13 +5205,20 @@ ieee80211_beacon_get_finish(struct ieee8
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
-ieee80211_beacon_add_mbssid(struct sk_buff *skb, struct beacon_data *beacon)
|
||||||
|
+ieee80211_beacon_add_mbssid(struct sk_buff *skb, struct beacon_data *beacon,
|
||||||
|
+ u8 i)
|
||||||
|
{
|
||||||
|
- int i;
|
||||||
|
+ if (!beacon->mbssid_ies || !beacon->mbssid_ies->cnt ||
|
||||||
|
+ i > beacon->mbssid_ies->cnt)
|
||||||
|
+ return;
|
||||||
|
|
||||||
|
- if (!beacon->mbssid_ies)
|
||||||
|
+ if (i < beacon->mbssid_ies->cnt) {
|
||||||
|
+ skb_put_data(skb, beacon->mbssid_ies->elem[i].data,
|
||||||
|
+ beacon->mbssid_ies->elem[i].len);
|
||||||
|
return;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
+ /* i == beacon->mbssid_ies->cnt, include all MBSSID elements */
|
||||||
|
for (i = 0; i < beacon->mbssid_ies->cnt; i++)
|
||||||
|
skb_put_data(skb, beacon->mbssid_ies->elem[i].data,
|
||||||
|
beacon->mbssid_ies->elem[i].len);
|
||||||
|
@@ -5224,7 +5231,8 @@ ieee80211_beacon_get_ap(struct ieee80211
|
||||||
|
struct ieee80211_mutable_offsets *offs,
|
||||||
|
bool is_template,
|
||||||
|
struct beacon_data *beacon,
|
||||||
|
- struct ieee80211_chanctx_conf *chanctx_conf)
|
||||||
|
+ struct ieee80211_chanctx_conf *chanctx_conf,
|
||||||
|
+ u8 ema_index)
|
||||||
|
{
|
||||||
|
struct ieee80211_local *local = hw_to_local(hw);
|
||||||
|
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||||
|
@@ -5243,7 +5251,9 @@ ieee80211_beacon_get_ap(struct ieee80211
|
||||||
|
/* headroom, head length,
|
||||||
|
* tail length, maximum TIM length and multiple BSSID length
|
||||||
|
*/
|
||||||
|
- mbssid_len = ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies);
|
||||||
|
+ mbssid_len = ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies,
|
||||||
|
+ ema_index);
|
||||||
|
+
|
||||||
|
skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
|
||||||
|
beacon->tail_len + 256 +
|
||||||
|
local->hw.extra_beacon_tailroom + mbssid_len);
|
||||||
|
@@ -5261,7 +5271,7 @@ ieee80211_beacon_get_ap(struct ieee80211
|
||||||
|
offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0];
|
||||||
|
|
||||||
|
if (mbssid_len) {
|
||||||
|
- ieee80211_beacon_add_mbssid(skb, beacon);
|
||||||
|
+ ieee80211_beacon_add_mbssid(skb, beacon, ema_index);
|
||||||
|
offs->mbssid_off = skb->len - mbssid_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -5280,12 +5290,51 @@ ieee80211_beacon_get_ap(struct ieee80211
|
||||||
|
return skb;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static struct ieee80211_ema_beacons *
|
||||||
|
+ieee80211_beacon_get_ap_ema_list(struct ieee80211_hw *hw,
|
||||||
|
+ struct ieee80211_vif *vif,
|
||||||
|
+ struct ieee80211_link_data *link,
|
||||||
|
+ struct ieee80211_mutable_offsets *offs,
|
||||||
|
+ bool is_template, struct beacon_data *beacon,
|
||||||
|
+ struct ieee80211_chanctx_conf *chanctx_conf)
|
||||||
|
+{
|
||||||
|
+ struct ieee80211_ema_beacons *ema = NULL;
|
||||||
|
+
|
||||||
|
+ if (!beacon->mbssid_ies || !beacon->mbssid_ies->cnt)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ ema = kzalloc(struct_size(ema, bcn, beacon->mbssid_ies->cnt),
|
||||||
|
+ GFP_ATOMIC);
|
||||||
|
+ if (!ema)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ for (ema->cnt = 0; ema->cnt < beacon->mbssid_ies->cnt; ema->cnt++) {
|
||||||
|
+ ema->bcn[ema->cnt].skb =
|
||||||
|
+ ieee80211_beacon_get_ap(hw, vif, link,
|
||||||
|
+ &ema->bcn[ema->cnt].offs,
|
||||||
|
+ is_template, beacon,
|
||||||
|
+ chanctx_conf, ema->cnt);
|
||||||
|
+ if (!ema->bcn[ema->cnt].skb)
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (ema->cnt == beacon->mbssid_ies->cnt)
|
||||||
|
+ return ema;
|
||||||
|
+
|
||||||
|
+ ieee80211_beacon_free_ema_list(ema);
|
||||||
|
+ return NULL;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#define IEEE80211_INCLUDE_ALL_MBSSID_ELEMS -1
|
||||||
|
+
|
||||||
|
static struct sk_buff *
|
||||||
|
__ieee80211_beacon_get(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
|
struct ieee80211_mutable_offsets *offs,
|
||||||
|
bool is_template,
|
||||||
|
- unsigned int link_id)
|
||||||
|
+ unsigned int link_id,
|
||||||
|
+ int ema_index,
|
||||||
|
+ struct ieee80211_ema_beacons **ema_beacons)
|
||||||
|
{
|
||||||
|
struct ieee80211_local *local = hw_to_local(hw);
|
||||||
|
struct beacon_data *beacon = NULL;
|
||||||
|
@@ -5314,8 +5363,29 @@ __ieee80211_beacon_get(struct ieee80211_
|
||||||
|
if (!beacon)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
- skb = ieee80211_beacon_get_ap(hw, vif, link, offs, is_template,
|
||||||
|
- beacon, chanctx_conf);
|
||||||
|
+ if (ema_beacons) {
|
||||||
|
+ *ema_beacons =
|
||||||
|
+ ieee80211_beacon_get_ap_ema_list(hw, vif, link,
|
||||||
|
+ offs,
|
||||||
|
+ is_template,
|
||||||
|
+ beacon,
|
||||||
|
+ chanctx_conf);
|
||||||
|
+ } else {
|
||||||
|
+ if (beacon->mbssid_ies && beacon->mbssid_ies->cnt) {
|
||||||
|
+ if (ema_index >= beacon->mbssid_ies->cnt)
|
||||||
|
+ goto out; /* End of MBSSID elements */
|
||||||
|
+
|
||||||
|
+ if (ema_index <= IEEE80211_INCLUDE_ALL_MBSSID_ELEMS)
|
||||||
|
+ ema_index = beacon->mbssid_ies->cnt;
|
||||||
|
+ } else {
|
||||||
|
+ ema_index = 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ skb = ieee80211_beacon_get_ap(hw, vif, link, offs,
|
||||||
|
+ is_template, beacon,
|
||||||
|
+ chanctx_conf,
|
||||||
|
+ ema_index);
|
||||||
|
+ }
|
||||||
|
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
|
||||||
|
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||||
|
struct ieee80211_hdr *hdr;
|
||||||
|
@@ -5403,10 +5473,50 @@ ieee80211_beacon_get_template(struct iee
|
||||||
|
struct ieee80211_mutable_offsets *offs,
|
||||||
|
unsigned int link_id)
|
||||||
|
{
|
||||||
|
- return __ieee80211_beacon_get(hw, vif, offs, true, link_id);
|
||||||
|
+ return __ieee80211_beacon_get(hw, vif, offs, true, link_id,
|
||||||
|
+ IEEE80211_INCLUDE_ALL_MBSSID_ELEMS, NULL);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ieee80211_beacon_get_template);
|
||||||
|
|
||||||
|
+struct sk_buff *
|
||||||
|
+ieee80211_beacon_get_template_ema_index(struct ieee80211_hw *hw,
|
||||||
|
+ struct ieee80211_vif *vif,
|
||||||
|
+ struct ieee80211_mutable_offsets *offs,
|
||||||
|
+ unsigned int link_id, u8 ema_index)
|
||||||
|
+{
|
||||||
|
+ return __ieee80211_beacon_get(hw, vif, offs, true, link_id, ema_index,
|
||||||
|
+ NULL);
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(ieee80211_beacon_get_template_ema_index);
|
||||||
|
+
|
||||||
|
+void ieee80211_beacon_free_ema_list(struct ieee80211_ema_beacons *ema_beacons)
|
||||||
|
+{
|
||||||
|
+ u8 i;
|
||||||
|
+
|
||||||
|
+ if (!ema_beacons)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < ema_beacons->cnt; i++)
|
||||||
|
+ kfree_skb(ema_beacons->bcn[i].skb);
|
||||||
|
+
|
||||||
|
+ kfree(ema_beacons);
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(ieee80211_beacon_free_ema_list);
|
||||||
|
+
|
||||||
|
+struct ieee80211_ema_beacons *
|
||||||
|
+ieee80211_beacon_get_template_ema_list(struct ieee80211_hw *hw,
|
||||||
|
+ struct ieee80211_vif *vif,
|
||||||
|
+ unsigned int link_id)
|
||||||
|
+{
|
||||||
|
+ struct ieee80211_ema_beacons *ema_beacons = NULL;
|
||||||
|
+
|
||||||
|
+ WARN_ON(__ieee80211_beacon_get(hw, vif, NULL, false, link_id, 0,
|
||||||
|
+ &ema_beacons));
|
||||||
|
+
|
||||||
|
+ return ema_beacons;
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(ieee80211_beacon_get_template_ema_list);
|
||||||
|
+
|
||||||
|
struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
|
u16 *tim_offset, u16 *tim_length,
|
||||||
|
@@ -5414,7 +5524,9 @@ struct sk_buff *ieee80211_beacon_get_tim
|
||||||
|
{
|
||||||
|
struct ieee80211_mutable_offsets offs = {};
|
||||||
|
struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false,
|
||||||
|
- link_id);
|
||||||
|
+ link_id,
|
||||||
|
+ IEEE80211_INCLUDE_ALL_MBSSID_ELEMS,
|
||||||
|
+ NULL);
|
||||||
|
struct sk_buff *copy;
|
||||||
|
int shift;
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
static void ieee80211_rfkill_poll(struct wiphy *wiphy)
|
static void ieee80211_rfkill_poll(struct wiphy *wiphy)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||||
@@ -4953,6 +4966,7 @@ const struct cfg80211_ops mac80211_confi
|
@@ -4956,6 +4969,7 @@ const struct cfg80211_ops mac80211_confi
|
||||||
.set_wiphy_params = ieee80211_set_wiphy_params,
|
.set_wiphy_params = ieee80211_set_wiphy_params,
|
||||||
.set_tx_power = ieee80211_set_tx_power,
|
.set_tx_power = ieee80211_set_tx_power,
|
||||||
.get_tx_power = ieee80211_get_tx_power,
|
.get_tx_power = ieee80211_get_tx_power,
|
||||||
|
@ -87,7 +87,7 @@
|
||||||
CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump)
|
CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump)
|
||||||
--- a/net/mac80211/ieee80211_i.h
|
--- a/net/mac80211/ieee80211_i.h
|
||||||
+++ b/net/mac80211/ieee80211_i.h
|
+++ b/net/mac80211/ieee80211_i.h
|
||||||
@@ -1538,6 +1538,7 @@ struct ieee80211_local {
|
@@ -1542,6 +1542,7 @@ struct ieee80211_local {
|
||||||
int dynamic_ps_forced_timeout;
|
int dynamic_ps_forced_timeout;
|
||||||
|
|
||||||
int user_power_level; /* in dBm, for all interfaces */
|
int user_power_level; /* in dBm, for all interfaces */
|
||||||
|
|
|
@ -155,11 +155,12 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
|
||||||
- dp_priv->phydev = phy_connect(netdev, phy_id,
|
- dp_priv->phydev = phy_connect(netdev, phy_id,
|
||||||
- &nss_dp_adjust_link,
|
- &nss_dp_adjust_link,
|
||||||
- dp_priv->phy_mii_type);
|
- dp_priv->phy_mii_type);
|
||||||
|
- if (IS_ERR(dp_priv->phydev)) {
|
||||||
|
- netdev_dbg(netdev, "failed to connect to phy device\n");
|
||||||
+ dp_priv->phydev = of_phy_connect(netdev, dp_priv->phy_node,
|
+ dp_priv->phydev = of_phy_connect(netdev, dp_priv->phy_node,
|
||||||
+ &nss_dp_adjust_link, 0,
|
+ &nss_dp_adjust_link, 0,
|
||||||
+ dp_priv->phy_mii_type);
|
+ dp_priv->phy_mii_type);
|
||||||
if (IS_ERR(dp_priv->phydev)) {
|
+ if (!(dp_priv->phydev)) {
|
||||||
- netdev_dbg(netdev, "failed to connect to phy device\n");
|
|
||||||
+ dev_err(&pdev->dev, "Could not attach to PHY\n");
|
+ dev_err(&pdev->dev, "Could not attach to PHY\n");
|
||||||
goto phy_setup_fail;
|
goto phy_setup_fail;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,9 @@ PKG_RELEASE=1
|
||||||
|
|
||||||
PKG_SOURCE_PROTO:=git
|
PKG_SOURCE_PROTO:=git
|
||||||
PKG_SOURCE_URL=$(PROJECT_GIT)/project/libubox.git
|
PKG_SOURCE_URL=$(PROJECT_GIT)/project/libubox.git
|
||||||
PKG_MIRROR_HASH:=400bef38b8c0f382e4e595a50bb52dfbdb8da820eb80f3447b9bd7be3f5499a5
|
PKG_MIRROR_HASH:=f22de22a784a0135cc2869fe81ff30e52136dca36863ee713503b4be5be01869
|
||||||
PKG_SOURCE_DATE:=2022-09-27
|
PKG_SOURCE_DATE:=2023-05-23
|
||||||
PKG_SOURCE_VERSION:=ea56013409d5823001b47a9bba6f74055a6d76a5
|
PKG_SOURCE_VERSION:=75a3b870cace1171faf57bd55e5a9a2f1564f757
|
||||||
PKG_ABI_VERSION:=$(call abi_version_str,$(PKG_SOURCE_DATE))
|
PKG_ABI_VERSION:=$(call abi_version_str,$(PKG_SOURCE_DATE))
|
||||||
CMAKE_INSTALL:=1
|
CMAKE_INSTALL:=1
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@ PKG_RELEASE:=1
|
||||||
|
|
||||||
PKG_SOURCE_PROTO:=git
|
PKG_SOURCE_PROTO:=git
|
||||||
PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git
|
PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git
|
||||||
PKG_SOURCE_DATE:=2023-05-31
|
PKG_SOURCE_DATE:=2023-06-04
|
||||||
PKG_SOURCE_VERSION:=38cbdc1c8cbbe2e30d62227d74565bd3fa21a36b
|
PKG_SOURCE_VERSION:=ec9dba72124597b7224bbfe75960386dc320f4bd
|
||||||
PKG_MIRROR_HASH:=5fbf325516a1bf1cc945019c061af280f5217267b20ae46fcfc71739616b3389
|
PKG_MIRROR_HASH:=baee39a3882a2b03fc83a3a6a8963c340fa8d884c7a8c9e80e7d2dddc50e24bd
|
||||||
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
||||||
|
|
||||||
PKG_LICENSE:=GPL-2.0
|
PKG_LICENSE:=GPL-2.0
|
||||||
|
|
|
@ -10,9 +10,9 @@ include $(TOPDIR)/rules.mk
|
||||||
PKG_NAME:=unetd
|
PKG_NAME:=unetd
|
||||||
PKG_SOURCE_PROTO:=git
|
PKG_SOURCE_PROTO:=git
|
||||||
PKG_SOURCE_URL=$(PROJECT_GIT)/project/unetd.git
|
PKG_SOURCE_URL=$(PROJECT_GIT)/project/unetd.git
|
||||||
PKG_SOURCE_DATE:=2022-09-16.1
|
PKG_SOURCE_DATE:=2023-05-31
|
||||||
PKG_SOURCE_VERSION:=6c888f897862b152e2cfae735faafc9cdcb07336
|
PKG_SOURCE_VERSION:=7d3986b7a5a20b9af0dacd053b2657210385e7bb
|
||||||
PKG_MIRROR_HASH:=35df8c822c671495146c3d5d1c193c1d1a44721c274aee2035943eb5e8c04768
|
PKG_MIRROR_HASH:=07f0a4cbae3e80c6309bb8aa27fcef19fbc56093a9c7e426e0d527227af09429
|
||||||
|
|
||||||
PKG_LICENSE:=GPL-2.0
|
PKG_LICENSE:=GPL-2.0
|
||||||
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
||||||
|
|
1
rules.mk
1
rules.mk
|
@ -227,6 +227,7 @@ else
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
export ORIG_PATH:=$(if $(ORIG_PATH),$(ORIG_PATH),$(PATH))
|
||||||
export PATH:=$(TARGET_PATH)
|
export PATH:=$(TARGET_PATH)
|
||||||
export STAGING_DIR STAGING_DIR_HOST STAGING_DIR_HOSTPKG
|
export STAGING_DIR STAGING_DIR_HOST STAGING_DIR_HOSTPKG
|
||||||
export SH_FUNC:=. $(INCLUDE_DIR)/shell.sh;
|
export SH_FUNC:=. $(INCLUDE_DIR)/shell.sh;
|
||||||
|
|
|
@ -191,13 +191,10 @@ OVCONFIGS=""
|
||||||
"
|
"
|
||||||
OVCONFIGS="$OVCONFIGS
|
OVCONFIGS="$OVCONFIGS
|
||||||
|
|
||||||
config-$ovname {
|
$ovname {
|
||||||
description = \"OpenWrt ${DEVICE} with $ovname\";
|
description = \"OpenWrt ${DEVICE} overlay $ovname\";
|
||||||
kernel = \"kernel${REFERENCE_CHAR}1\";
|
fdt = \"$ovnode\";
|
||||||
fdt = \"fdt${REFERENCE_CHAR}$FDTNUM\", \"$ovnode\";
|
|
||||||
${LOADABLES:+loadables = ${LOADABLES};}
|
|
||||||
${COMPATIBLE_PROP}
|
${COMPATIBLE_PROP}
|
||||||
${INITRD_PROP}
|
|
||||||
};
|
};
|
||||||
"
|
"
|
||||||
done
|
done
|
||||||
|
|
|
@ -13,6 +13,7 @@ export TOPDIR LC_ALL LANG
|
||||||
export OPENWRT_VERBOSE=s
|
export OPENWRT_VERBOSE=s
|
||||||
all: help
|
all: help
|
||||||
|
|
||||||
|
export ORIG_PATH:=$(if $(ORIG_PATH),$(ORIG_PATH),$(PATH))
|
||||||
export PATH:=$(TOPDIR)/staging_dir/host/bin:$(PATH)
|
export PATH:=$(TOPDIR)/staging_dir/host/bin:$(PATH)
|
||||||
|
|
||||||
ifneq ($(OPENWRT_BUILD),1)
|
ifneq ($(OPENWRT_BUILD),1)
|
||||||
|
|
|
@ -156,7 +156,7 @@ See: https://github.com/raspberrypi/linux/issues/1064
|
||||||
+MODULE_LICENSE("GPL");
|
+MODULE_LICENSE("GPL");
|
||||||
--- a/include/linux/leds.h
|
--- a/include/linux/leds.h
|
||||||
+++ b/include/linux/leds.h
|
+++ b/include/linux/leds.h
|
||||||
@@ -85,6 +85,9 @@ struct led_classdev {
|
@@ -95,6 +95,9 @@ struct led_classdev {
|
||||||
#define LED_BRIGHT_HW_CHANGED BIT(21)
|
#define LED_BRIGHT_HW_CHANGED BIT(21)
|
||||||
#define LED_RETAIN_AT_SHUTDOWN BIT(22)
|
#define LED_RETAIN_AT_SHUTDOWN BIT(22)
|
||||||
#define LED_INIT_DEFAULT_TRIGGER BIT(23)
|
#define LED_INIT_DEFAULT_TRIGGER BIT(23)
|
||||||
|
|
|
@ -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
|
||||||
|
@@ -414,6 +414,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)
|
||||||
|
@@ -1185,6 +1186,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
|
||||||
|
@@ -377,6 +423,19 @@ struct qca8k_mdio_cache {
|
||||||
|
u16 page;
|
||||||
|
};
|
||||||
|
|
||||||
|
+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;
|
||||||
|
@@ -399,6 +458,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
|
||||||
|
@@ -3118,6 +3189,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,35 @@
|
||||||
|
From cee4bd16c3195a701be683f7da9e88c6e11acb73 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Date: Wed, 19 Apr 2023 23:07:39 +0200
|
||||||
|
Subject: [PATCH 1/5] leds: trigger: netdev: Recheck NETDEV_LED_MODE_LINKUP on
|
||||||
|
dev rename
|
||||||
|
|
||||||
|
Dev can be renamed also while up for supported device. We currently
|
||||||
|
wrongly clear the NETDEV_LED_MODE_LINKUP flag on NETDEV_CHANGENAME
|
||||||
|
event.
|
||||||
|
|
||||||
|
Fix this by rechecking if the carrier is ok on NETDEV_CHANGENAME and
|
||||||
|
correctly set the NETDEV_LED_MODE_LINKUP bit.
|
||||||
|
|
||||||
|
Fixes: 5f820ed52371 ("leds: trigger: netdev: fix handling on interface rename")
|
||||||
|
Cc: stable@vger.kernel.org # v5.5+
|
||||||
|
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-2-ansuelsmth@gmail.com
|
||||||
|
---
|
||||||
|
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
|
||||||
|
@@ -318,6 +318,9 @@ static int netdev_trig_notify(struct not
|
||||||
|
clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||||
|
switch (evt) {
|
||||||
|
case NETDEV_CHANGENAME:
|
||||||
|
+ if (netif_carrier_ok(dev))
|
||||||
|
+ set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||||
|
+ fallthrough;
|
||||||
|
case NETDEV_REGISTER:
|
||||||
|
if (trigger_data->net_dev)
|
||||||
|
dev_put(trigger_data->net_dev);
|
|
@ -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;
|
|
@ -1,56 +0,0 @@
|
||||||
From: Qingfang DENG <qingfang.deng@siflower.com.cn>
|
|
||||||
Date: Fri, 3 Feb 2023 09:16:11 +0800
|
|
||||||
Subject: [PATCH] net: page_pool: use in_softirq() instead
|
|
||||||
|
|
||||||
We use BH context only for synchronization, so we don't care if it's
|
|
||||||
actually serving softirq or not.
|
|
||||||
|
|
||||||
As a side node, in case of threaded NAPI, in_serving_softirq() will
|
|
||||||
return false because it's in process context with BH off, making
|
|
||||||
page_pool_recycle_in_cache() unreachable.
|
|
||||||
|
|
||||||
Signed-off-by: Qingfang DENG <qingfang.deng@siflower.com.cn>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/include/net/page_pool.h
|
|
||||||
+++ b/include/net/page_pool.h
|
|
||||||
@@ -386,7 +386,7 @@ static inline void page_pool_nid_changed
|
|
||||||
static inline void page_pool_ring_lock(struct page_pool *pool)
|
|
||||||
__acquires(&pool->ring.producer_lock)
|
|
||||||
{
|
|
||||||
- if (in_serving_softirq())
|
|
||||||
+ if (in_softirq())
|
|
||||||
spin_lock(&pool->ring.producer_lock);
|
|
||||||
else
|
|
||||||
spin_lock_bh(&pool->ring.producer_lock);
|
|
||||||
@@ -395,7 +395,7 @@ static inline void page_pool_ring_lock(s
|
|
||||||
static inline void page_pool_ring_unlock(struct page_pool *pool)
|
|
||||||
__releases(&pool->ring.producer_lock)
|
|
||||||
{
|
|
||||||
- if (in_serving_softirq())
|
|
||||||
+ if (in_softirq())
|
|
||||||
spin_unlock(&pool->ring.producer_lock);
|
|
||||||
else
|
|
||||||
spin_unlock_bh(&pool->ring.producer_lock);
|
|
||||||
--- a/net/core/page_pool.c
|
|
||||||
+++ b/net/core/page_pool.c
|
|
||||||
@@ -511,8 +511,8 @@ static void page_pool_return_page(struct
|
|
||||||
static bool page_pool_recycle_in_ring(struct page_pool *pool, struct page *page)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
- /* BH protection not needed if current is serving softirq */
|
|
||||||
- if (in_serving_softirq())
|
|
||||||
+ /* BH protection not needed if current is softirq */
|
|
||||||
+ if (in_softirq())
|
|
||||||
ret = ptr_ring_produce(&pool->ring, page);
|
|
||||||
else
|
|
||||||
ret = ptr_ring_produce_bh(&pool->ring, page);
|
|
||||||
@@ -570,7 +570,7 @@ __page_pool_put_page(struct page_pool *p
|
|
||||||
page_pool_dma_sync_for_device(pool, page,
|
|
||||||
dma_sync_size);
|
|
||||||
|
|
||||||
- if (allow_direct && in_serving_softirq() &&
|
|
||||||
+ if (allow_direct && in_softirq() &&
|
|
||||||
page_pool_recycle_in_cache(page, pool))
|
|
||||||
return NULL;
|
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
@@ -2934,11 +2934,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,
|
||||||
|
@@ -2955,12 +2962,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
|
||||||
|
@@ -765,15 +765,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
|
||||||
|
*
|
||||||
|
@@ -988,6 +992,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
|
||||||
|
@@ -2832,6 +2834,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;
|
||||||
|
@@ -3081,6 +3111,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,
|
||||||
|
@@ -3187,6 +3218,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,
|
||||||
|
@@ -3213,6 +3245,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,
|
||||||
|
@@ -3239,6 +3272,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,
|
||||||
|
@@ -3380,6 +3414,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
|
||||||
|
@@ -2948,6 +2948,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)
|
||||||
|
{
|
||||||
|
@@ -2970,6 +2986,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
|
||||||
|
@@ -1001,6 +1001,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)
|
||||||
|
@@ -2862,6 +2864,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;
|
||||||
|
@@ -3112,6 +3143,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,
|
||||||
|
@@ -3219,6 +3251,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,
|
||||||
|
@@ -3246,6 +3279,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,
|
||||||
|
@@ -3273,6 +3307,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,
|
||||||
|
@@ -3415,6 +3450,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
|
||||||
|
@@ -2880,10 +2880,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,35 @@
|
||||||
|
From cee4bd16c3195a701be683f7da9e88c6e11acb73 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Date: Wed, 19 Apr 2023 23:07:39 +0200
|
||||||
|
Subject: [PATCH 1/5] leds: trigger: netdev: Recheck NETDEV_LED_MODE_LINKUP on
|
||||||
|
dev rename
|
||||||
|
|
||||||
|
Dev can be renamed also while up for supported device. We currently
|
||||||
|
wrongly clear the NETDEV_LED_MODE_LINKUP flag on NETDEV_CHANGENAME
|
||||||
|
event.
|
||||||
|
|
||||||
|
Fix this by rechecking if the carrier is ok on NETDEV_CHANGENAME and
|
||||||
|
correctly set the NETDEV_LED_MODE_LINKUP bit.
|
||||||
|
|
||||||
|
Fixes: 5f820ed52371 ("leds: trigger: netdev: fix handling on interface rename")
|
||||||
|
Cc: stable@vger.kernel.org # v5.5+
|
||||||
|
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-2-ansuelsmth@gmail.com
|
||||||
|
---
|
||||||
|
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
|
||||||
|
@@ -318,6 +318,9 @@ static int netdev_trig_notify(struct not
|
||||||
|
clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||||
|
switch (evt) {
|
||||||
|
case NETDEV_CHANGENAME:
|
||||||
|
+ if (netif_carrier_ok(dev))
|
||||||
|
+ set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||||
|
+ fallthrough;
|
||||||
|
case NETDEV_REGISTER:
|
||||||
|
if (trigger_data->net_dev)
|
||||||
|
dev_put(trigger_data->net_dev);
|
|
@ -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;
|
|
@ -1,4 +1,4 @@
|
||||||
From 97505f4c049fa2e8c86a53411a9e599033898533 Mon Sep 17 00:00:00 2001
|
From 7cbff3c3f867ff3b24de674f44ca03f54e416a37 Mon Sep 17 00:00:00 2001
|
||||||
From: Robert Marko <robimarko@gmail.com>
|
From: Robert Marko <robimarko@gmail.com>
|
||||||
Date: Sat, 31 Dec 2022 00:27:42 +0100
|
Date: Sat, 31 Dec 2022 00:27:42 +0100
|
||||||
Subject: [PATCH] soc: qcom: socinfo: move SMEM item struct and defines to a
|
Subject: [PATCH] soc: qcom: socinfo: move SMEM item struct and defines to a
|
||||||
|
@ -9,6 +9,9 @@ to reuse them in the Qualcomm NVMEM CPUFreq driver instead of duplicating
|
||||||
them.
|
them.
|
||||||
|
|
||||||
Signed-off-by: Robert Marko <robimarko@gmail.com>
|
Signed-off-by: Robert Marko <robimarko@gmail.com>
|
||||||
|
Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||||
|
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
|
||||||
|
Link: https://lore.kernel.org/r/20230526204802.3081168-1-robimarko@gmail.com
|
||||||
---
|
---
|
||||||
drivers/soc/qcom/socinfo.c | 58 +--------------------------
|
drivers/soc/qcom/socinfo.c | 58 +--------------------------
|
||||||
include/linux/soc/qcom/socinfo.h | 67 ++++++++++++++++++++++++++++++++
|
include/linux/soc/qcom/socinfo.h | 67 ++++++++++++++++++++++++++++++++
|
|
@ -0,0 +1,55 @@
|
||||||
|
From 9f1bbff157a69db7684f5da2f73b2325c638a90e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robert Marko <robimarko@gmail.com>
|
||||||
|
Date: Fri, 26 May 2023 22:47:59 +0200
|
||||||
|
Subject: [PATCH] soc: qcom: smem: Switch to EXPORT_SYMBOL_GPL()
|
||||||
|
|
||||||
|
SMEM has been GPL licensed from the start, and there is no reason to use
|
||||||
|
EXPORT_SYMBOL() so switch to the GPL version.
|
||||||
|
|
||||||
|
Signed-off-by: Robert Marko <robimarko@gmail.com>
|
||||||
|
Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||||
|
Reviewed-by: Trilok Soni <quic_tsoni@quicinc.com>
|
||||||
|
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
|
||||||
|
Link: https://lore.kernel.org/r/20230526204802.3081168-2-robimarko@gmail.com
|
||||||
|
---
|
||||||
|
drivers/soc/qcom/smem.c | 8 ++++----
|
||||||
|
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/soc/qcom/smem.c
|
||||||
|
+++ b/drivers/soc/qcom/smem.c
|
||||||
|
@@ -500,7 +500,7 @@ int qcom_smem_alloc(unsigned host, unsig
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
-EXPORT_SYMBOL(qcom_smem_alloc);
|
||||||
|
+EXPORT_SYMBOL_GPL(qcom_smem_alloc);
|
||||||
|
|
||||||
|
static void *qcom_smem_get_global(struct qcom_smem *smem,
|
||||||
|
unsigned item,
|
||||||
|
@@ -674,7 +674,7 @@ void *qcom_smem_get(unsigned host, unsig
|
||||||
|
return ptr;
|
||||||
|
|
||||||
|
}
|
||||||
|
-EXPORT_SYMBOL(qcom_smem_get);
|
||||||
|
+EXPORT_SYMBOL_GPL(qcom_smem_get);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcom_smem_get_free_space() - retrieve amount of free space in a partition
|
||||||
|
@@ -719,7 +719,7 @@ int qcom_smem_get_free_space(unsigned ho
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
-EXPORT_SYMBOL(qcom_smem_get_free_space);
|
||||||
|
+EXPORT_SYMBOL_GPL(qcom_smem_get_free_space);
|
||||||
|
|
||||||
|
static bool addr_in_range(void __iomem *base, size_t size, void *addr)
|
||||||
|
{
|
||||||
|
@@ -770,7 +770,7 @@ phys_addr_t qcom_smem_virt_to_phys(void
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
-EXPORT_SYMBOL(qcom_smem_virt_to_phys);
|
||||||
|
+EXPORT_SYMBOL_GPL(qcom_smem_virt_to_phys);
|
||||||
|
|
||||||
|
static int qcom_smem_get_sbl_version(struct qcom_smem *smem)
|
||||||
|
{
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue