mirror of
https://github.com/nxp-imx/linux-imx.git
synced 2025-10-22 23:23:03 +02:00
Merge remote-tracking branch 'lf-lts/lf-6.12.y' into nxp-linux-sdk/lf-6.12.y_android
Conflicts: drivers/pci/controller/dwc/pci-imx6.c include/linux/pci.h Change-Id: I42cf28e28d9d634ef37517ddf7e82c52e11c13b4
This commit is contained in:
commit
97bf30a802
|
@ -790,11 +790,24 @@ F: drivers/mtd/nand/raw/gpmi-nand/
|
|||
F: include/linux/fsl_ifc.h
|
||||
|
||||
net/phy
|
||||
M: Wei Fang <wei.fang@nxp.com>
|
||||
R: Clark Wang <xiaoning.wang@nxp.com>
|
||||
R: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
|
||||
M: Clark Wang <xiaoning.wang@nxp.com>
|
||||
M: Ioana Ciornei <ioana.ciornei@nxp.com>
|
||||
M: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
R: Wei Fang <wei.fang@nxp.com>
|
||||
F: Documentation/devicetree/bindings/phy/inphi,in112525.yaml
|
||||
F: Documentation/devicetree/bindings/phy/ti,ds125df111.yaml
|
||||
F: drivers/net/pcs/
|
||||
F: drivers/net/phy/
|
||||
F: drivers/phy/inphi/
|
||||
F: drivers/phy/freescale/phy-fsl-lynx-*.c
|
||||
F: drivers/phy/freescale/phy-fsl-lynx-xgkr-algorithm.h
|
||||
F: drivers/phy/ti/phy-ds125df111.c
|
||||
F: drivers/soc/fsl/guts.c
|
||||
F: include/linux/fsl/guts.h
|
||||
F: include/linux/mii.h
|
||||
F: include/linux/phy.h
|
||||
F: include/linux/phy/phy-ethernet.h
|
||||
F: include/linux/phy/phy-fsl-lynx.h
|
||||
|
||||
net/tsn
|
||||
M: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
|
||||
|
|
|
@ -12,14 +12,11 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/map.h>
|
||||
#include <asm/mach/pci.h>
|
||||
|
||||
#include "../../../drivers/pci/pcie/portdrv.h"
|
||||
|
||||
static int debug_pci;
|
||||
|
||||
/*
|
||||
|
@ -67,47 +64,6 @@ void pcibios_report_status(u_int status_mask, int warn)
|
|||
pcibios_bus_report_status(bus, status_mask, warn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check device tree if the service interrupts are there
|
||||
*/
|
||||
int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask)
|
||||
{
|
||||
int ret, count = 0;
|
||||
struct device_node *np = NULL;
|
||||
|
||||
if (dev->bus->dev.of_node)
|
||||
np = dev->bus->dev.of_node;
|
||||
|
||||
if (np == NULL)
|
||||
return 0;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OF_IRQ))
|
||||
return 0;
|
||||
|
||||
/* If root port doesn't support MSI/MSI-X/INTx in RC mode,
|
||||
* request irq for aer
|
||||
*/
|
||||
if (mask & PCIE_PORT_SERVICE_AER) {
|
||||
ret = of_irq_get_byname(np, "aer");
|
||||
if (ret > 0) {
|
||||
irqs[PCIE_PORT_SERVICE_AER_SHIFT] = ret;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & PCIE_PORT_SERVICE_PME) {
|
||||
ret = of_irq_get_byname(np, "pme");
|
||||
if (ret > 0) {
|
||||
irqs[PCIE_PORT_SERVICE_PME_SHIFT] = ret;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: add more service interrupts if there it is in the device tree*/
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't use this to fix the device, but initialisation of it.
|
||||
* It's not the correct use for this, but it works.
|
||||
|
|
|
@ -78,6 +78,10 @@
|
|||
};
|
||||
};
|
||||
|
||||
sound-micfil {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
};
|
||||
};
|
||||
|
||||
&iomuxc {
|
||||
|
|
|
@ -84,6 +84,11 @@
|
|||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
|
||||
sound-micfil {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
};
|
||||
};
|
||||
|
||||
&iomuxc {
|
||||
|
|
|
@ -92,6 +92,11 @@
|
|||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
|
||||
sound-micfil {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
};
|
||||
};
|
||||
|
||||
&iomuxc {
|
||||
|
|
|
@ -92,6 +92,11 @@
|
|||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
|
||||
sound-micfil {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
};
|
||||
};
|
||||
|
||||
&iomuxc {
|
||||
|
|
|
@ -116,6 +116,11 @@
|
|||
regulator-always-on;
|
||||
};
|
||||
|
||||
sound-micfil {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
};
|
||||
|
||||
sound-wm8962 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
|
|
@ -151,6 +151,10 @@
|
|||
};
|
||||
};
|
||||
|
||||
sound-micfil {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
};
|
||||
};
|
||||
|
||||
&adp5585 {
|
||||
|
|
|
@ -109,6 +109,8 @@
|
|||
sound-micfil {
|
||||
compatible = "fsl,imx-audio-card";
|
||||
model = "micfil-audio";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
pri-dai-link {
|
||||
link-name = "micfil hifi";
|
||||
format = "i2s";
|
||||
|
|
|
@ -132,6 +132,8 @@
|
|||
sound-micfil {
|
||||
compatible = "fsl,imx-audio-card";
|
||||
model = "micfil-audio";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
pri-dai-link {
|
||||
link-name = "micfil hifi";
|
||||
format = "i2s";
|
||||
|
|
|
@ -128,6 +128,10 @@
|
|||
};
|
||||
};
|
||||
|
||||
sound-micfil {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
};
|
||||
};
|
||||
|
||||
&dmic {
|
||||
|
|
|
@ -103,6 +103,11 @@
|
|||
regulator-always-on;
|
||||
};
|
||||
|
||||
sound-micfil {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
};
|
||||
|
||||
sound-wm8962 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
|
|
@ -138,6 +138,10 @@
|
|||
};
|
||||
};
|
||||
|
||||
sound-micfil {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
};
|
||||
};
|
||||
|
||||
&dmic {
|
||||
|
|
|
@ -109,6 +109,8 @@
|
|||
sound-micfil {
|
||||
compatible = "fsl,imx-audio-card";
|
||||
model = "micfil-audio";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
pri-dai-link {
|
||||
link-name = "micfil hifi";
|
||||
format = "i2s";
|
||||
|
|
|
@ -132,6 +132,8 @@
|
|||
sound-micfil {
|
||||
compatible = "fsl,imx-audio-card";
|
||||
model = "micfil-audio";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
pri-dai-link {
|
||||
link-name = "micfil hifi";
|
||||
format = "i2s";
|
||||
|
|
|
@ -106,6 +106,8 @@
|
|||
sound-micfil {
|
||||
compatible = "fsl,imx-audio-card";
|
||||
model = "micfil-audio";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
pri-dai-link {
|
||||
link-name = "micfil hifi";
|
||||
format = "i2s";
|
||||
|
|
|
@ -137,6 +137,8 @@
|
|||
sound-micfil {
|
||||
compatible = "fsl,imx-audio-card";
|
||||
model = "micfil-audio";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
pri-dai-link {
|
||||
link-name = "micfil hifi";
|
||||
format = "i2s";
|
||||
|
|
|
@ -143,6 +143,10 @@
|
|||
};
|
||||
};
|
||||
|
||||
sound-micfil {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
};
|
||||
};
|
||||
|
||||
&dmic {
|
||||
|
|
|
@ -1661,8 +1661,10 @@
|
|||
bus-range = <0x00 0xff>;
|
||||
num-lanes = <1>;
|
||||
num-viewport = <8>;
|
||||
interrupts = <GIC_SPI 364 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "msi";
|
||||
interrupts = <GIC_SPI 364 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 364 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 364 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "msi", "pme", "intr";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0x7>;
|
||||
interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>,
|
||||
|
|
|
@ -285,8 +285,10 @@
|
|||
bus-range = <0x00 0xff>;
|
||||
num-lanes = <1>;
|
||||
num-viewport = <8>;
|
||||
interrupts = <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "msi";
|
||||
interrupts = <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "msi", "pme", "intr";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0x7>;
|
||||
interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 366 IRQ_TYPE_LEVEL_HIGH>,
|
||||
|
|
|
@ -103,6 +103,11 @@
|
|||
regulator-always-on;
|
||||
};
|
||||
|
||||
sound-micfil {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
};
|
||||
|
||||
sound-wm8962 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
|
|
@ -130,6 +130,10 @@
|
|||
};
|
||||
};
|
||||
|
||||
sound-micfil {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
};
|
||||
};
|
||||
|
||||
&dmic {
|
||||
|
|
|
@ -85,6 +85,11 @@
|
|||
interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
sound-micfil {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
};
|
||||
};
|
||||
|
||||
&micfil {
|
||||
|
|
|
@ -117,6 +117,11 @@
|
|||
};
|
||||
};
|
||||
|
||||
sound-micfil {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
|
||||
};
|
||||
|
||||
sound-xcvr {
|
||||
compatible = "fsl,imx-audio-card";
|
||||
model = "imx-audio-xcvr";
|
||||
|
@ -132,15 +137,13 @@
|
|||
&pcal6524 {
|
||||
/* When low, select can; When high, select gpio. */
|
||||
can-gpio-sel-hog {
|
||||
gpio-hog;
|
||||
gpios = <4 GPIO_ACTIVE_HIGH>;
|
||||
/delete-property/ output-low;
|
||||
output-high;
|
||||
};
|
||||
|
||||
/* When low, select pwm; When high, select gpio. */
|
||||
pwm-gpio-sel-hog {
|
||||
gpio-hog;
|
||||
gpios = <5 GPIO_ACTIVE_LOW>;
|
||||
/delete-property/ output-low;
|
||||
output-high;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -362,6 +362,34 @@
|
|||
"LVDS panel backlight enable",
|
||||
"LVDS panel backlight power enable",
|
||||
"LVDS to HDMI converter IT6263 reset";
|
||||
|
||||
/* When low, select lpspi; When high, select gpio. */
|
||||
lpspi-gpio-sel-hog {
|
||||
gpio-hog;
|
||||
gpios = <2 GPIO_ACTIVE_HIGH>;
|
||||
output-low;
|
||||
};
|
||||
|
||||
/* When low, select lpuart3; When high, select gpio. */
|
||||
lpuart-gpio-sel-hog {
|
||||
gpio-hog;
|
||||
gpios = <3 GPIO_ACTIVE_HIGH>;
|
||||
output-low;
|
||||
};
|
||||
|
||||
/* When low, select CAN; When high, select gpio. */
|
||||
can-gpio-sel-hog {
|
||||
gpio-hog;
|
||||
gpios = <4 GPIO_ACTIVE_HIGH>;
|
||||
output-low;
|
||||
};
|
||||
|
||||
/* When low, select pwm; When high, select gpio. */
|
||||
pwm-gpio-sel-hog {
|
||||
gpio-hog;
|
||||
gpios = <5 GPIO_ACTIVE_HIGH>;
|
||||
output-low;
|
||||
};
|
||||
};
|
||||
|
||||
pcal6408_b: gpio@20 {
|
||||
|
|
|
@ -2726,8 +2726,10 @@
|
|||
bus-range = <0x00 0xff>;
|
||||
num-lanes = <1>;
|
||||
num-viewport = <8>;
|
||||
interrupts = <GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "msi";
|
||||
interrupts = <GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "msi", "pme", "intr";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0x7>;
|
||||
interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>,
|
||||
|
@ -2804,8 +2806,10 @@
|
|||
bus-range = <0x00 0xff>;
|
||||
num-lanes = <1>;
|
||||
num-viewport = <8>;
|
||||
interrupts = <GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "msi";
|
||||
interrupts = <GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "msi", "pme", "intr";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0x7>;
|
||||
interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>,
|
||||
|
|
|
@ -7,50 +7,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#include "../../../drivers/pci/pcie/portdrv.h"
|
||||
|
||||
/*
|
||||
* Check device tree if the service interrupts are there
|
||||
*/
|
||||
int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask)
|
||||
{
|
||||
int ret, count = 0;
|
||||
struct device_node *np = NULL;
|
||||
|
||||
if (dev->bus->dev.of_node)
|
||||
np = dev->bus->dev.of_node;
|
||||
|
||||
if (np == NULL)
|
||||
return 0;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OF_IRQ))
|
||||
return 0;
|
||||
|
||||
/* If root port doesn't support MSI/MSI-X/INTx in RC mode,
|
||||
* request irq for aer
|
||||
*/
|
||||
if (mask & PCIE_PORT_SERVICE_AER) {
|
||||
ret = of_irq_get_byname(np, "aer");
|
||||
if (ret > 0) {
|
||||
irqs[PCIE_PORT_SERVICE_AER_SHIFT] = ret;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & PCIE_PORT_SERVICE_PME) {
|
||||
ret = of_irq_get_byname(np, "pme");
|
||||
if (ret > 0) {
|
||||
irqs[PCIE_PORT_SERVICE_PME_SHIFT] = ret;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: add more service interrupts if there it is in the device tree*/
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* raw_pci_read/write - Platform-specific PCI config space access.
|
||||
|
|
|
@ -114,7 +114,7 @@ static int pm_callback_power_on(struct kbase_device *kbdev)
|
|||
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
|
||||
WARN_ON(kbase_io_is_gpu_powered(kbdev));
|
||||
if (likely(kbdev->csf.firmware_inited)) {
|
||||
WARN_ON(!kbdev->pm.active_count);
|
||||
WARN_ON(!atomic_read(&(kbdev->pm.active_count)));
|
||||
WARN_ON(kbdev->pm.runtime_active);
|
||||
}
|
||||
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
|
||||
|
|
|
@ -141,7 +141,9 @@
|
|||
|
||||
#define FOUT_MAX MHZ(1250)
|
||||
#define FOUT_MIN MHZ(40)
|
||||
#define FVCO_DIV_FACTOR MHZ(80)
|
||||
|
||||
#define FVCO_CNTRL_OP_DIV_MASK GENMASK(5, 4)
|
||||
#define FVCO_CNTRL_OP_DIV(n) FIELD_GET(FVCO_CNTRL_OP_DIV_MASK, n)
|
||||
|
||||
#define MBPS(x) ((x) * 1000000UL)
|
||||
|
||||
|
@ -190,9 +192,11 @@ struct imx95_dsi {
|
|||
struct imx95_dsi_phy_pll_cfg {
|
||||
u32 m; /* PLL Feedback Multiplication Ratio */
|
||||
u32 n; /* PLL Input Frequency Division Ratio */
|
||||
unsigned int vco_prop_sel; /* Index for best PLL vco_cntrl/prop_cntrl */
|
||||
};
|
||||
|
||||
struct imx95_dsi_phy_pll_vco_prop {
|
||||
unsigned long min_fout;
|
||||
unsigned long max_fout;
|
||||
u8 vco_cntl;
|
||||
u8 prop_cntl;
|
||||
|
@ -205,17 +209,17 @@ struct imx95_dsi_phy_pll_hsfreqrange {
|
|||
|
||||
/* DPHY Databook Table 3-12 Charge-pump Programmability */
|
||||
static const struct imx95_dsi_phy_pll_vco_prop vco_prop_map[] = {
|
||||
{ 55, 0x3f, 0x0d },
|
||||
{ 82, 0x39, 0x0d },
|
||||
{ 110, 0x2f, 0x0d },
|
||||
{ 165, 0x29, 0x0d },
|
||||
{ 220, 0x1f, 0x0d },
|
||||
{ 330, 0x19, 0x0d },
|
||||
{ 440, 0x0f, 0x0d },
|
||||
{ 660, 0x09, 0x0d },
|
||||
{ 1149, 0x03, 0x0d },
|
||||
{ 1152, 0x01, 0x0d },
|
||||
{ 1250, 0x01, 0x0e },
|
||||
{ 40, 55, 0x3f, 0x0d },
|
||||
{ 52, 82, 0x39, 0x0d },
|
||||
{ 80, 110, 0x2f, 0x0d },
|
||||
{ 105, 165, 0x29, 0x0d },
|
||||
{ 160, 220, 0x1f, 0x0d },
|
||||
{ 210, 330, 0x19, 0x0d },
|
||||
{ 320, 440, 0x0f, 0x0d },
|
||||
{ 420, 660, 0x09, 0x0d },
|
||||
{ 630, 1149, 0x03, 0x0d },
|
||||
{ 1100, 1152, 0x01, 0x0d },
|
||||
{ 1150, 1250, 0x01, 0x0e },
|
||||
};
|
||||
|
||||
/* DPHY Databook Table A-4 High-Speed Transition Times */
|
||||
|
@ -507,6 +511,17 @@ static inline unsigned long data_rate_to_fout(unsigned long data_rate)
|
|||
return data_rate / 2;
|
||||
}
|
||||
|
||||
static inline unsigned int vco_cntrl_to_fvco_div(u8 vco_cntl)
|
||||
{
|
||||
/* bits [5:4] of vco_cntrl represent fvco divider */
|
||||
/* fvco_div is determined using the below mapping */
|
||||
/* 00 -> divide by 1 */
|
||||
/* 01 -> divide by 2 */
|
||||
/* 10 -> divide by 4 */
|
||||
/* 11 -> divide by 8 */
|
||||
return 1 << FVCO_CNTRL_OP_DIV(vco_cntl);
|
||||
}
|
||||
|
||||
static int
|
||||
imx95_dsi_phy_pll_get_configure_from_opts(struct imx95_dsi *dsi,
|
||||
struct phy_configure_opts_mipi_dphy *dphy_opts,
|
||||
|
@ -521,6 +536,8 @@ imx95_dsi_phy_pll_get_configure_from_opts(struct imx95_dsi *dsi,
|
|||
unsigned long m, best_m;
|
||||
unsigned long min_delta = ULONG_MAX;
|
||||
unsigned long delta;
|
||||
unsigned int i;
|
||||
unsigned int best_vco_prop;
|
||||
u64 tmp;
|
||||
|
||||
if (dphy_opts->hs_clk_rate < DATA_RATE_MIN_SPEED ||
|
||||
|
@ -532,11 +549,6 @@ imx95_dsi_phy_pll_get_configure_from_opts(struct imx95_dsi *dsi,
|
|||
|
||||
fout = data_rate_to_fout(dphy_opts->hs_clk_rate);
|
||||
|
||||
/* DPHY Databook 3.3.6.1 Output Frequency */
|
||||
/* Fout = Fvco / Fvco_div = (Fin * M) / (Fvco_div * N) */
|
||||
/* Fvco_div could be 1/2/4/8 according to Fout range. */
|
||||
fvco_div = 8UL / min(DIV_ROUND_UP(fout, FVCO_DIV_FACTOR), 8UL);
|
||||
|
||||
/* limitation: 2MHz <= Fin / N <= 8MHz */
|
||||
min_n = DIV_ROUND_UP_ULL((u64)fin, MHZ(8));
|
||||
max_n = DIV_ROUND_DOWN_ULL((u64)fin, MHZ(2));
|
||||
|
@ -545,37 +557,49 @@ imx95_dsi_phy_pll_get_configure_from_opts(struct imx95_dsi *dsi,
|
|||
min_n = clamp(min_n, N_MIN, N_MAX);
|
||||
max_n = clamp(max_n, N_MIN, N_MAX);
|
||||
|
||||
dev_dbg(dev, "Fout = %lu, Fvco_div = %u, n_range = [%u, %u]\n",
|
||||
fout, fvco_div, min_n, max_n);
|
||||
dev_dbg(dev, "Fout = %lu, n_range = [%u, %u]\n", fout, min_n, max_n);
|
||||
|
||||
for (n = min_n; n <= max_n; n++) {
|
||||
/* M = (Fout * N * Fvco_div) / Fin */
|
||||
m = DIV_ROUND_CLOSEST(fout * n * fvco_div, fin);
|
||||
|
||||
/* check M range */
|
||||
if (m < M_MIN || m > M_MAX)
|
||||
for (i = 0; i < ARRAY_SIZE(vco_prop_map); i++) {
|
||||
if ((fout / MHZ(1)) < vco_prop_map[i].min_fout ||
|
||||
(fout / MHZ(1)) > vco_prop_map[i].max_fout)
|
||||
continue;
|
||||
|
||||
/* calculate temporary Fout */
|
||||
tmp = m * fin;
|
||||
do_div(tmp, n * fvco_div);
|
||||
if (tmp < FOUT_MIN || tmp > FOUT_MAX)
|
||||
continue;
|
||||
/* fvco divider value can be either 1,2,4,or 8 */
|
||||
fvco_div = vco_cntrl_to_fvco_div(vco_prop_map[i].vco_cntl);
|
||||
|
||||
delta = abs(fout - tmp);
|
||||
if (delta < min_delta) {
|
||||
best_n = n;
|
||||
best_m = m;
|
||||
min_delta = delta;
|
||||
best_fout = tmp;
|
||||
dev_dbg(dev, "Trying fvco_div = %u\n", fvco_div);
|
||||
|
||||
for (n = min_n; n <= max_n; n++) {
|
||||
/* M = (Fout * N * Fvco_div) / Fin */
|
||||
m = DIV_ROUND_CLOSEST(fout * n * fvco_div, fin);
|
||||
|
||||
/* check M range */
|
||||
if (m < M_MIN || m > M_MAX)
|
||||
continue;
|
||||
|
||||
/* calculate temporary Fout */
|
||||
tmp = m * fin;
|
||||
do_div(tmp, n * fvco_div);
|
||||
if (tmp < FOUT_MIN || tmp > FOUT_MAX)
|
||||
continue;
|
||||
|
||||
delta = abs(fout - tmp);
|
||||
if (delta < min_delta) {
|
||||
best_n = n;
|
||||
best_m = m;
|
||||
best_vco_prop = i;
|
||||
best_fout = tmp;
|
||||
min_delta = delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best_fout) {
|
||||
cfg->m = best_m;
|
||||
cfg->n = best_n;
|
||||
dev_dbg(dev, "best Fout = %lu, m = %u, n = %u\n",
|
||||
best_fout, cfg->m, cfg->n);
|
||||
cfg->vco_prop_sel = best_vco_prop;
|
||||
dev_dbg(dev, "best Fout = %lu, fvco_div = %u, m = %u, n = %u\n",
|
||||
best_fout, fvco_div, cfg->m, cfg->n);
|
||||
} else {
|
||||
dev_dbg(dev, "failed to find best Fout\n");
|
||||
return -EINVAL;
|
||||
|
@ -607,29 +631,15 @@ static unsigned long imx95_dsi_phy_pll_get_cfgclkrange(struct imx95_dsi *dsi)
|
|||
}
|
||||
|
||||
static u8
|
||||
imx95_dsi_phy_pll_get_vco(struct phy_configure_opts_mipi_dphy *dphy_opts)
|
||||
imx95_dsi_phy_pll_get_vco(struct imx95_dsi_phy_pll_cfg *cfg)
|
||||
{
|
||||
unsigned long fout = data_rate_to_fout(dphy_opts->hs_clk_rate) / MHZ(1);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vco_prop_map); i++)
|
||||
if (fout <= vco_prop_map[i].max_fout)
|
||||
return vco_prop_map[i].vco_cntl;
|
||||
|
||||
return 0;
|
||||
return vco_prop_map[cfg->vco_prop_sel].vco_cntl;
|
||||
}
|
||||
|
||||
static u8
|
||||
imx95_dsi_phy_pll_get_prop(struct phy_configure_opts_mipi_dphy *dphy_opts)
|
||||
imx95_dsi_phy_pll_get_prop(struct imx95_dsi_phy_pll_cfg *cfg)
|
||||
{
|
||||
unsigned long fout = data_rate_to_fout(dphy_opts->hs_clk_rate) / MHZ(1);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vco_prop_map); i++)
|
||||
if (fout <= vco_prop_map[i].max_fout)
|
||||
return vco_prop_map[i].prop_cntl;
|
||||
|
||||
return 0;
|
||||
return vco_prop_map[cfg->vco_prop_sel].prop_cntl;
|
||||
}
|
||||
|
||||
static int imx95_dsi_phy_pll_configure(struct imx95_dsi *dsi,
|
||||
|
@ -695,7 +705,7 @@ static int imx95_dsi_phy_pll_configure(struct imx95_dsi *dsi,
|
|||
PLL_N_OVR_RW(cfg.n) | PLL_N_OVR_EN_RW);
|
||||
|
||||
/* vco ctrl */
|
||||
val = imx95_dsi_phy_pll_get_vco(&opts->mipi_dphy);
|
||||
val = imx95_dsi_phy_pll_get_vco(&cfg);
|
||||
imx95_dsi_phy_tst_ctrl_update(dsi, DIG_RDWR_TX_PLL_30,
|
||||
PLL_VCO_CNTRL_OVR_RW_MASK |
|
||||
PLL_VCO_CNTRL_OVR_EN_RW,
|
||||
|
@ -713,7 +723,7 @@ static int imx95_dsi_phy_pll_configure(struct imx95_dsi *dsi,
|
|||
PLL_GMP_CNTRL_RW(0x1));
|
||||
|
||||
/* prop ctrl */
|
||||
val = imx95_dsi_phy_pll_get_prop(&opts->mipi_dphy);
|
||||
val = imx95_dsi_phy_pll_get_prop(&cfg);
|
||||
imx95_dsi_phy_tst_ctrl_update(dsi, DIG_RDWR_TX_PLL_17,
|
||||
PLL_PROP_CNTRL_RW_MASK,
|
||||
PLL_PROP_CNTRL_RW(val));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_NET_DSA_NETC_SWITCH) += nxp-netc-switch.o
|
||||
nxp-netc-switch-objs := netc_main.o netc_platform.o netc_tc.o \
|
||||
netc_ethtool.o netc_ptp.o
|
||||
netc_ethtool.o netc_ptp.o netc_pm.o
|
||||
nxp-netc-switch-$(CONFIG_DEBUG_FS) += netc_debugfs.o
|
||||
|
|
|
@ -29,12 +29,11 @@ static struct netc_fdb_entry *netc_lookup_fdb_entry(struct netc_switch *priv,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void netc_destroy_fdb_list(struct netc_switch *priv)
|
||||
void netc_destroy_fdb_list(struct netc_switch *priv)
|
||||
{
|
||||
struct netc_fdb_entry *entry;
|
||||
struct hlist_node *tmp;
|
||||
|
||||
guard(mutex)(&priv->fdbt_lock);
|
||||
hlist_for_each_entry_safe(entry, tmp, &priv->fdb_list, node)
|
||||
netc_del_fdb_entry(entry);
|
||||
}
|
||||
|
@ -51,12 +50,11 @@ static struct netc_vlan_entry *netc_lookup_vlan_entry(struct netc_switch *priv,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void netc_destroy_vlan_list(struct netc_switch *priv)
|
||||
void netc_destroy_vlan_list(struct netc_switch *priv)
|
||||
{
|
||||
struct netc_vlan_entry *entry;
|
||||
struct hlist_node *tmp;
|
||||
|
||||
guard(mutex)(&priv->vft_lock);
|
||||
hlist_for_each_entry_safe(entry, tmp, &priv->vlan_list, node)
|
||||
netc_del_vlan_entry(entry);
|
||||
}
|
||||
|
@ -126,7 +124,7 @@ void netc_mac_port_wr(struct netc_port *port, u32 reg, u32 val)
|
|||
netc_port_wr(port, reg + NETC_PMAC_OFFSET, val);
|
||||
}
|
||||
|
||||
static u32 netc_mac_port_rd(struct netc_port *port, u32 reg)
|
||||
u32 netc_mac_port_rd(struct netc_port *port, u32 reg)
|
||||
{
|
||||
if (is_netc_pseudo_port(port))
|
||||
return 0;
|
||||
|
@ -741,6 +739,13 @@ static void netc_switch_isit_key_config(struct netc_switch *priv)
|
|||
netc_base_wr(regs, NETC_ISIDKCCR0(1), val);
|
||||
}
|
||||
|
||||
void netc_switch_fixed_config(struct netc_switch *priv)
|
||||
{
|
||||
netc_switch_dos_default_config(priv);
|
||||
netc_switch_vfht_default_config(priv);
|
||||
netc_switch_isit_key_config(priv);
|
||||
}
|
||||
|
||||
static void netc_port_set_max_frame_size(struct netc_port *port,
|
||||
u32 max_frame_size)
|
||||
{
|
||||
|
@ -787,18 +792,11 @@ static void netc_port_set_mlo(struct netc_port *port, int mlo)
|
|||
netc_port_wr(port, NETC_BPCR, val);
|
||||
}
|
||||
|
||||
static void netc_port_default_config(struct netc_port *port)
|
||||
void netc_port_fixed_config(struct netc_port *port)
|
||||
{
|
||||
u32 pqnt = 0xffff, qth = 0xffff / 2;
|
||||
u32 val;
|
||||
|
||||
/* Default VLAN unware */
|
||||
val = netc_port_rd(port, NETC_BPDVR);
|
||||
if (!(val & BPDVR_RXVAM)) {
|
||||
val |= BPDVR_RXVAM;
|
||||
netc_port_wr(port, NETC_BPDVR, val);
|
||||
}
|
||||
|
||||
/* Default IPV and DR setting */
|
||||
val = netc_port_rd(port, NETC_PQOSMR);
|
||||
val |= PQOSMR_VS | PQOSMR_VE;
|
||||
|
@ -830,13 +828,28 @@ static void netc_port_default_config(struct netc_port *port)
|
|||
* if a pause condition still exists.
|
||||
*/
|
||||
netc_port_wr(port, NETC_PM_PAUSE_TRHESH(0), qth);
|
||||
}
|
||||
}
|
||||
|
||||
static void netc_port_default_config(struct netc_port *port)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
netc_port_fixed_config(port);
|
||||
|
||||
/* Default VLAN unware */
|
||||
val = netc_port_rd(port, NETC_BPDVR);
|
||||
if (!(val & BPDVR_RXVAM)) {
|
||||
val |= BPDVR_RXVAM;
|
||||
netc_port_wr(port, NETC_BPDVR, val);
|
||||
}
|
||||
|
||||
if (dsa_port_is_user(port->dp)) {
|
||||
netc_port_set_mlo(port, MLO_DISABLE);
|
||||
} else {
|
||||
val = netc_port_rd(port, NETC_BPCR);
|
||||
val |= BPCR_SRCPRND;
|
||||
val = netc_port_rd(port, NETC_BPCR) | BPCR_SRCPRND;
|
||||
val = u32_replace_bits(val, MLO_HW, BPCR_MLO);
|
||||
netc_port_wr(port, NETC_BPCR, val);
|
||||
|
||||
netc_port_set_mlo(port, MLO_HW);
|
||||
}
|
||||
|
||||
netc_port_set_max_frame_size(port, NETC_MAX_FRAME_LEN);
|
||||
|
@ -892,9 +905,7 @@ static int netc_setup(struct dsa_switch *ds)
|
|||
INIT_DELAYED_WORK(&priv->fdbt_clean, netc_clean_fdbt_aging_entries);
|
||||
mutex_init(&priv->bpt_lock);
|
||||
|
||||
netc_switch_dos_default_config(priv);
|
||||
netc_switch_vfht_default_config(priv);
|
||||
netc_switch_isit_key_config(priv);
|
||||
netc_switch_fixed_config(priv);
|
||||
|
||||
/* default setting for ports */
|
||||
for (i = 0; i < priv->num_ports; i++) {
|
||||
|
@ -929,6 +940,14 @@ static void netc_destroy_all_lists(struct netc_switch *priv)
|
|||
mutex_destroy(&priv->vft_lock);
|
||||
}
|
||||
|
||||
static void netc_free_ports_taprio(struct netc_switch *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->num_ports; i++)
|
||||
netc_port_free_taprio(priv->ports[i]);
|
||||
}
|
||||
|
||||
static void netc_teardown(struct dsa_switch *ds)
|
||||
{
|
||||
struct netc_switch *priv = ds->priv;
|
||||
|
@ -937,6 +956,7 @@ static void netc_teardown(struct dsa_switch *ds)
|
|||
netc_destroy_all_lists(priv);
|
||||
netc_deinit_ntmp_priv(priv);
|
||||
netc_remove_all_ports_internal_mdiobus(ds);
|
||||
netc_free_ports_taprio(priv);
|
||||
}
|
||||
|
||||
static bool netc_switch_is_emdio_consumer(struct device_node *ports)
|
||||
|
@ -1099,15 +1119,71 @@ static void netc_switch_get_ip_revision(struct netc_switch *priv)
|
|||
priv->revision = val & IPBRR0_IP_REV;
|
||||
}
|
||||
|
||||
static int netc_add_or_update_ett_entry(struct netc_switch *priv, bool add,
|
||||
bool untagged, u32 ett_eid, u32 ect_eid)
|
||||
{
|
||||
struct netc_cbdrs *cbdrs = &priv->ntmp.cbdrs;
|
||||
struct ett_cfge_data ett_cfge = {};
|
||||
u32 vuda_sqta = FMTEID_VUDA_SQTA;
|
||||
u16 efm_cfg = 0;
|
||||
|
||||
if (ect_eid != NTMP_NULL_ENTRY_ID) {
|
||||
/* Increase egress frame counter */
|
||||
efm_cfg |= FIELD_PREP(ETT_ECA, ETT_ECA_INC);
|
||||
ett_cfge.ec_eid = cpu_to_le32(ect_eid);
|
||||
}
|
||||
|
||||
/* If egress rule is VLAN untagged */
|
||||
if (untagged) {
|
||||
/* delete outer VLAN tag */
|
||||
vuda_sqta |= FIELD_PREP(FMTEID_VUDA, FMTEID_VUDA_DEL_OTAG);
|
||||
/* length change: twos-complement notation */
|
||||
efm_cfg |= FIELD_PREP(ETT_EFM_LEN_CHANGE, ETT_FRM_LEN_DEL_VLAN);
|
||||
}
|
||||
|
||||
ett_cfge.efm_eid = cpu_to_le32(vuda_sqta);
|
||||
ett_cfge.efm_cfg = cpu_to_le16(efm_cfg);
|
||||
|
||||
return ntmp_ett_add_or_update_entry(cbdrs, ett_eid, add, &ett_cfge);
|
||||
}
|
||||
|
||||
int netc_add_ett_group_entries(struct netc_switch *priv,
|
||||
u32 untagged_port_bitmap,
|
||||
u32 ett_base_eid,
|
||||
u32 ect_base_eid)
|
||||
{
|
||||
struct netc_cbdrs *cbdrs = &priv->ntmp.cbdrs;
|
||||
u32 ett_eid = ett_base_eid;
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < priv->num_ports; i++, ett_eid++) {
|
||||
bool untagged = !!(untagged_port_bitmap & BIT(i));
|
||||
u32 ect_eid = NTMP_NULL_ENTRY_ID;
|
||||
|
||||
if (ect_base_eid != NTMP_NULL_ENTRY_ID)
|
||||
ect_eid = ect_base_eid + i;
|
||||
|
||||
err = netc_add_or_update_ett_entry(priv, true, untagged,
|
||||
ett_eid, ect_eid);
|
||||
if (err)
|
||||
goto clear_ett_entries;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
clear_ett_entries:
|
||||
for (i--, ett_eid--; i >= 0; i--, ett_eid--)
|
||||
ntmp_ett_delete_entry(cbdrs, ett_eid);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int netc_switch_add_vlan_egress_rule(struct netc_switch *priv,
|
||||
struct netc_vlan_entry *entry)
|
||||
{
|
||||
struct netc_cbdrs *cbdrs = &priv->ntmp.cbdrs;
|
||||
struct ett_cfge_data ett_cfge = {};
|
||||
u32 ect_eid = NTMP_NULL_ENTRY_ID;
|
||||
u32 ett_eid, vuda_sqta;
|
||||
u32 ett_gid, ect_gid;
|
||||
u16 efm_cfg;
|
||||
u32 ett_eid, ett_gid, ect_gid;
|
||||
int i, err;
|
||||
|
||||
/* step1: find available ect entries and update these entries */
|
||||
|
@ -1131,53 +1207,24 @@ static int netc_switch_add_vlan_egress_rule(struct netc_switch *priv,
|
|||
if (ett_gid == NTMP_NULL_ENTRY_ID) {
|
||||
dev_err(priv->dev, "No free ETT entries found\n");
|
||||
err = -ENOSPC;
|
||||
goto clear_ect_eid;
|
||||
goto clear_ect_gid;
|
||||
}
|
||||
|
||||
ett_eid = ett_gid * priv->num_ports;
|
||||
for (i = 0; i < priv->num_ports; i++, ett_eid++) {
|
||||
/* Specify the FMT entry ID format */
|
||||
vuda_sqta = FMTEID_VUDA_SQTA;
|
||||
efm_cfg = 0;
|
||||
err = netc_add_ett_group_entries(priv, entry->untagged_port_bitmap,
|
||||
ett_eid, ect_eid);
|
||||
if (err)
|
||||
goto clear_ett_gid;
|
||||
|
||||
if (ect_eid != NTMP_NULL_ENTRY_ID) {
|
||||
/* Increase egress frame counter */
|
||||
efm_cfg |= FIELD_PREP(ETT_ECA, ETT_ECA_INC);
|
||||
ett_cfge.ec_eid = cpu_to_le32(ect_eid);
|
||||
ect_eid++;
|
||||
}
|
||||
|
||||
/* If egress rule is VLAN untagged */
|
||||
if (entry->untagged_port_bitmap & BIT(i)) {
|
||||
/* delete outer VLAN tag */
|
||||
vuda_sqta |= FIELD_PREP(FMTEID_VUDA,
|
||||
FMTEID_VUDA_DEL_OTAG);
|
||||
/* length change: twos-complement notation */
|
||||
efm_cfg |= FIELD_PREP(ETT_EFM_LEN_CHANGE,
|
||||
ETT_FRM_LEN_DEL_VLAN);
|
||||
}
|
||||
|
||||
ett_cfge.efm_eid = cpu_to_le32(vuda_sqta);
|
||||
ett_cfge.efm_cfg = cpu_to_le16(efm_cfg);
|
||||
|
||||
/* Add an ETT entry */
|
||||
err = ntmp_ett_add_or_update_entry(cbdrs, ett_eid, true, &ett_cfge);
|
||||
if (err)
|
||||
goto clear_ett_entries;
|
||||
}
|
||||
|
||||
ett_eid = ett_gid * priv->num_ports;
|
||||
entry->cfge.et_eid = cpu_to_le32(ett_eid);
|
||||
entry->ect_gid = ect_gid;
|
||||
|
||||
return 0;
|
||||
|
||||
clear_ett_entries:
|
||||
clear_ett_gid:
|
||||
ntmp_clear_eid_bitmap(priv->ntmp.ett_gid_bitmap, ett_gid);
|
||||
for (i--, ett_eid--; i >= 0; i--, ett_eid--)
|
||||
ntmp_ett_delete_entry(cbdrs, ett_eid);
|
||||
|
||||
clear_ect_eid:
|
||||
clear_ect_gid:
|
||||
/* ECT is a static index table, no need to delete the entries */
|
||||
if (ect_gid != NTMP_NULL_ENTRY_ID)
|
||||
ntmp_clear_eid_bitmap(priv->ntmp.ect_gid_bitmap, ect_gid);
|
||||
|
@ -1185,8 +1232,8 @@ clear_ect_eid:
|
|||
return err;
|
||||
}
|
||||
|
||||
static void netc_switch_delete_vlan_egress_rule(struct netc_switch *priv,
|
||||
struct netc_vlan_entry *entry)
|
||||
void netc_switch_delete_vlan_egress_rule(struct netc_switch *priv,
|
||||
struct netc_vlan_entry *entry)
|
||||
{
|
||||
u32 ett_eid, ett_eid_bit;
|
||||
int i;
|
||||
|
@ -1212,13 +1259,12 @@ static void netc_switch_delete_vlan_egress_rule(struct netc_switch *priv,
|
|||
static int netc_port_update_vlan_egress_rule(struct netc_port *port,
|
||||
struct netc_vlan_entry *entry)
|
||||
{
|
||||
bool untagged = !!(entry->untagged_port_bitmap & BIT(port->index));
|
||||
u32 ett_eid = le32_to_cpu(entry->cfge.et_eid);
|
||||
struct netc_switch *priv = port->switch_priv;
|
||||
struct netc_cbdrs *cbdrs = &priv->ntmp.cbdrs;
|
||||
struct ett_cfge_data ett_cfge = {};
|
||||
u32 ett_eid, ect_eid, vuda_sqta;
|
||||
u16 efm_cfg = 0;
|
||||
u32 ect_eid = NTMP_NULL_ENTRY_ID;
|
||||
|
||||
ett_eid = le32_to_cpu(entry->cfge.et_eid);
|
||||
if (ett_eid == NTMP_NULL_ENTRY_ID)
|
||||
return 0;
|
||||
|
||||
|
@ -1227,26 +1273,10 @@ static int netc_port_update_vlan_egress_rule(struct netc_port *port,
|
|||
ect_eid = entry->ect_gid * priv->num_ports;
|
||||
ect_eid += port->index;
|
||||
ntmp_ect_update_entry(cbdrs, ect_eid);
|
||||
|
||||
efm_cfg |= FIELD_PREP(ETT_ECA, ETT_ECA_INC);
|
||||
ett_cfge.ec_eid = cpu_to_le32(ect_eid);
|
||||
}
|
||||
|
||||
/* Specify the FMT entry ID format */
|
||||
vuda_sqta = FMTEID_VUDA_SQTA;
|
||||
/* If egress rule is VLAN untagged */
|
||||
if (entry->untagged_port_bitmap & BIT(port->index)) {
|
||||
/* delete outer VLAN tag */
|
||||
vuda_sqta |= FIELD_PREP(FMTEID_VUDA, FMTEID_VUDA_DEL_OTAG);
|
||||
/* length change: twos-complement notation */
|
||||
efm_cfg |= FIELD_PREP(ETT_EFM_LEN_CHANGE, ETT_FRM_LEN_DEL_VLAN);
|
||||
}
|
||||
|
||||
ett_cfge.efm_cfg = cpu_to_le16(efm_cfg);
|
||||
ett_cfge.efm_eid = cpu_to_le32(vuda_sqta);
|
||||
|
||||
/* Add an ETT entry */
|
||||
return ntmp_ett_add_or_update_entry(cbdrs, ett_eid, false, &ett_cfge);
|
||||
return netc_add_or_update_ett_entry(priv, false, untagged,
|
||||
ett_eid, ect_eid);
|
||||
}
|
||||
|
||||
static int netc_port_add_vlan_entry(struct netc_port *port, u16 vid,
|
||||
|
@ -1562,14 +1592,6 @@ static int netc_port_del_bcast_fdb_entry(struct netc_port *port, u16 vid)
|
|||
return netc_port_del_fdb_entry(port, bcast, vid);
|
||||
}
|
||||
|
||||
static struct net_device *netc_port_get_net_device(struct netc_port *port)
|
||||
{
|
||||
if (dsa_port_is_cpu(port->dp))
|
||||
return port->dp->conduit;
|
||||
else
|
||||
return port->dp->user;
|
||||
}
|
||||
|
||||
static int netc_port_enable(struct dsa_switch *ds, int port_id,
|
||||
struct phy_device *phy)
|
||||
{
|
||||
|
@ -1616,6 +1638,8 @@ static int netc_port_enable(struct dsa_switch *ds, int port_id,
|
|||
goto del_unaware_vlan_entry;
|
||||
}
|
||||
|
||||
port->enabled = true;
|
||||
|
||||
return 0;
|
||||
|
||||
del_unaware_vlan_entry:
|
||||
|
@ -1642,6 +1666,7 @@ static void netc_port_disable(struct dsa_switch *ds, int port_id)
|
|||
}
|
||||
|
||||
netc_port_del_vlan_entry(port, NETC_STANDALONE_PVID);
|
||||
port->enabled = false;
|
||||
}
|
||||
|
||||
static void netc_port_stp_state_set(struct dsa_switch *ds, int port_id, u8 state)
|
||||
|
@ -2068,100 +2093,6 @@ static int netc_port_cls_flower_stats(struct dsa_switch *ds, int port_id,
|
|||
return netc_port_flow_cls_stats(port, cls);
|
||||
}
|
||||
|
||||
static int netc_suspend(struct dsa_switch *ds)
|
||||
{
|
||||
struct netc_switch *priv = NETC_PRIV(ds);
|
||||
struct pci_dev *pdev = priv->pdev;
|
||||
int port_id;
|
||||
|
||||
cancel_delayed_work_sync(&priv->fdbt_clean);
|
||||
|
||||
for (port_id = 0; port_id < ds->num_ports; port_id++) {
|
||||
struct netc_port *port = NETC_PORT(priv, port_id);
|
||||
struct net_device *ndev;
|
||||
|
||||
if (!port->dp)
|
||||
continue;
|
||||
|
||||
ndev = netc_port_get_net_device(port);
|
||||
if (netif_running(ndev))
|
||||
netc_port_disable(ds, port_id);
|
||||
}
|
||||
|
||||
netc_destroy_fdb_list(priv);
|
||||
netc_destroy_vlan_list(priv);
|
||||
netc_deinit_ntmp_priv(priv);
|
||||
pci_disable_device(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netc_resume(struct dsa_switch *ds)
|
||||
{
|
||||
struct netc_switch *priv = NETC_PRIV(ds);
|
||||
struct pci_dev *pdev = priv->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct netc_port *cpu_port;
|
||||
int port_id, err;
|
||||
|
||||
pcie_flr(pdev);
|
||||
err = pci_enable_device_mem(pdev);
|
||||
if (err)
|
||||
return dev_err_probe(dev, err, "Failed to enable device\n");
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
err = netc_init_ntmp_priv(priv);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
netc_switch_dos_default_config(priv);
|
||||
netc_switch_vfht_default_config(priv);
|
||||
netc_switch_isit_key_config(priv);
|
||||
|
||||
err = netc_switch_bpt_default_config(priv);
|
||||
if (err)
|
||||
goto deinit_ntmp_priv;
|
||||
|
||||
cpu_port = NETC_PORT(priv, ds->num_ports - 1);
|
||||
for (port_id = 0; port_id < ds->num_ports; port_id++) {
|
||||
struct netc_port *port = NETC_PORT(priv, port_id);
|
||||
struct net_device *ndev;
|
||||
u16 pvid;
|
||||
|
||||
if (!port->dp)
|
||||
continue;
|
||||
|
||||
netc_port_default_config(port);
|
||||
ndev = netc_port_get_net_device(port);
|
||||
if (netif_running(ndev)) {
|
||||
err = netc_port_enable(ds, port_id, NULL);
|
||||
if (err)
|
||||
goto deinit_ntmp_priv;
|
||||
|
||||
if (port->bridge)
|
||||
pvid = port->vlan_aware ? NETC_CPU_PORT_PVID :
|
||||
NETC_VLAN_UNAWARE_PVID;
|
||||
else
|
||||
pvid = NETC_STANDALONE_PVID;
|
||||
|
||||
err = netc_port_set_fdb_entry(cpu_port, ndev->dev_addr,
|
||||
pvid);
|
||||
if (err)
|
||||
goto deinit_ntmp_priv;
|
||||
}
|
||||
}
|
||||
|
||||
schedule_delayed_work(&priv->fdbt_clean, priv->fdbt_acteu_interval);
|
||||
|
||||
return 0;
|
||||
|
||||
deinit_ntmp_priv:
|
||||
netc_deinit_ntmp_priv(priv);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void netc_phylink_get_caps(struct dsa_switch *ds, int port_id,
|
||||
struct phylink_config *config)
|
||||
{
|
||||
|
|
462
drivers/net/dsa/netc/netc_pm.c
Normal file
462
drivers/net/dsa/netc/netc_pm.c
Normal file
|
@ -0,0 +1,462 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
|
||||
/*
|
||||
* Power Management of NXP NETC switch driver
|
||||
* Copyright 2025 NXP
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "netc_switch.h"
|
||||
|
||||
static void netc_port_save_config_to_db(struct netc_port *port)
|
||||
{
|
||||
struct netc_port_db *db = &port->db;
|
||||
int i;
|
||||
|
||||
if (!port->dp)
|
||||
return;
|
||||
|
||||
db->bpdvr = netc_port_rd(port, NETC_BPDVR);
|
||||
db->bpcr = netc_port_rd(port, NETC_BPCR);
|
||||
db->maxfrm = netc_mac_port_rd(port, NETC_PM_MAXFRM(0));
|
||||
db->bpstgsr = netc_port_rd(port, NETC_BPSTGSR);
|
||||
db->ptgscr = netc_port_rd(port, NETC_PTGSCR);
|
||||
|
||||
for (i = 0; i < NETC_TC_NUM; i++) {
|
||||
db->ptctmsdur[i] = netc_port_rd(port, NETC_PTCTMSDUR(i));
|
||||
db->ptccbsr1[i] = netc_port_rd(port, NETC_PTCCBSR1(i));
|
||||
db->ptccbsr2[i] = netc_port_rd(port, NETC_PTCCBSR2(i));
|
||||
}
|
||||
|
||||
db->mmcsr = netc_port_rd(port, NETC_MAC_MERGE_MMCSR);
|
||||
db->ptp_filter = port->ptp_filter;
|
||||
port->ptp_filter = HWTSTAMP_FILTER_NONE;
|
||||
}
|
||||
|
||||
static int netc_port_restore_config_from_db(struct netc_port *port)
|
||||
{
|
||||
struct netc_port_db *db = &port->db;
|
||||
int i;
|
||||
|
||||
netc_port_wr(port, NETC_BPDVR, db->bpdvr);
|
||||
netc_port_wr(port, NETC_BPCR, db->bpcr);
|
||||
netc_mac_port_wr(port, NETC_PM_MAXFRM(0), db->maxfrm);
|
||||
netc_port_wr(port, NETC_BPSTGSR, db->bpstgsr);
|
||||
|
||||
for (i = 0; i < NETC_TC_NUM; i++) {
|
||||
netc_port_wr(port, NETC_PTCTMSDUR(i), db->ptctmsdur[i]);
|
||||
netc_port_wr(port, NETC_PTCCBSR1(i), db->ptccbsr1[i]);
|
||||
netc_port_wr(port, NETC_PTCCBSR2(i), db->ptccbsr2[i]);
|
||||
}
|
||||
|
||||
netc_port_wr(port, NETC_PTGSCR, db->ptgscr);
|
||||
netc_port_wr(port, NETC_MAC_MERGE_MMCSR, db->mmcsr);
|
||||
|
||||
return netc_port_set_ptp_filter(port, db->ptp_filter);
|
||||
}
|
||||
|
||||
static void netc_restore_bpt_entries(struct netc_switch *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&priv->bpt_lock);
|
||||
|
||||
for (i = 0; i < priv->caps.num_bp; i++) {
|
||||
struct bpt_cfge_data *cfge = &priv->bpt_list[i];
|
||||
|
||||
ntmp_bpt_update_entry(&priv->ntmp.cbdrs, i, cfge);
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->bpt_lock);
|
||||
}
|
||||
|
||||
static int netc_restore_vlan_egress_rule(struct netc_switch *priv,
|
||||
struct netc_vlan_entry *entry)
|
||||
{
|
||||
u32 ett_base_eid = le32_to_cpu(entry->cfge.et_eid);
|
||||
u32 ect_base_eid = NTMP_NULL_ENTRY_ID;
|
||||
|
||||
if (entry->ect_gid != NTMP_NULL_ENTRY_ID)
|
||||
ect_base_eid = entry->ect_gid * priv->num_ports;
|
||||
|
||||
return netc_add_ett_group_entries(priv, entry->untagged_port_bitmap,
|
||||
ett_base_eid, ect_base_eid);
|
||||
}
|
||||
|
||||
static int netc_restore_vlan_entry(struct netc_switch *priv,
|
||||
struct netc_vlan_entry *entry)
|
||||
{
|
||||
struct netc_cbdrs *cbdrs = &priv->ntmp.cbdrs;
|
||||
struct device *dev = priv->dev;
|
||||
u16 vid = entry->vid;
|
||||
int err;
|
||||
|
||||
if (vid != NETC_STANDALONE_PVID) {
|
||||
err = netc_restore_vlan_egress_rule(priv, entry);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to restore VLAN %u egress rule\n",
|
||||
vid);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = ntmp_vft_add_entry(cbdrs, &entry->entry_id, vid, &entry->cfge);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to restore VFT entry, VLAN %u\n", vid);
|
||||
goto del_vlan_egress_rule;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
del_vlan_egress_rule:
|
||||
if (vid != NETC_STANDALONE_PVID)
|
||||
netc_switch_delete_vlan_egress_rule(priv, entry);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int netc_restore_vlan_entries(struct netc_switch *priv)
|
||||
{
|
||||
struct netc_cbdrs *cbdrs = &priv->ntmp.cbdrs;
|
||||
struct netc_vlan_entry *entry, *tmp;
|
||||
int err;
|
||||
|
||||
mutex_lock(&priv->vft_lock);
|
||||
|
||||
hlist_for_each_entry(entry, &priv->vlan_list, node) {
|
||||
err = netc_restore_vlan_entry(priv, entry);
|
||||
if (err)
|
||||
goto del_vlan_entries;
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->vft_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
del_vlan_entries:
|
||||
hlist_for_each_entry(tmp, &priv->vlan_list, node) {
|
||||
if (tmp == entry)
|
||||
break;
|
||||
|
||||
ntmp_vft_delete_entry(cbdrs, tmp->vid);
|
||||
|
||||
if (tmp->vid != NETC_STANDALONE_PVID)
|
||||
netc_switch_delete_vlan_egress_rule(priv, tmp);
|
||||
}
|
||||
|
||||
netc_destroy_vlan_list(priv);
|
||||
bitmap_zero(priv->ntmp.ect_gid_bitmap, priv->ntmp.ect_bitmap_size);
|
||||
bitmap_zero(priv->ntmp.ett_gid_bitmap, priv->ntmp.ett_bitmap_size);
|
||||
|
||||
mutex_unlock(&priv->vft_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void netc_remove_vlan_entries(struct netc_switch *priv)
|
||||
{
|
||||
struct netc_cbdrs *cbdrs = &priv->ntmp.cbdrs;
|
||||
struct netc_vlan_entry *entry;
|
||||
struct hlist_node *tmp;
|
||||
|
||||
mutex_lock(&priv->vft_lock);
|
||||
|
||||
hlist_for_each_entry_safe(entry, tmp, &priv->vlan_list, node) {
|
||||
ntmp_vft_delete_entry(cbdrs, entry->vid);
|
||||
|
||||
if (entry->vid != NETC_STANDALONE_PVID)
|
||||
netc_switch_delete_vlan_egress_rule(priv, entry);
|
||||
|
||||
netc_del_vlan_entry(entry);
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->vft_lock);
|
||||
}
|
||||
|
||||
static int netc_restore_fdbt_entries(struct netc_switch *priv)
|
||||
{
|
||||
struct netc_cbdrs *cbdrs = &priv->ntmp.cbdrs;
|
||||
struct netc_fdb_entry *entry, *tmp;
|
||||
int err;
|
||||
|
||||
mutex_lock(&priv->fdbt_lock);
|
||||
|
||||
hlist_for_each_entry(entry, &priv->fdb_list, node) {
|
||||
err = ntmp_fdbt_add_entry(cbdrs, &entry->entry_id,
|
||||
&entry->keye, &entry->cfge);
|
||||
if (err) {
|
||||
dev_err(priv->dev,
|
||||
"Failed to restore FDBT entry, mac: %pm vid: %u\n",
|
||||
entry->keye.mac_addr, le16_to_cpu(entry->keye.fid));
|
||||
goto del_fdb_entries;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->fdbt_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
del_fdb_entries:
|
||||
hlist_for_each_entry(tmp, &priv->fdb_list, node) {
|
||||
if (tmp == entry)
|
||||
break;
|
||||
|
||||
ntmp_fdbt_delete_entry(cbdrs, tmp->entry_id);
|
||||
}
|
||||
|
||||
netc_destroy_fdb_list(priv);
|
||||
|
||||
mutex_unlock(&priv->fdbt_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void netc_remove_fdbt_entries(struct netc_switch *priv)
|
||||
{
|
||||
struct netc_cbdrs *cbdrs = &priv->ntmp.cbdrs;
|
||||
struct netc_fdb_entry *entry;
|
||||
struct hlist_node *tmp;
|
||||
|
||||
mutex_lock(&priv->fdbt_lock);
|
||||
|
||||
hlist_for_each_entry_safe(entry, tmp, &priv->fdb_list, node) {
|
||||
ntmp_fdbt_delete_entry(cbdrs, entry->entry_id);
|
||||
netc_del_fdb_entry(entry);
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->fdbt_lock);
|
||||
}
|
||||
|
||||
static int netc_port_restore_taprio(struct netc_port *port)
|
||||
{
|
||||
struct netc_switch *priv = port->switch_priv;
|
||||
u32 entry_id = port->index;
|
||||
|
||||
if (!port->taprio)
|
||||
return 0;
|
||||
|
||||
return netc_setup_taprio(&priv->ntmp, entry_id, port->taprio);
|
||||
}
|
||||
|
||||
static int netc_port_restore_config(struct netc_port *port)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!port->dp)
|
||||
return 0;
|
||||
|
||||
netc_port_fixed_config(port);
|
||||
|
||||
err = netc_port_restore_config_from_db(port);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = netc_port_restore_taprio(port);
|
||||
if (err)
|
||||
goto del_ptp_filter;
|
||||
|
||||
return 0;
|
||||
|
||||
del_ptp_filter:
|
||||
netc_port_set_ptp_filter(port, HWTSTAMP_FILTER_NONE);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void netc_port_remove_config(struct netc_port *port)
|
||||
{
|
||||
if (!port->dp)
|
||||
return;
|
||||
|
||||
if (port->taprio)
|
||||
netc_port_reset_taprio(port);
|
||||
|
||||
netc_port_set_ptp_filter(port, HWTSTAMP_FILTER_NONE);
|
||||
}
|
||||
|
||||
static int netc_restore_ports_config(struct netc_switch *priv)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < priv->num_ports; i++) {
|
||||
err = netc_port_restore_config(NETC_PORT(priv, i));
|
||||
if (err)
|
||||
goto del_ports_config;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
del_ports_config:
|
||||
while (--i >= 0)
|
||||
netc_port_remove_config(NETC_PORT(priv, i));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void netc_remove_ports_config(struct netc_switch *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->num_ports; i++)
|
||||
netc_port_remove_config(NETC_PORT(priv, i));
|
||||
}
|
||||
|
||||
static void netc_enable_all_cdbrs(struct netc_switch *priv)
|
||||
{
|
||||
struct netc_cbdrs *cbdrs = &priv->ntmp.cbdrs;
|
||||
struct netc_switch_regs *regs = &priv->regs;
|
||||
int i;
|
||||
|
||||
netc_base_wr(regs, NETC_CCAR, NETC_DEFAULT_CMD_CACHE_ATTR);
|
||||
|
||||
for (i = 0; i < cbdrs->cbdr_num; i++)
|
||||
netc_enable_cbdr(&cbdrs->ring[i]);
|
||||
}
|
||||
|
||||
static int netc_restore_hw_config(struct netc_switch *priv)
|
||||
{
|
||||
int err;
|
||||
|
||||
netc_enable_all_cdbrs(priv);
|
||||
netc_switch_fixed_config(priv);
|
||||
netc_restore_bpt_entries(priv);
|
||||
|
||||
/* Restore VLAN filter table entries */
|
||||
err = netc_restore_vlan_entries(priv);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Restore FDB table */
|
||||
err = netc_restore_fdbt_entries(priv);
|
||||
if (err)
|
||||
goto del_vlan_entries;
|
||||
|
||||
err = netc_restore_ports_config(priv);
|
||||
if (err)
|
||||
goto del_fdb_entries;
|
||||
|
||||
err = netc_restore_flower_list_config(&priv->ntmp);
|
||||
if (err)
|
||||
goto del_ports_config;
|
||||
|
||||
return 0;
|
||||
|
||||
del_ports_config:
|
||||
netc_remove_ports_config(priv);
|
||||
del_fdb_entries:
|
||||
netc_remove_fdbt_entries(priv);
|
||||
del_vlan_entries:
|
||||
netc_remove_vlan_entries(priv);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void netc_disable_port_clk(struct netc_port *port)
|
||||
{
|
||||
if (!port->enabled)
|
||||
return;
|
||||
|
||||
clk_disable_unprepare(port->ref_clk);
|
||||
}
|
||||
|
||||
static int netc_enable_port_clk(struct netc_port *port)
|
||||
{
|
||||
if (!port->enabled)
|
||||
return 0;
|
||||
|
||||
return clk_prepare_enable(port->ref_clk);
|
||||
}
|
||||
|
||||
int netc_suspend(struct dsa_switch *ds)
|
||||
{
|
||||
struct netc_switch *priv = ds->priv;
|
||||
struct pci_dev *pdev = priv->pdev;
|
||||
bool power_off;
|
||||
int i;
|
||||
|
||||
/* NETC keeps power in suspend mode if WOL is enabled. If
|
||||
* WOL is not enabled, we assume that NETC will be powered
|
||||
* off in suspend mode, even though it may not actually be
|
||||
* powered off. Because currently there is no helper function
|
||||
* to query whether NETC will be powered off in suspend mode.
|
||||
*/
|
||||
power_off = !(netc_ierb_may_wakeonlan() > 0);
|
||||
cancel_delayed_work_sync(&priv->fdbt_clean);
|
||||
|
||||
for (i = 0; i < priv->num_ports; i++) {
|
||||
struct netc_port *port = NETC_PORT(priv, i);
|
||||
|
||||
if (power_off) {
|
||||
netc_port_save_config_to_db(port);
|
||||
netc_port_remove_config(port);
|
||||
}
|
||||
|
||||
netc_disable_port_clk(port);
|
||||
}
|
||||
|
||||
if (power_off) {
|
||||
netc_clear_flower_table_restored_flag(&priv->ntmp);
|
||||
} else {
|
||||
pci_save_state(pdev);
|
||||
pci_set_power_state(pdev, PCI_D3hot);
|
||||
}
|
||||
|
||||
pci_disable_device(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netc_resume(struct dsa_switch *ds)
|
||||
{
|
||||
struct netc_switch *priv = ds->priv;
|
||||
struct pci_dev *pdev = priv->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
bool power_off;
|
||||
int i, err;
|
||||
|
||||
power_off = !(netc_ierb_may_wakeonlan() > 0);
|
||||
|
||||
/* If WOL is not enabled, we assume that NETC is powered off
|
||||
* in suspend mode, and then restore the switch configuration
|
||||
* when it resumes. But in fact NETC may not be powered off,
|
||||
* for example, the system suspend fails, or NETC remains
|
||||
* powered on for other reasons. But we do not know that NETC
|
||||
* is not powered off in suspend mode. In this case, the switch
|
||||
* still retains its configuration, which will cause the
|
||||
* configuration recovery to fail. Therefore, we need to reset
|
||||
* the switch through FLR and then restore the configuration.
|
||||
*/
|
||||
if (power_off)
|
||||
pcie_flr(pdev);
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to enable device\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
if (power_off) {
|
||||
err = netc_restore_hw_config(priv);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to restore configurations\n");
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
}
|
||||
|
||||
for (i = 0; i < priv->num_ports; i++) {
|
||||
err = netc_enable_port_clk(NETC_PORT(priv, i));
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to enable port %d clock\n", i);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
schedule_delayed_work(&priv->fdbt_clean, priv->fdbt_acteu_interval);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -183,7 +183,7 @@ static int netc_port_add_l2_l4_ptp_filter(struct netc_port *port)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int netc_port_set_ptp_filter(struct netc_port *port, int ptp_filter)
|
||||
int netc_port_set_ptp_filter(struct netc_port *port, int ptp_filter)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
@ -239,7 +239,7 @@ int netc_port_hwtstamp_set(struct dsa_switch *ds, int port_id,
|
|||
port->offloads |= NETC_FLAG_TX_ONESTEP_SYNC;
|
||||
break;
|
||||
case HWTSTAMP_TX_OFF:
|
||||
port->offloads &= !(NETC_FLAG_TX_TSTAMP |
|
||||
port->offloads &= ~(NETC_FLAG_TX_TSTAMP |
|
||||
NETC_FLAG_TX_ONESTEP_SYNC);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -100,6 +100,19 @@ enum netc_ptp_type {
|
|||
NETC_PTP_MAX,
|
||||
};
|
||||
|
||||
struct netc_port_db {
|
||||
u32 bpdvr;
|
||||
u32 bpcr;
|
||||
u32 maxfrm;
|
||||
u32 bpstgsr;
|
||||
u32 ptgscr;
|
||||
u32 ptctmsdur[NETC_TC_NUM];
|
||||
u32 ptccbsr1[NETC_TC_NUM];
|
||||
u32 ptccbsr2[NETC_TC_NUM];
|
||||
u32 mmcsr;
|
||||
int ptp_filter;
|
||||
};
|
||||
|
||||
struct netc_switch;
|
||||
|
||||
struct netc_port {
|
||||
|
@ -120,6 +133,7 @@ struct netc_port {
|
|||
u16 pvid;
|
||||
u16 vlan_aware:1;
|
||||
u16 tx_pause:1;
|
||||
u16 enabled:1;
|
||||
|
||||
enum netc_port_offloads offloads;
|
||||
|
||||
|
@ -138,6 +152,8 @@ struct netc_port {
|
|||
|
||||
bool tx_lpi_enabled;
|
||||
u32 tx_lpi_timer;
|
||||
struct netc_port_db db;
|
||||
struct tc_taprio_qopt_offload *taprio;
|
||||
};
|
||||
|
||||
enum netc_port_mac {
|
||||
|
@ -247,6 +263,16 @@ void netc_port_set_tx_pause(struct netc_port *port, bool tx_pause);
|
|||
void netc_port_set_all_tc_msdu(struct netc_port *port, u32 *max_sdu);
|
||||
struct pci_dev *netc_switch_get_timer(struct netc_switch *priv);
|
||||
void netc_mac_port_wr(struct netc_port *port, u32 reg, u32 val);
|
||||
u32 netc_mac_port_rd(struct netc_port *port, u32 reg);
|
||||
void netc_destroy_fdb_list(struct netc_switch *priv);
|
||||
void netc_destroy_vlan_list(struct netc_switch *priv);
|
||||
void netc_switch_fixed_config(struct netc_switch *priv);
|
||||
void netc_port_fixed_config(struct netc_port *port);
|
||||
int netc_add_ett_group_entries(struct netc_switch *priv,
|
||||
u32 untagged_port_bitmap,
|
||||
u32 ett_base_eid, u32 ect_base_eid);
|
||||
void netc_switch_delete_vlan_egress_rule(struct netc_switch *priv,
|
||||
struct netc_vlan_entry *entry);
|
||||
|
||||
/* TC APIs */
|
||||
int netc_tc_query_caps(struct tc_query_caps_base *base);
|
||||
|
@ -256,6 +282,7 @@ int netc_tc_setup_cbs(struct netc_switch *priv, int port,
|
|||
struct tc_cbs_qopt_offload *cbs);
|
||||
int netc_tc_setup_taprio(struct netc_switch *priv, int port,
|
||||
struct tc_taprio_qopt_offload *taprio);
|
||||
int netc_port_reset_taprio(struct netc_port *port);
|
||||
int netc_port_flow_cls_replace(struct netc_port *port,
|
||||
struct flow_cls_offload *f);
|
||||
int netc_port_flow_cls_destroy(struct netc_port *port,
|
||||
|
@ -263,6 +290,7 @@ int netc_port_flow_cls_destroy(struct netc_port *port,
|
|||
int netc_port_flow_cls_stats(struct netc_port *port,
|
||||
struct flow_cls_offload *f);
|
||||
void netc_destroy_flower_list(struct netc_switch *priv);
|
||||
void netc_port_free_taprio(struct netc_port *port);
|
||||
|
||||
/* ethtool APIs */
|
||||
void netc_port_mm_commit_preemptible_tcs(struct netc_port *port);
|
||||
|
@ -302,6 +330,11 @@ bool netc_port_rxtstamp(struct dsa_switch *ds, int port,
|
|||
struct sk_buff *skb, unsigned int type);
|
||||
void netc_port_txtstamp(struct dsa_switch *ds, int port_id,
|
||||
struct sk_buff *skb);
|
||||
int netc_port_set_ptp_filter(struct netc_port *port, int ptp_filter);
|
||||
|
||||
/* Power Management */
|
||||
int netc_suspend(struct dsa_switch *ds);
|
||||
int netc_resume(struct dsa_switch *ds);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DEBUG_FS)
|
||||
void netc_create_debugfs(struct netc_switch *priv);
|
||||
|
|
|
@ -294,6 +294,14 @@ disable_time_gating:
|
|||
return err;
|
||||
}
|
||||
|
||||
void netc_port_free_taprio(struct netc_port *port)
|
||||
{
|
||||
if (port->taprio) {
|
||||
taprio_offload_free(port->taprio);
|
||||
port->taprio = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int netc_tc_taprio_replace(struct netc_switch *priv, int port_id,
|
||||
struct tc_taprio_qopt_offload *taprio)
|
||||
{
|
||||
|
@ -311,10 +319,13 @@ static int netc_tc_taprio_replace(struct netc_switch *priv, int port_id,
|
|||
if (err)
|
||||
netc_port_reset_mqprio(port);
|
||||
|
||||
netc_port_free_taprio(port);
|
||||
port->taprio = taprio_offload_get(taprio);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int netc_port_reset_taprio(struct netc_port *port)
|
||||
int netc_port_reset_taprio(struct netc_port *port)
|
||||
{
|
||||
/* Remove both operational and administrative gate control list from
|
||||
* the corresponding table entry by disabling time gate scheduling on
|
||||
|
@ -341,6 +352,7 @@ static int netc_tc_taprio_destroy(struct netc_switch *priv, int port_id)
|
|||
struct netc_port *port = NETC_PORT(priv, port_id);
|
||||
|
||||
netc_port_reset_taprio(port);
|
||||
netc_port_free_taprio(port);
|
||||
netc_port_reset_mqprio(port);
|
||||
|
||||
return 0;
|
||||
|
@ -632,8 +644,6 @@ static int netc_setup_trap_redirect(struct ntmp_priv *ntmp, int port_id,
|
|||
}
|
||||
|
||||
netc_rpt_entry_config(police_act, rpt_entry);
|
||||
police_tbl->rpt_eid = police_act->hw_index;
|
||||
refcount_set(&police_tbl->refcount, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -688,12 +698,15 @@ static int netc_setup_trap_redirect(struct ntmp_priv *ntmp, int port_id,
|
|||
|
||||
rule->lastused = jiffies;
|
||||
rule->key_tbl = key_tbl;
|
||||
rule->isct_eid = isct_eid;
|
||||
|
||||
if (police_act) {
|
||||
if (reused_police_tbl) {
|
||||
rule->police_tbl = reused_police_tbl;
|
||||
refcount_inc(&reused_police_tbl->refcount);
|
||||
} else {
|
||||
police_tbl->rpt_entry = no_free_ptr(rpt_entry);
|
||||
refcount_set(&police_tbl->refcount, 1);
|
||||
rule->police_tbl = no_free_ptr(police_tbl);
|
||||
}
|
||||
}
|
||||
|
@ -769,22 +782,19 @@ static void netc_delete_trap_redirect_flower_rule(struct ntmp_priv *ntmp,
|
|||
struct netc_cbdrs *cbdrs = &ntmp->cbdrs;
|
||||
struct ntmp_ipft_entry *ipft_entry;
|
||||
struct ntmp_ist_entry *ist_entry;
|
||||
u32 isct_eid;
|
||||
|
||||
ipft_entry = key_tbl->ipft_entry;
|
||||
ist_entry = key_tbl->ist_entry;
|
||||
|
||||
ntmp_ipft_delete_entry(cbdrs, ipft_entry->entry_id);
|
||||
|
||||
if (ist_entry) {
|
||||
if (ist_entry)
|
||||
ntmp_ist_delete_entry(cbdrs, ist_entry->entry_id);
|
||||
|
||||
isct_eid = le32_to_cpu(ist_entry->cfge.isc_eid);
|
||||
if (isct_eid != NTMP_NULL_ENTRY_ID) {
|
||||
ntmp_isct_operate_entry(cbdrs, isct_eid,
|
||||
NTMP_CMD_DELETE, NULL);
|
||||
ntmp_clear_eid_bitmap(ntmp->isct_eid_bitmap, isct_eid);
|
||||
}
|
||||
if (rule->isct_eid != NTMP_NULL_ENTRY_ID) {
|
||||
ntmp_isct_operate_entry(cbdrs, rule->isct_eid,
|
||||
NTMP_CMD_DELETE, NULL);
|
||||
ntmp_clear_eid_bitmap(ntmp->isct_eid_bitmap, rule->isct_eid);
|
||||
}
|
||||
|
||||
netc_free_flower_police_tbl(ntmp, police_tbl);
|
||||
|
@ -840,17 +850,12 @@ static int netc_trap_redirect_flower_stat(struct ntmp_priv *ntmp,
|
|||
u64 *drop_cnt)
|
||||
{
|
||||
struct ntmp_ipft_entry *ipft_entry = rule->key_tbl->ipft_entry;
|
||||
struct ntmp_ist_entry *ist_entry = rule->key_tbl->ist_entry;
|
||||
struct ntmp_ipft_entry *ipft_query __free(kfree) = NULL;
|
||||
u32 isct_eid = NTMP_NULL_ENTRY_ID;
|
||||
struct isct_stse_data stse = {0};
|
||||
int err;
|
||||
|
||||
if (ist_entry)
|
||||
isct_eid = le32_to_cpu(ist_entry->cfge.isc_eid);
|
||||
|
||||
if (isct_eid != NTMP_NULL_ENTRY_ID) {
|
||||
err = ntmp_isct_operate_entry(&ntmp->cbdrs, isct_eid,
|
||||
if (rule->isct_eid != NTMP_NULL_ENTRY_ID) {
|
||||
err = ntmp_isct_operate_entry(&ntmp->cbdrs, rule->isct_eid,
|
||||
NTMP_CMD_QU, &stse);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
@ -1111,6 +1111,11 @@ netdev_tx_t enetc_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|||
u8 udp, msgtype, twostep;
|
||||
u16 offset1, offset2;
|
||||
|
||||
if (unlikely(netif_carrier_ok(ndev) == false)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
/* Mark tx timestamp type on enetc_cb->flag if requires */
|
||||
if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
|
||||
(priv->active_offloads & ENETC_F_TX_TSTAMP_MASK))
|
||||
|
|
|
@ -255,6 +255,8 @@
|
|||
|
||||
/* Port operational register */
|
||||
#define ENETC4_POR 0x4100
|
||||
#define POR_TXDIS BIT(0)
|
||||
#define POR_RXDIS BIT(1)
|
||||
|
||||
/* Port status register */
|
||||
#define ENETC4_PSR 0x4104
|
||||
|
|
|
@ -270,9 +270,6 @@ static void enetc4_configure_port(struct enetc_pf *pf)
|
|||
|
||||
/* Master enable for all SIs */
|
||||
enetc4_enable_all_si(pf);
|
||||
|
||||
/* Enable port transmit/receive */
|
||||
enetc_port_wr(hw, ENETC4_POR, 0);
|
||||
}
|
||||
|
||||
static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
|
||||
|
@ -646,9 +643,12 @@ static void enetc4_set_tx_pause(struct enetc_pf *pf, int num_rxbdr, bool tx_paus
|
|||
|
||||
static void enetc4_enable_mac(struct enetc_pf *pf, bool en)
|
||||
{
|
||||
struct enetc_hw *hw = &pf->si->hw;
|
||||
struct enetc_si *si = pf->si;
|
||||
u32 val;
|
||||
|
||||
enetc_port_wr(hw, ENETC4_POR, en ? 0 : POR_TXDIS | POR_RXDIS);
|
||||
|
||||
val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0));
|
||||
val &= ~(PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN);
|
||||
val |= en ? (PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN) : 0;
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#define IMX94_EXT_PIN_CONTROL 0x10
|
||||
#define MAC2_MAC3_SEL BIT(1)
|
||||
|
||||
#define IMX94_CFG_LINK_PCS_PROT(a) (0x14 + (a) * 4)
|
||||
#define IMX94_NETC_LINK_CFG(a) (0x4c + (a) * 4)
|
||||
#define NETC_LINK_CFG_MII_PROT GENMASK(3, 0)
|
||||
#define NETC_LINK_CFG_IO_VAR GENMASK(19, 16)
|
||||
|
@ -274,17 +273,9 @@ static int imx94_link_config(struct netc_blk_ctrl *priv,
|
|||
return -EINVAL;
|
||||
|
||||
val = mii_proto & NETC_LINK_CFG_MII_PROT;
|
||||
if (mii_proto == MII_PROT_SERIAL) {
|
||||
int pcs_proto = PCS_PROT_1G_SGMII;
|
||||
|
||||
if (pcs_proto == PHY_INTERFACE_MODE_2500BASEX)
|
||||
pcs_proto = PCS_PROT_2500M_SGMII;
|
||||
|
||||
netc_reg_write(priv->netcmix, IMX94_CFG_LINK_PCS_PROT(link_id),
|
||||
pcs_proto);
|
||||
if (mii_proto == MII_PROT_SERIAL)
|
||||
val = u32_replace_bits(val, IO_VAR_16FF_16G_SERDES,
|
||||
NETC_LINK_CFG_IO_VAR);
|
||||
}
|
||||
|
||||
netc_reg_write(priv->netcmix, IMX94_NETC_LINK_CFG(link_id), val);
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ void netc_show_psfp_flower(struct seq_file *s, struct netc_flower_rule *rule)
|
|||
struct ntmp_isit_entry *isit_entry = rule->key_tbl->isit_entry;
|
||||
struct ntmp_ist_entry *ist_entry = rule->key_tbl->ist_entry;
|
||||
struct ntmp_isft_entry *isft_entry = rule->isft_entry;
|
||||
struct netc_gate_tbl *gate_tbl = rule->gate_tbl;
|
||||
u32 rpt_eid, isct_eid;
|
||||
|
||||
seq_printf(s, "ISIT entry ID:0x%x\n", isit_entry->entry_id);
|
||||
|
@ -55,9 +56,11 @@ void netc_show_psfp_flower(struct seq_file *s, struct netc_flower_rule *rule)
|
|||
seq_printf(s, "RPT entry ID: 0x%x\n", rpt_eid);
|
||||
seq_printf(s, "ISCT entry ID: 0x%x\n", isct_eid);
|
||||
|
||||
if (rule->gate_tbl) {
|
||||
seq_printf(s, "SGIT entry ID: 0x%x\n", rule->gate_tbl->sgit_eid);
|
||||
seq_printf(s, "SGCLT entry ID: 0x%x\n", rule->gate_tbl->sgclt_eid);
|
||||
if (gate_tbl) {
|
||||
seq_printf(s, "SGIT entry ID: 0x%x\n",
|
||||
gate_tbl->sgit_entry->entry_id);
|
||||
seq_printf(s, "SGCLT entry ID: 0x%x\n",
|
||||
gate_tbl->sgclt_entry->entry_id);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(netc_show_psfp_flower);
|
||||
|
|
|
@ -141,7 +141,7 @@ netc_find_flower_gate_table(struct ntmp_priv *priv, u32 index)
|
|||
if (!gate_tbl)
|
||||
continue;
|
||||
|
||||
if (gate_tbl->sgit_eid == index)
|
||||
if (gate_tbl->sgit_entry->entry_id == index)
|
||||
return gate_tbl;
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,7 @@ netc_find_flower_police_table(struct ntmp_priv *priv, u32 index)
|
|||
if (!police_tbl)
|
||||
continue;
|
||||
|
||||
if (police_tbl->rpt_eid == index)
|
||||
if (police_tbl->rpt_entry->entry_id == index)
|
||||
return police_tbl;
|
||||
}
|
||||
|
||||
|
@ -349,24 +349,21 @@ static void netc_psfp_gate_entry_config(struct ntmp_priv *priv,
|
|||
struct ntmp_sgit_entry *sgit_entry,
|
||||
struct ntmp_sgclt_entry *sgclt_entry)
|
||||
{
|
||||
u32 cycle_time, cycle_time_ext, num_gates;
|
||||
u32 cycle_time_ext = gate_entry->gate.cycletimeext;
|
||||
u32 num_gates = gate_entry->gate.num_entries;
|
||||
u32 cycle_time = gate_entry->gate.cycletime;
|
||||
u64 base_time = gate_entry->gate.basetime;
|
||||
u8 sgit_cfg, sgit_icfg = SGIT_GST;
|
||||
u8 sgclt_extcfg = SGCLT_EXT_GTST;
|
||||
int i;
|
||||
|
||||
num_gates = gate_entry->gate.num_entries;
|
||||
cycle_time = gate_entry->gate.cycletime;
|
||||
cycle_time_ext = gate_entry->gate.cycletimeext;
|
||||
|
||||
if (gate_entry->gate.prio >= 0) {
|
||||
sgit_icfg |= FIELD_PREP(SGIT_IPV, gate_entry->gate.prio);
|
||||
sgit_icfg |= SGIT_OIPV;
|
||||
}
|
||||
|
||||
if (priv->adjust_base_time)
|
||||
base_time = priv->adjust_base_time(priv, base_time,
|
||||
gate_entry->gate.cycletime);
|
||||
base_time = priv->adjust_base_time(priv, base_time, cycle_time);
|
||||
|
||||
sgit_cfg = FIELD_PREP(SGIT_SDU_TYPE, SDU_TYPE_MPDU);
|
||||
sgit_entry->acfge.admin_base_time = cpu_to_le64(base_time);
|
||||
|
@ -816,8 +813,6 @@ int netc_setup_psfp(struct ntmp_priv *priv, int port_id,
|
|||
}
|
||||
|
||||
netc_rpt_entry_config(police_entry, rpt_entry);
|
||||
police_tbl->rpt_eid = police_entry->hw_index;
|
||||
refcount_set(&police_tbl->refcount, 1);
|
||||
}
|
||||
|
||||
sgit_eid = gate_entry->hw_index;
|
||||
|
@ -856,9 +851,6 @@ int netc_setup_psfp(struct ntmp_priv *priv, int port_id,
|
|||
}
|
||||
|
||||
sgclt_entry->entry_id = sgclt_eid;
|
||||
gate_tbl->sgclt_eid = sgclt_eid;
|
||||
gate_tbl->sgit_eid = sgit_eid;
|
||||
refcount_set(&gate_tbl->refcount, 1);
|
||||
netc_psfp_gate_entry_config(priv, gate_entry, sgit_entry, sgclt_entry);
|
||||
|
||||
config_isct:
|
||||
|
@ -932,6 +924,7 @@ config_isct:
|
|||
|
||||
rule->lastused = jiffies;
|
||||
rule->isft_entry = no_free_ptr(isft_entry);
|
||||
rule->isct_eid = isct_eid;
|
||||
|
||||
if (reused_key_tbl) {
|
||||
rule->key_tbl = reused_key_tbl;
|
||||
|
@ -944,6 +937,9 @@ config_isct:
|
|||
rule->gate_tbl = reused_gate_tbl;
|
||||
refcount_inc(&reused_gate_tbl->refcount);
|
||||
} else {
|
||||
gate_tbl->sgit_entry = no_free_ptr(sgit_entry);
|
||||
gate_tbl->sgclt_entry = no_free_ptr(sgclt_entry);
|
||||
refcount_set(&gate_tbl->refcount, 1);
|
||||
rule->gate_tbl = no_free_ptr(gate_tbl);
|
||||
}
|
||||
|
||||
|
@ -951,6 +947,8 @@ config_isct:
|
|||
rule->police_tbl = reused_police_tbl;
|
||||
refcount_inc(&reused_police_tbl->refcount);
|
||||
} else if (police_tbl) {
|
||||
police_tbl->rpt_entry = no_free_ptr(rpt_entry);
|
||||
refcount_set(&police_tbl->refcount, 1);
|
||||
rule->police_tbl = no_free_ptr(police_tbl);
|
||||
}
|
||||
|
||||
|
@ -992,9 +990,12 @@ void netc_free_flower_police_tbl(struct ntmp_priv *priv,
|
|||
return;
|
||||
|
||||
if (refcount_dec_and_test(&police_tbl->refcount)) {
|
||||
ntmp_rpt_delete_entry(cbdrs, police_tbl->rpt_eid);
|
||||
struct ntmp_rpt_entry *rpt_entry = police_tbl->rpt_entry;
|
||||
|
||||
ntmp_rpt_delete_entry(cbdrs, rpt_entry->entry_id);
|
||||
ntmp_clear_eid_bitmap(priv->rpt_eid_bitmap,
|
||||
police_tbl->rpt_eid);
|
||||
rpt_entry->entry_id);
|
||||
kfree(rpt_entry);
|
||||
kfree(police_tbl);
|
||||
}
|
||||
}
|
||||
|
@ -1009,29 +1010,27 @@ void netc_delete_psfp_flower_rule(struct ntmp_priv *priv,
|
|||
struct netc_cbdrs *cbdrs = &priv->cbdrs;
|
||||
struct ntmp_isit_entry *isit_entry;
|
||||
struct ntmp_ist_entry *ist_entry;
|
||||
u32 isct_eid;
|
||||
|
||||
if (refcount_dec_and_test(&key_tbl->refcount)) {
|
||||
isit_entry = key_tbl->isit_entry;
|
||||
ist_entry = key_tbl->ist_entry;
|
||||
ntmp_isit_delete_entry(cbdrs, isit_entry->entry_id);
|
||||
ntmp_ist_delete_entry(cbdrs, ist_entry->entry_id);
|
||||
|
||||
isct_eid = le32_to_cpu(ist_entry->cfge.isc_eid);
|
||||
netc_free_flower_key_tbl(priv, key_tbl);
|
||||
}
|
||||
|
||||
if (isft_entry) {
|
||||
isct_eid = le32_to_cpu(isft_entry->cfge.isc_eid);
|
||||
ntmp_isft_delete_entry(cbdrs, isft_entry->entry_id);
|
||||
kfree(isft_entry);
|
||||
}
|
||||
|
||||
ntmp_isct_operate_entry(cbdrs, isct_eid, NTMP_CMD_DELETE, NULL);
|
||||
ntmp_clear_eid_bitmap(priv->isct_eid_bitmap, isct_eid);
|
||||
ntmp_isct_operate_entry(cbdrs, rule->isct_eid, NTMP_CMD_DELETE, NULL);
|
||||
ntmp_clear_eid_bitmap(priv->isct_eid_bitmap, rule->isct_eid);
|
||||
|
||||
if (gate_tbl && refcount_dec_and_test(&gate_tbl->refcount)) {
|
||||
netc_delete_sgit_entry(priv, gate_tbl->sgit_eid);
|
||||
netc_delete_sgit_entry(priv, gate_tbl->sgit_entry->entry_id);
|
||||
kfree(gate_tbl->sgit_entry);
|
||||
kfree(gate_tbl->sgclt_entry);
|
||||
kfree(gate_tbl);
|
||||
}
|
||||
|
||||
|
@ -1365,6 +1364,7 @@ int netc_setup_police(struct ntmp_priv *priv, int port_id,
|
|||
rule->port_id = port_id;
|
||||
rule->cookie = cookie;
|
||||
rule->flower_type = FLOWER_TYPE_POLICE;
|
||||
rule->isct_eid = NTMP_NULL_ENTRY_ID;
|
||||
|
||||
flow_action_for_each(i, action_entry, &cls_rule->action)
|
||||
if (action_entry->id == FLOW_ACTION_POLICE)
|
||||
|
@ -1410,8 +1410,6 @@ int netc_setup_police(struct ntmp_priv *priv, int port_id,
|
|||
goto clear_rpt_eid_bit;
|
||||
}
|
||||
|
||||
police_tbl->rpt_eid = police_act->hw_index;
|
||||
refcount_set(&police_tbl->refcount, 1);
|
||||
netc_rpt_entry_config(police_act, rpt_entry);
|
||||
}
|
||||
|
||||
|
@ -1436,6 +1434,8 @@ int netc_setup_police(struct ntmp_priv *priv, int port_id,
|
|||
rule->police_tbl = reused_police_tbl;
|
||||
refcount_inc(&reused_police_tbl->refcount);
|
||||
} else if (police_tbl) {
|
||||
police_tbl->rpt_entry = no_free_ptr(rpt_entry);
|
||||
refcount_set(&police_tbl->refcount, 1);
|
||||
rule->police_tbl = no_free_ptr(police_tbl);
|
||||
}
|
||||
|
||||
|
@ -1492,3 +1492,308 @@ int netc_police_flower_stat(struct ntmp_priv *priv,
|
|||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(netc_police_flower_stat);
|
||||
|
||||
static int netc_restore_gate_table(struct ntmp_priv *priv,
|
||||
struct netc_gate_tbl *gate_tbl)
|
||||
{
|
||||
struct ntmp_sgclt_entry *sgclt_entry = gate_tbl->sgclt_entry;
|
||||
struct ntmp_sgit_entry *sgit_entry = gate_tbl->sgit_entry;
|
||||
struct netc_cbdrs *cbdrs = &priv->cbdrs;
|
||||
u32 cycle_time;
|
||||
u64 base_time;
|
||||
int err;
|
||||
|
||||
if (gate_tbl->restored)
|
||||
return 0;
|
||||
|
||||
err = ntmp_sgclt_add_entry(cbdrs, sgclt_entry);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (priv->adjust_base_time) {
|
||||
cycle_time = le32_to_cpu(sgclt_entry->cfge.cycle_time);
|
||||
base_time = le64_to_cpu(sgit_entry->acfge.admin_base_time);
|
||||
base_time = priv->adjust_base_time(priv, base_time, cycle_time);
|
||||
sgit_entry->acfge.admin_base_time = cpu_to_le64(base_time);
|
||||
}
|
||||
|
||||
err = ntmp_sgit_add_or_update_entry(cbdrs, sgit_entry);
|
||||
if (err)
|
||||
goto del_sgit_entry;
|
||||
|
||||
gate_tbl->restored = true;
|
||||
|
||||
return 0;
|
||||
|
||||
del_sgit_entry:
|
||||
ntmp_sgclt_delete_entry(cbdrs, sgclt_entry->entry_id);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void netc_remove_gate_table(struct ntmp_priv *priv,
|
||||
struct netc_gate_tbl *gate_tbl)
|
||||
{
|
||||
struct ntmp_sgclt_entry *sgclt_entry = gate_tbl->sgclt_entry;
|
||||
struct ntmp_sgit_entry *sgit_entry = gate_tbl->sgit_entry;
|
||||
struct netc_cbdrs *cbdrs = &priv->cbdrs;
|
||||
struct ntmp_sgit_entry null_entry = {};
|
||||
|
||||
null_entry.acfge.admin_sgcl_eid = cpu_to_le32(NTMP_NULL_ENTRY_ID);
|
||||
null_entry.entry_id = sgit_entry->entry_id;
|
||||
ntmp_sgit_add_or_update_entry(cbdrs, &null_entry);
|
||||
ntmp_sgit_delete_entry(cbdrs, sgit_entry->entry_id);
|
||||
ntmp_sgclt_delete_entry(cbdrs, sgclt_entry->entry_id);
|
||||
gate_tbl->restored = false;
|
||||
}
|
||||
|
||||
static int netc_restore_police_table(struct ntmp_priv *priv,
|
||||
struct netc_police_tbl *police_tbl)
|
||||
{
|
||||
struct ntmp_rpt_entry *rpt_entry = police_tbl->rpt_entry;
|
||||
int err;
|
||||
|
||||
if (police_tbl->restored)
|
||||
return 0;
|
||||
|
||||
err = ntmp_rpt_add_or_update_entry(&priv->cbdrs, rpt_entry);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
police_tbl->restored = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void netc_remove_police_table(struct ntmp_priv *priv,
|
||||
struct netc_police_tbl *police_tbl)
|
||||
{
|
||||
struct ntmp_rpt_entry *rpt_entry = police_tbl->rpt_entry;
|
||||
|
||||
ntmp_rpt_delete_entry(&priv->cbdrs, rpt_entry->entry_id);
|
||||
police_tbl->restored = false;
|
||||
}
|
||||
|
||||
static int netc_restore_key_table(struct ntmp_priv *priv,
|
||||
struct netc_flower_key_tbl *key_tbl)
|
||||
{
|
||||
struct ntmp_ist_entry *ist_entry = key_tbl->ist_entry;
|
||||
struct netc_cbdrs *cbdrs = &priv->cbdrs;
|
||||
struct ntmp_ipft_entry *ipft_entry;
|
||||
int err;
|
||||
|
||||
if (key_tbl->restored)
|
||||
return 0;
|
||||
|
||||
if (ist_entry) {
|
||||
err = ntmp_ist_add_or_update_entry(cbdrs, ist_entry);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
switch (key_tbl->tbl_type) {
|
||||
case FLOWER_KEY_TBL_ISIT:
|
||||
err = ntmp_isit_add_or_update_entry(cbdrs, true,
|
||||
key_tbl->isit_entry);
|
||||
if (err)
|
||||
goto del_ist_entry;
|
||||
break;
|
||||
case FLOWER_KEY_TBL_IPFT:
|
||||
ipft_entry = key_tbl->ipft_entry;
|
||||
err = ntmp_ipft_add_entry(cbdrs, &ipft_entry->entry_id,
|
||||
ipft_entry);
|
||||
if (err)
|
||||
goto del_ist_entry;
|
||||
break;
|
||||
}
|
||||
|
||||
key_tbl->restored = true;
|
||||
|
||||
return 0;
|
||||
|
||||
del_ist_entry:
|
||||
if (ist_entry)
|
||||
ntmp_ist_delete_entry(&priv->cbdrs, ist_entry->entry_id);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void netc_remove_key_table(struct ntmp_priv *priv,
|
||||
struct netc_flower_key_tbl *key_tbl)
|
||||
{
|
||||
struct ntmp_ist_entry *ist_entry = key_tbl->ist_entry;
|
||||
struct netc_cbdrs *cbdrs = &priv->cbdrs;
|
||||
|
||||
switch (key_tbl->tbl_type) {
|
||||
case FLOWER_KEY_TBL_ISIT:
|
||||
ntmp_isit_delete_entry(cbdrs, key_tbl->isit_entry->entry_id);
|
||||
break;
|
||||
case FLOWER_KEY_TBL_IPFT:
|
||||
ntmp_ipft_delete_entry(cbdrs, key_tbl->ipft_entry->entry_id);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ist_entry)
|
||||
ntmp_ist_delete_entry(&priv->cbdrs, ist_entry->entry_id);
|
||||
|
||||
key_tbl->restored = false;
|
||||
}
|
||||
|
||||
static int netc_restore_flower_tables(struct ntmp_priv *priv,
|
||||
struct netc_flower_rule *rule)
|
||||
{
|
||||
struct netc_cbdrs *cbdrs = &priv->cbdrs;
|
||||
int err;
|
||||
|
||||
if (rule->isct_eid != NTMP_NULL_ENTRY_ID) {
|
||||
err = ntmp_isct_operate_entry(cbdrs, rule->isct_eid,
|
||||
NTMP_CMD_ADD, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (rule->gate_tbl) {
|
||||
err = netc_restore_gate_table(priv, rule->gate_tbl);
|
||||
if (err)
|
||||
goto del_isct_entry;
|
||||
}
|
||||
|
||||
if (rule->police_tbl) {
|
||||
err = netc_restore_police_table(priv, rule->police_tbl);
|
||||
if (err)
|
||||
goto del_gate_table;
|
||||
}
|
||||
|
||||
if (rule->isft_entry) {
|
||||
err = ntmp_isft_add_or_update_entry(cbdrs, true,
|
||||
rule->isft_entry);
|
||||
if (err)
|
||||
goto del_police_table;
|
||||
}
|
||||
|
||||
err = netc_restore_key_table(priv, rule->key_tbl);
|
||||
if (err)
|
||||
goto del_isft_entry;
|
||||
|
||||
return 0;
|
||||
|
||||
del_isft_entry:
|
||||
if (rule->isft_entry)
|
||||
ntmp_isft_delete_entry(cbdrs, rule->isft_entry->entry_id);
|
||||
del_police_table:
|
||||
if (rule->police_tbl)
|
||||
netc_remove_police_table(priv, rule->police_tbl);
|
||||
del_gate_table:
|
||||
if (rule->gate_tbl)
|
||||
netc_remove_gate_table(priv, rule->gate_tbl);
|
||||
del_isct_entry:
|
||||
if (rule->isct_eid != NTMP_NULL_ENTRY_ID)
|
||||
ntmp_isct_operate_entry(cbdrs, rule->isct_eid,
|
||||
NTMP_CMD_DELETE, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void netc_remove_flower_tables(struct ntmp_priv *priv,
|
||||
struct netc_flower_rule *rule)
|
||||
{
|
||||
struct ntmp_isft_entry *isft_entry = rule->isft_entry;
|
||||
struct netc_cbdrs *cbdrs = &priv->cbdrs;
|
||||
|
||||
netc_remove_key_table(priv, rule->key_tbl);
|
||||
|
||||
if (isft_entry)
|
||||
ntmp_isft_delete_entry(cbdrs, isft_entry->entry_id);
|
||||
|
||||
if (rule->police_tbl)
|
||||
netc_remove_police_table(priv, rule->police_tbl);
|
||||
|
||||
if (rule->gate_tbl)
|
||||
netc_remove_gate_table(priv, rule->gate_tbl);
|
||||
|
||||
if (rule->isct_eid != NTMP_NULL_ENTRY_ID)
|
||||
ntmp_isct_operate_entry(cbdrs, rule->isct_eid,
|
||||
NTMP_CMD_DELETE, NULL);
|
||||
}
|
||||
|
||||
static void netc_free_flower_rule(struct ntmp_priv *priv,
|
||||
struct netc_flower_rule *rule)
|
||||
{
|
||||
struct netc_police_tbl *police_tbl = rule->police_tbl;
|
||||
struct netc_flower_key_tbl *key_tbl = rule->key_tbl;
|
||||
struct netc_gate_tbl *gate_tbl = rule->gate_tbl;
|
||||
|
||||
if (refcount_dec_and_test(&key_tbl->refcount))
|
||||
netc_free_flower_key_tbl(priv, key_tbl);
|
||||
|
||||
kfree(rule->isft_entry);
|
||||
|
||||
if (gate_tbl && refcount_dec_and_test(&gate_tbl->refcount)) {
|
||||
kfree(gate_tbl->sgit_entry);
|
||||
kfree(gate_tbl->sgclt_entry);
|
||||
kfree(gate_tbl);
|
||||
}
|
||||
|
||||
if (police_tbl && refcount_dec_and_test(&police_tbl->refcount)) {
|
||||
kfree(police_tbl->rpt_entry);
|
||||
kfree(police_tbl);
|
||||
}
|
||||
|
||||
hlist_del(&rule->node);
|
||||
kfree(rule);
|
||||
}
|
||||
|
||||
int netc_restore_flower_list_config(struct ntmp_priv *priv)
|
||||
{
|
||||
struct netc_flower_rule *rule, *iterator;
|
||||
struct hlist_node *tmp;
|
||||
int err;
|
||||
|
||||
mutex_lock(&priv->flower_lock);
|
||||
|
||||
hlist_for_each_entry(rule, &priv->flower_list, node) {
|
||||
err = netc_restore_flower_tables(priv, rule);
|
||||
if (err)
|
||||
goto del_flower_tables;
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->flower_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
del_flower_tables:
|
||||
hlist_for_each_entry(iterator, &priv->flower_list, node) {
|
||||
if (iterator == rule)
|
||||
break;
|
||||
|
||||
netc_remove_flower_tables(priv, iterator);
|
||||
}
|
||||
|
||||
hlist_for_each_entry_safe(iterator, tmp, &priv->flower_list, node)
|
||||
netc_free_flower_rule(priv, iterator);
|
||||
|
||||
mutex_unlock(&priv->flower_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(netc_restore_flower_list_config);
|
||||
|
||||
void netc_clear_flower_table_restored_flag(struct ntmp_priv *priv)
|
||||
{
|
||||
struct netc_flower_rule *rule;
|
||||
|
||||
mutex_lock(&priv->flower_lock);
|
||||
|
||||
hlist_for_each_entry(rule, &priv->flower_list, node) {
|
||||
rule->key_tbl->restored = false;
|
||||
|
||||
if (rule->gate_tbl)
|
||||
rule->gate_tbl->restored = false;
|
||||
|
||||
if (rule->police_tbl)
|
||||
rule->police_tbl->restored = false;
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->flower_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(netc_clear_flower_table_restored_flag);
|
||||
|
|
|
@ -65,6 +65,23 @@
|
|||
#define RSST_CFGE_DATA_SIZE(n) (n)
|
||||
#define FMDT_DATA_LEN_ALIGN 4
|
||||
|
||||
void netc_enable_cbdr(struct netc_cbdr *cbdr)
|
||||
{
|
||||
cbdr->next_to_clean = netc_read(cbdr->regs.cir);
|
||||
cbdr->next_to_use = netc_read(cbdr->regs.pir);
|
||||
|
||||
/* Step 1: Configure the base address of the Control BD Ring */
|
||||
netc_write(cbdr->regs.bar0, lower_32_bits(cbdr->dma_base_align));
|
||||
netc_write(cbdr->regs.bar1, upper_32_bits(cbdr->dma_base_align));
|
||||
|
||||
/* Step 2: Configure the number of BDs of the Control BD Ring */
|
||||
netc_write(cbdr->regs.lenr, cbdr->bd_num);
|
||||
|
||||
/* Step 3: Enable the Control BD Ring */
|
||||
netc_write(cbdr->regs.mr, NETC_CBDR_MR_EN);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(netc_enable_cbdr);
|
||||
|
||||
int netc_setup_cbdr(struct device *dev, int cbd_num,
|
||||
struct netc_cbdr_regs *regs,
|
||||
struct netc_cbdr *cbdr)
|
||||
|
@ -89,25 +106,9 @@ int netc_setup_cbdr(struct device *dev, int cbd_num,
|
|||
cbdr->addr_base_align = PTR_ALIGN(cbdr->addr_base,
|
||||
NTMP_BASE_ADDR_ALIGN);
|
||||
|
||||
cbdr->next_to_clean = 0;
|
||||
cbdr->next_to_use = 0;
|
||||
spin_lock_init(&cbdr->ring_lock);
|
||||
|
||||
/* Step 1: Configure the base address of the Control BD Ring */
|
||||
netc_write(cbdr->regs.bar0, lower_32_bits(cbdr->dma_base_align));
|
||||
netc_write(cbdr->regs.bar1, upper_32_bits(cbdr->dma_base_align));
|
||||
|
||||
/* Step 2: Configure the producer index register */
|
||||
netc_write(cbdr->regs.pir, cbdr->next_to_clean);
|
||||
|
||||
/* Step 3: Configure the consumer index register */
|
||||
netc_write(cbdr->regs.cir, cbdr->next_to_use);
|
||||
|
||||
/* Step4: Configure the number of BDs of the Control BD Ring */
|
||||
netc_write(cbdr->regs.lenr, cbdr->bd_num);
|
||||
|
||||
/* Step 5: Enable the Control BD Ring */
|
||||
netc_write(cbdr->regs.mr, NETC_CBDR_MR_EN);
|
||||
netc_enable_cbdr(cbdr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -139,6 +139,7 @@ static int __cold memac_init(struct mac_device *mac_dev)
|
|||
param.f_Exception = mac_exception;
|
||||
param.f_Event = mac_exception;
|
||||
param.h_App = mac_dev;
|
||||
param.fixed = !!mac_dev->fixed_link;
|
||||
|
||||
priv->fm_mac = fm_mac_config(¶m);
|
||||
if (unlikely(priv->fm_mac == NULL)) {
|
||||
|
|
|
@ -84,9 +84,12 @@ static uint32_t GetMacAddrHashCode(uint64_t ethAddr)
|
|||
|
||||
static void SetupSgmiiInternalPhy(t_Memac *p_Memac, uint8_t phyAddr)
|
||||
{
|
||||
bool autoneg_disabled = false;
|
||||
uint16_t tmpReg16;
|
||||
e_EnetMode enetMode;
|
||||
bool autoneg_disabled = p_Memac->enetMode == e_ENET_MODE_SGMII_2500;
|
||||
|
||||
if (p_Memac->fixed || p_Memac->enetMode == e_ENET_MODE_SGMII_2500)
|
||||
autoneg_disabled = true;
|
||||
|
||||
/* In case the higher MACs are used (i.e. the MACs that should support 10G),
|
||||
speed=10000 is provided for SGMII ports. Temporary modify enet mode
|
||||
|
@ -1156,6 +1159,7 @@ t_Handle MEMAC_Config(t_FmMacParams *p_FmMacParam)
|
|||
p_Memac->f_Exception = p_FmMacParam->f_Exception;
|
||||
p_Memac->f_Event = p_FmMacParam->f_Event;
|
||||
p_Memac->h_App = p_FmMacParam->h_App;
|
||||
p_Memac->fixed = p_FmMacParam->fixed;
|
||||
|
||||
return p_Memac;
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ typedef struct
|
|||
uint8_t macId;
|
||||
uint32_t exceptions;
|
||||
struct memac_cfg *p_MemacDriverParam;
|
||||
bool fixed;
|
||||
} t_Memac;
|
||||
|
||||
|
||||
|
|
|
@ -248,6 +248,7 @@ typedef struct t_FmMacParams {
|
|||
t_FmMacExceptionCallback *f_Exception; /**< Exception Callback Routine */
|
||||
t_Handle h_App; /**< A handle to an application layer object; This handle will
|
||||
be passed by the driver upon calling the above callbacks */
|
||||
bool fixed; /**< Specifies whether MAC has a fixed-link */
|
||||
} t_FmMacParams;
|
||||
|
||||
|
||||
|
|
|
@ -13,11 +13,13 @@
|
|||
#include <linux/irqdomain.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/pci_regs.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "../../pci.h"
|
||||
#include "../../pcie/portdrv.h"
|
||||
#include "pcie-designware.h"
|
||||
|
||||
static struct pci_ops dw_pcie_ops;
|
||||
|
@ -419,6 +421,35 @@ static void dw_pcie_host_request_msg_tlp_res(struct dw_pcie_rp *pp)
|
|||
}
|
||||
}
|
||||
|
||||
static int dw_pcie_get_service_irqs(struct pci_host_bridge *bridge,
|
||||
int *irqs, int mask)
|
||||
{
|
||||
struct device *dev = bridge->dev.parent;
|
||||
struct device_node *np = dev->of_node;
|
||||
int ret, count = 0;
|
||||
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
if (mask & PCIE_PORT_SERVICE_AER) {
|
||||
ret = of_irq_get_byname(np, "aer");
|
||||
if (ret > 0) {
|
||||
irqs[PCIE_PORT_SERVICE_AER_SHIFT] = ret;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & PCIE_PORT_SERVICE_PME) {
|
||||
ret = of_irq_get_byname(np, "pme");
|
||||
if (ret > 0) {
|
||||
irqs[PCIE_PORT_SERVICE_PME_SHIFT] = ret;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int dw_pcie_host_init(struct dw_pcie_rp *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
@ -454,6 +485,7 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
|
|||
return -ENOMEM;
|
||||
|
||||
pp->bridge = bridge;
|
||||
pp->bridge->get_service_irqs = dw_pcie_get_service_irqs;
|
||||
|
||||
/* Get the I/O range from DT */
|
||||
win = resource_list_first_type(&bridge->windows, IORESOURCE_IO);
|
||||
|
|
|
@ -49,20 +49,6 @@ static void release_pcie_device(struct device *dev)
|
|||
kfree(to_pcie_device(dev));
|
||||
}
|
||||
|
||||
/**
|
||||
* pcibios_check_service_irqs - check irqs in the device tree
|
||||
* @dev: PCI Express port to handle
|
||||
* @irqs: Array of irqs to populate
|
||||
* @mask: Bitmask of port capabilities returned by get_port_device_capability()
|
||||
*
|
||||
* Return value: 0 means no service irqs in the device tree
|
||||
*
|
||||
*/
|
||||
int __weak pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in *pme, *aer, *dpc with the relevant Interrupt Message Numbers if
|
||||
* services are enabled in "mask". Return the number of MSI/MSI-X vectors
|
||||
|
@ -190,26 +176,18 @@ static int pcie_port_enable_irq_vec(struct pci_dev *dev, int *irqs, int mask)
|
|||
*/
|
||||
static int pcie_init_service_irqs(struct pci_dev *dev, int *irqs, int mask)
|
||||
{
|
||||
struct pci_host_bridge *host_bridge = pci_find_host_bridge(dev->bus);
|
||||
int ret, i;
|
||||
int irq = -1;
|
||||
|
||||
/* Check if some platforms owns independent irq pins for AER/PME etc.
|
||||
* Some platforms may own independent AER/PME interrupts and set
|
||||
* them in the device tree file.
|
||||
*/
|
||||
ret = pcibios_check_service_irqs(dev, irqs, mask);
|
||||
if (ret) {
|
||||
if (dev->irq)
|
||||
irq = dev->irq;
|
||||
for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
|
||||
if (irqs[i] == -1)
|
||||
irqs[i] = irq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
|
||||
irqs[i] = -1;
|
||||
|
||||
if (host_bridge->get_service_irqs) {
|
||||
ret = host_bridge->get_service_irqs(host_bridge, irqs, mask);
|
||||
if (ret > 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we support PME but can't use MSI/MSI-X for it, we have to
|
||||
* fall back to INTx or other interrupts, e.g., a system shared
|
||||
|
|
|
@ -26,7 +26,12 @@
|
|||
#define PCCR9_QXGMIIa_CFG BIT(0)
|
||||
|
||||
#define PCCRB 0x22c
|
||||
/* XFIa_CFG is the generic value to enable the protocol converter (0b001),
|
||||
* not to be confused with XFIA_CFG_LS1046A (0b010), which is specific to
|
||||
* XFI protocol converter A, routed to SerDes1 lane C.
|
||||
*/
|
||||
#define PCCRB_XFIa_CFG BIT(0)
|
||||
#define PCCRB_XFIA_CFG_LS1046A BIT(1)
|
||||
#define PCCRB_SXGMIIa_CFG BIT(0)
|
||||
|
||||
#define SGMII_CFG(id) (28 - (id) * 4)
|
||||
|
@ -512,6 +517,7 @@ struct lynx_info {
|
|||
struct lynx_pccr *pccr);
|
||||
int (*get_pcvt_offset)(int lane, enum lynx_lane_mode mode);
|
||||
bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode);
|
||||
int (*pccr_override)(int lane, enum lynx_lane_mode mode, u32 *val);
|
||||
int num_lanes;
|
||||
bool has_hardcoded_usxgmii;
|
||||
int index;
|
||||
|
@ -680,6 +686,22 @@ static const struct lynx_info lynx_info_ls1028a = {
|
|||
.index = 1,
|
||||
};
|
||||
|
||||
/* LS1046A PCCRB[XFIA_CFG] is special in that lane C needs a special value to
|
||||
* work in 10G mode, not the standard PCCRB_XFIa_CFG
|
||||
*/
|
||||
static int ls1046a_serdes1_pccr_override(int lane, enum lynx_lane_mode mode,
|
||||
u32 *val)
|
||||
{
|
||||
if ((mode == LANE_MODE_10GBASER || mode == LANE_MODE_10GBASEKR) &&
|
||||
lane == 2) {
|
||||
*val = PCCRB_XFIA_CFG_LS1046A;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No other override */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int ls1046a_serdes1_get_pccr(enum lynx_lane_mode lane_mode, int lane,
|
||||
struct lynx_pccr *pccr)
|
||||
{
|
||||
|
@ -768,6 +790,7 @@ static bool ls1046a_serdes1_lane_supports_mode(int lane,
|
|||
}
|
||||
|
||||
static const struct lynx_info lynx_info_ls1046a_serdes1 = {
|
||||
.pccr_override = ls1046a_serdes1_pccr_override,
|
||||
.get_pccr = ls1046a_serdes1_get_pccr,
|
||||
.get_pcvt_offset = ls1046a_serdes1_get_pcvt_offset,
|
||||
.lane_supports_mode = ls1046a_serdes1_lane_supports_mode,
|
||||
|
@ -1157,6 +1180,61 @@ static int lynx_pccr_write(struct lynx_10g_lane *lane,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lynx_10g_lane_pccr_val(struct lynx_10g_lane *lane,
|
||||
enum lynx_lane_mode mode,
|
||||
u32 *val)
|
||||
{
|
||||
struct lynx_10g_priv *priv = lane->priv;
|
||||
int err;
|
||||
|
||||
if (lane->default_pccr[mode]) {
|
||||
*val = lane->default_pccr[mode];
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (priv->info->pccr_override) {
|
||||
err = priv->info->pccr_override(lane->id, mode, val);
|
||||
/* -EOPNOTSUPP means the function is implemented, but there is
|
||||
* no override for this lane or this lane mode. Let the code
|
||||
* fall back to the normal calculation, but treat other error
|
||||
* codes as critical.
|
||||
*/
|
||||
if (err == 0 || err != -EOPNOTSUPP)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Normal PCCR value calculation */
|
||||
*val = 0;
|
||||
|
||||
switch (mode) {
|
||||
case LANE_MODE_1000BASEKX:
|
||||
*val |= PCCR8_SGMIIa_KX;
|
||||
fallthrough;
|
||||
case LANE_MODE_1000BASEX_SGMII:
|
||||
case LANE_MODE_2500BASEX:
|
||||
*val |= PCCR8_SGMIIa_CFG;
|
||||
break;
|
||||
case LANE_MODE_QSGMII:
|
||||
*val |= PCCR9_QSGMIIa_CFG;
|
||||
break;
|
||||
case LANE_MODE_10G_QXGMII:
|
||||
*val |= PCCR9_QXGMIIa_CFG;
|
||||
break;
|
||||
case LANE_MODE_10GBASER:
|
||||
case LANE_MODE_10GBASEKR:
|
||||
*val |= PCCRB_XFIa_CFG;
|
||||
break;
|
||||
case LANE_MODE_USXGMII:
|
||||
*val |= PCCRB_SXGMIIa_CFG;
|
||||
break;
|
||||
default:
|
||||
/* Should be unreachable due to lynx_lane_supports_mode() */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lynx_pcvt_read(struct lynx_10g_lane *lane, enum lynx_lane_mode mode,
|
||||
int cr, u32 *val)
|
||||
{
|
||||
|
@ -1642,40 +1720,10 @@ static int lynx_10g_lane_enable_pcvt(struct lynx_10g_lane *lane,
|
|||
err = 0;
|
||||
}
|
||||
|
||||
if (lane->default_pccr[mode]) {
|
||||
err = lynx_pccr_write(lane, mode, lane->default_pccr[mode]);
|
||||
goto out;
|
||||
}
|
||||
err = lynx_10g_lane_pccr_val(lane, mode, &val);
|
||||
if (err == 0)
|
||||
err = lynx_pccr_write(lane, mode, val);
|
||||
|
||||
val = 0;
|
||||
|
||||
switch (mode) {
|
||||
case LANE_MODE_1000BASEKX:
|
||||
val |= PCCR8_SGMIIa_KX;
|
||||
fallthrough;
|
||||
case LANE_MODE_1000BASEX_SGMII:
|
||||
case LANE_MODE_2500BASEX:
|
||||
val |= PCCR8_SGMIIa_CFG;
|
||||
break;
|
||||
case LANE_MODE_QSGMII:
|
||||
val |= PCCR9_QSGMIIa_CFG;
|
||||
break;
|
||||
case LANE_MODE_10G_QXGMII:
|
||||
val |= PCCR9_QXGMIIa_CFG;
|
||||
break;
|
||||
case LANE_MODE_10GBASER:
|
||||
case LANE_MODE_10GBASEKR:
|
||||
val |= PCCRB_XFIa_CFG;
|
||||
break;
|
||||
case LANE_MODE_USXGMII:
|
||||
val |= PCCRB_SXGMIIa_CFG;
|
||||
break;
|
||||
default:
|
||||
err = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = lynx_pccr_write(lane, mode, val);
|
||||
out:
|
||||
spin_unlock(&priv->pccr_lock);
|
||||
|
||||
|
|
|
@ -334,7 +334,8 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event)
|
|||
schedule_work(&ci->usb_phy->chg_work);
|
||||
break;
|
||||
case CI_HDRC_CONTROLLER_PULLUP_EVENT:
|
||||
if (ci->role == CI_ROLE_GADGET)
|
||||
if (ci->role == CI_ROLE_GADGET &&
|
||||
ci->gadget.speed == USB_SPEED_HIGH)
|
||||
imx_usbmisc_pullup(data->usbmisc_data,
|
||||
ci->gadget.connected);
|
||||
break;
|
||||
|
|
|
@ -1004,15 +1004,24 @@ static void usbmisc_imx7d_pullup(struct imx_usbmisc_data *data, bool on)
|
|||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
if (on)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||
val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
|
||||
if (!on) {
|
||||
val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK;
|
||||
val |= MX7D_USBNC_USB_CTRL2_OPMODE(1);
|
||||
val |= MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN;
|
||||
} else {
|
||||
val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN;
|
||||
}
|
||||
val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK;
|
||||
val |= MX7D_USBNC_USB_CTRL2_OPMODE(1);
|
||||
val |= MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN;
|
||||
writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2);
|
||||
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||
|
||||
/* Last for at least 1 micro-frame to let host see disconnect signal */
|
||||
usleep_range(125, 150);
|
||||
|
||||
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||
val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK;
|
||||
val |= MX7D_USBNC_USB_CTRL2_OPMODE(0);
|
||||
val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN;
|
||||
writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2);
|
||||
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||
}
|
||||
|
|
|
@ -26,13 +26,19 @@ enum netc_key_tbl_type {
|
|||
};
|
||||
|
||||
struct netc_gate_tbl {
|
||||
u32 sgit_eid;
|
||||
u32 sgclt_eid;
|
||||
struct ntmp_sgit_entry *sgit_entry;
|
||||
struct ntmp_sgclt_entry *sgclt_entry;
|
||||
/* This flag is cleared when NETC suspends and it is
|
||||
* powered off, and it will be set when NETC resumes
|
||||
* and the table entries are restored.
|
||||
*/
|
||||
bool restored;
|
||||
refcount_t refcount;
|
||||
};
|
||||
|
||||
struct netc_police_tbl {
|
||||
u32 rpt_eid;
|
||||
struct ntmp_rpt_entry *rpt_entry;
|
||||
bool restored;
|
||||
refcount_t refcount;
|
||||
};
|
||||
|
||||
|
@ -43,11 +49,13 @@ struct netc_flower_key_tbl {
|
|||
struct ntmp_ipft_entry *ipft_entry;
|
||||
};
|
||||
struct ntmp_ist_entry *ist_entry;
|
||||
bool restored;
|
||||
refcount_t refcount;
|
||||
};
|
||||
|
||||
struct netc_flower_rule {
|
||||
u32 port_id;
|
||||
u32 isct_eid;
|
||||
unsigned long cookie;
|
||||
enum netc_flower_type flower_type;
|
||||
struct netc_flower_key_tbl *key_tbl;
|
||||
|
@ -120,6 +128,8 @@ void netc_delete_police_flower_rule(struct ntmp_priv *priv,
|
|||
struct netc_flower_rule *rule);
|
||||
int netc_police_flower_stat(struct ntmp_priv *priv, struct netc_flower_rule *rule,
|
||||
u64 *pkt_cnt);
|
||||
int netc_restore_flower_list_config(struct ntmp_priv *priv);
|
||||
void netc_clear_flower_table_restored_flag(struct ntmp_priv *priv);
|
||||
|
||||
/* debugfs API */
|
||||
int netc_kstrtouint(const char __user *buffer, size_t count, loff_t *ppos, u32 *val);
|
||||
|
@ -235,6 +245,15 @@ static inline int netc_police_flower_stat(struct ntmp_priv *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int netc_restore_flower_list_config(struct ntmp_priv *priv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void netc_clear_flower_table_restored_flag(struct ntmp_priv *priv)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void netc_show_psfp_flower(struct seq_file *s,
|
||||
struct netc_flower_rule *rule)
|
||||
{
|
||||
|
|
|
@ -773,6 +773,7 @@ struct sbpt_query_data {
|
|||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_NXP_NETC_LIB)
|
||||
void netc_enable_cbdr(struct netc_cbdr *cbdr);
|
||||
int netc_setup_cbdr(struct device *dev, int cbd_num, struct netc_cbdr_regs *regs,
|
||||
struct netc_cbdr *cbdr);
|
||||
void netc_teardown_cbdr(struct device *dev, struct netc_cbdr *cbdr);
|
||||
|
@ -863,6 +864,10 @@ int ntmp_fmdt_update_entry(struct netc_cbdrs *cbdrs, u32 entry_id,
|
|||
int ntmp_fmdt_query_entry(struct netc_cbdrs *cbdrs, u32 entry_id,
|
||||
u8 *data_buff, u32 data_len);
|
||||
#else
|
||||
static inline void netc_enable_cbdr(struct netc_cbdr *cbdr)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int netc_setup_cbdr(struct device *dev, int cbd_num,
|
||||
struct netc_cbdr_regs *regs,
|
||||
struct netc_cbdr *cbdr)
|
||||
|
|
|
@ -2364,7 +2364,6 @@ static inline void pcibios_penalize_isa_irq(int irq, int active) {}
|
|||
int pcibios_alloc_irq(struct pci_dev *dev);
|
||||
void pcibios_free_irq(struct pci_dev *dev);
|
||||
resource_size_t pcibios_default_alignment(void);
|
||||
int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask);
|
||||
|
||||
#if !defined(HAVE_PCI_MMAP) && !defined(ARCH_GENERIC_PCI_MMAP_RESOURCE)
|
||||
extern int pci_create_resource_files(struct pci_dev *dev);
|
||||
|
|
|
@ -1652,25 +1652,14 @@ out:
|
|||
EXPORT_SYMBOL_GPL(dsa_switch_shutdown);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static bool dsa_port_is_initialized(const struct dsa_port *dp)
|
||||
{
|
||||
return dp->type == DSA_PORT_TYPE_USER && dp->user;
|
||||
}
|
||||
|
||||
int dsa_switch_suspend(struct dsa_switch *ds)
|
||||
{
|
||||
struct dsa_port *dp;
|
||||
int ret = 0;
|
||||
|
||||
/* Suspend user network devices */
|
||||
dsa_switch_for_each_port(dp, ds) {
|
||||
if (!dsa_port_is_initialized(dp))
|
||||
continue;
|
||||
|
||||
ret = dsa_user_suspend(dp->user);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
/* Suspend user and shared ports */
|
||||
dsa_switch_for_each_available_port(dp, ds)
|
||||
dsa_port_suspend(dp);
|
||||
|
||||
if (ds->ops->suspend)
|
||||
ret = ds->ops->suspend(ds);
|
||||
|
@ -1690,15 +1679,9 @@ int dsa_switch_resume(struct dsa_switch *ds)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Resume user network devices */
|
||||
dsa_switch_for_each_port(dp, ds) {
|
||||
if (!dsa_port_is_initialized(dp))
|
||||
continue;
|
||||
|
||||
ret = dsa_user_resume(dp->user);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
/* Resume user and shared ports */
|
||||
dsa_switch_for_each_available_port(dp, ds)
|
||||
dsa_port_resume(dp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1914,6 +1914,44 @@ void dsa_shared_port_link_unregister_of(struct dsa_port *dp)
|
|||
}
|
||||
}
|
||||
|
||||
static void dsa_shared_port_suspend(struct dsa_port *dp)
|
||||
{
|
||||
if (!dp->pl)
|
||||
return;
|
||||
|
||||
rtnl_lock();
|
||||
phylink_stop(dp->pl);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
static void dsa_shared_port_resume(struct dsa_port *dp)
|
||||
{
|
||||
if (!dp->pl)
|
||||
return;
|
||||
|
||||
rtnl_lock();
|
||||
phylink_start(dp->pl);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
void dsa_port_suspend(struct dsa_port *dp)
|
||||
{
|
||||
if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp))
|
||||
return dsa_shared_port_suspend(dp);
|
||||
|
||||
if (dp->user)
|
||||
dsa_user_suspend(dp->user);
|
||||
}
|
||||
|
||||
void dsa_port_resume(struct dsa_port *dp)
|
||||
{
|
||||
if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp))
|
||||
return dsa_shared_port_resume(dp);
|
||||
|
||||
if (dp->user)
|
||||
dsa_user_resume(dp->user);
|
||||
}
|
||||
|
||||
int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
|
|
|
@ -103,6 +103,8 @@ int dsa_port_phylink_create(struct dsa_port *dp);
|
|||
void dsa_port_phylink_destroy(struct dsa_port *dp);
|
||||
int dsa_shared_port_link_register_of(struct dsa_port *dp);
|
||||
void dsa_shared_port_link_unregister_of(struct dsa_port *dp);
|
||||
void dsa_port_suspend(struct dsa_port *dp);
|
||||
void dsa_port_resume(struct dsa_port *dp);
|
||||
int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr,
|
||||
struct netlink_ext_ack *extack);
|
||||
void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr);
|
||||
|
|
Loading…
Reference in New Issue
Block a user