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:
Zhipeng Wang 2025-08-11 18:41:39 +09:00
commit 97bf30a802
57 changed files with 1429 additions and 525 deletions

View File

@ -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>

View File

@ -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.

View File

@ -78,6 +78,10 @@
};
};
sound-micfil {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
};
};
&iomuxc {

View File

@ -84,6 +84,11 @@
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
sound-micfil {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
};
};
&iomuxc {

View File

@ -92,6 +92,11 @@
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
sound-micfil {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
};
};
&iomuxc {

View File

@ -92,6 +92,11 @@
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
sound-micfil {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
};
};
&iomuxc {

View File

@ -116,6 +116,11 @@
regulator-always-on;
};
sound-micfil {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
};
sound-wm8962 {
status = "disabled";
};

View File

@ -151,6 +151,10 @@
};
};
sound-micfil {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
};
};
&adp5585 {

View File

@ -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";

View File

@ -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";

View File

@ -128,6 +128,10 @@
};
};
sound-micfil {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
};
};
&dmic {

View File

@ -103,6 +103,11 @@
regulator-always-on;
};
sound-micfil {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
};
sound-wm8962 {
status = "disabled";
};

View File

@ -138,6 +138,10 @@
};
};
sound-micfil {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
};
};
&dmic {

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -143,6 +143,10 @@
};
};
sound-micfil {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
};
};
&dmic {

View File

@ -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>,

View File

@ -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>,

View File

@ -103,6 +103,11 @@
regulator-always-on;
};
sound-micfil {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
};
sound-wm8962 {
status = "disabled";
};

View File

@ -130,6 +130,10 @@
};
};
sound-micfil {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
};
};
&dmic {

View File

@ -85,6 +85,11 @@
interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
};
};
sound-micfil {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_swpdm_mute_irq>;
};
};
&micfil {

View File

@ -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;
};
};

View File

@ -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 {

View File

@ -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>,

View File

@ -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.

View File

@ -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);

View File

@ -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));

View File

@ -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

View File

@ -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)
{

View 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;
}

View File

@ -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:

View File

@ -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);

View File

@ -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;

View File

@ -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))

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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(&param);
if (unlikely(priv->fm_mac == NULL)) {

View File

@ -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;
}

View File

@ -83,6 +83,7 @@ typedef struct
uint8_t macId;
uint32_t exceptions;
struct memac_cfg *p_MemacDriverParam;
bool fixed;
} t_Memac;

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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);