--- a/arch/mips/Kbuild.platforms
+++ b/arch/mips/Kbuild.platforms
-@@ -23,6 +23,7 @@ platform-$(CONFIG_NLM_COMMON) += netlog
+@@ -22,6 +22,7 @@ platform-$(CONFIG_MACH_NINTENDO64) += n6
platform-$(CONFIG_PIC32MZDA) += pic32/
platform-$(CONFIG_RALINK) += ralink/
platform-$(CONFIG_MIKROTIK_RB532) += rb532/
platform-$(CONFIG_SGI_IP28) += sgi-ip22/
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
-@@ -1053,8 +1053,58 @@ config NLM_XLP_BOARD
- This board is based on Netlogic XLP Processor.
- Say Y here if you have a XLP based board.
+@@ -990,8 +990,58 @@ config CAVIUM_OCTEON_SOC
+ Hikari
+ Say Y here for most Octeon reference boards.
+config RTL83XX
+ bool "Realtek based platforms"
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
-@@ -529,6 +529,12 @@ config GPIO_ROCKCHIP
+@@ -544,6 +544,12 @@ config GPIO_ROCKCHIP
help
Say yes here to support GPIO on Rockchip SoCs.
depends on MFD_SYSCON
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
-@@ -129,6 +129,7 @@ obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc3
+@@ -130,6 +130,7 @@ obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc3
obj-$(CONFIG_GPIO_REALTEK_OTTO) += gpio-realtek-otto.o
obj-$(CONFIG_GPIO_REG) += gpio-reg.o
obj-$(CONFIG_GPIO_ROCKCHIP) += gpio-rockchip.o
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
-@@ -127,6 +127,17 @@ config RDA_TIMER
+@@ -134,6 +134,17 @@ config RDA_TIMER
help
Enables the support for the RDA Micro timer driver.
depends on HAS_IOMEM
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
-@@ -58,6 +58,7 @@ obj-$(CONFIG_MILBEAUT_TIMER) += timer-mi
+@@ -59,6 +59,7 @@ obj-$(CONFIG_MILBEAUT_TIMER) += timer-mi
obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o
obj-$(CONFIG_NPCM7XX_TIMER) += timer-npcm7xx.o
obj-$(CONFIG_RDA_TIMER) += timer-rda.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
-@@ -177,6 +177,7 @@ enum cpuhp_state {
+@@ -179,6 +179,7 @@ enum cpuhp_state {
CPUHP_AP_MARCO_TIMER_STARTING,
CPUHP_AP_MIPS_GIC_TIMER_STARTING,
CPUHP_AP_ARC_TIMER_STARTING,
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
-@@ -503,8 +503,8 @@ config GPIO_RDA
+@@ -518,8 +518,8 @@ config GPIO_RDA
config GPIO_REALTEK_OTTO
tristate "Realtek Otto GPIO support"
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
-@@ -97,7 +97,7 @@ obj-$(CONFIG_SPI_QUP) += spi-qup.o
+@@ -107,7 +107,7 @@ obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o
obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
-@@ -112,7 +112,7 @@ obj-$(CONFIG_LOONGSON_PCH_PIC) += irq-l
- obj-$(CONFIG_LOONGSON_PCH_MSI) += irq-loongson-pch-msi.o
+@@ -115,7 +115,7 @@ obj-$(CONFIG_LOONGSON_PCH_MSI) += irq-l
+ obj-$(CONFIG_LOONGSON_PCH_LPC) += irq-loongson-pch-lpc.o
obj-$(CONFIG_MST_IRQ) += irq-mst-intc.o
obj-$(CONFIG_SL28CPLD_INTC) += irq-sl28cpld.o
-obj-$(CONFIG_MACH_REALTEK_RTL) += irq-realtek-rtl.o
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
-@@ -956,10 +956,10 @@ config RTD119X_WATCHDOG
+@@ -960,10 +960,10 @@ config RTD119X_WATCHDOG
config REALTEK_OTTO_WDT
tristate "Realtek Otto MIPS watchdog support"
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
-@@ -949,6 +949,16 @@ config I2C_RK3X
+@@ -998,6 +998,16 @@ config I2C_RK3X
This driver can also be built as a module. If so, the module will
be called i2c-rk3x.
+ This driver can also be built as a module. If so, the module will
+ be called i2c-rtl9300.
+
- config HAVE_S3C2410_I2C
- bool
- help
+ config I2C_RZV2M
+ tristate "Renesas RZ/V2M adapter"
+ depends on ARCH_RENESAS || COMPILE_TEST
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
-@@ -94,6 +94,7 @@ obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-
+@@ -102,6 +102,7 @@ obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-
obj-$(CONFIG_I2C_QUP) += i2c-qup.o
obj-$(CONFIG_I2C_RIIC) += i2c-riic.o
obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o
+obj-$(CONFIG_I2C_RTL9300) += i2c-rtl9300.o
+ obj-$(CONFIG_I2C_RZV2M) += i2c-rzv2m.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
- obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
In order to support VSMP, enable support for both VPEs
of the RTL839X and RTL930X SoCs in the irq-realtek-rtl
-driver. Add support for IRQ affinity setting.
+driver, with support for IRQ affinity setting.
Submitted-by: Birger Koblitz <git@birger-koblitz.de>
---
--- a/drivers/irqchip/irq-realtek-rtl.c
+++ b/drivers/irqchip/irq-realtek-rtl.c
-@@ -21,21 +21,63 @@
- #define RTL_ICTL_IRR2 0x10
+@@ -22,21 +22,56 @@
#define RTL_ICTL_IRR3 0x14
+ #define RTL_ICTL_NUM_INPUTS 32
+-
-#define REG(x) (realtek_ictl_base + x)
-+#define RTL_ICTL_NUM_INPUTS 32
+#define RTL_ICTL_NUM_OUTPUTS 15
static DEFINE_RAW_SPINLOCK(irq_lock);
+
+#define REG(offset, cpu) (realtek_ictl_base[cpu] + offset)
+
++static u32 realtek_ictl_unmask[NR_CPUS];
+static void __iomem *realtek_ictl_base[NR_CPUS];
+static cpumask_t realtek_ictl_cpu_configurable;
+
+ struct irq_domain *domain;
+ u32 child_mask;
+};
-+
-+/*
-+ * IRR0-IRR3 store 4 bits per interrupt, but Realtek uses inverted numbering,
-+ * placing IRQ 31 in the first four bits. A routing value of '0' means the
-+ * interrupt is left disconnected. Routing values {1..15} connect to output
-+ * lines {0..14}.
-+ */
-+#define IRR_OFFSET(idx) (4 * (3 - (idx * 4) / 32))
-+#define IRR_SHIFT(idx) ((idx * 4) % 32)
-+
-+static inline u32 read_irr(void __iomem *irr0, int idx)
+
+ /*
+- * IRR0-IRR3 store 4 bits per interrupt, but Realtek uses inverted numbering,
+- * placing IRQ 31 in the first four bits. A routing value of '0' means the
+- * interrupt is left disconnected. Routing values {1..15} connect to output
+- * lines {0..14}.
++ * Per CPU we have a set of 5 registers that determine interrupt handling for
++ * 32 external interrupts. GIMR (enable/disable interrupt) plus IRR0-IRR3 that
++ * contain "routing" or "priority" values. GIMR uses one bit for each interrupt
++ * and IRRx store 4 bits per interrupt. Realtek uses inverted numbering,
++ * placing IRQ 31 in the first four bits. The register combinations give the
++ * following results for a single interrupt in the wild:
++ *
++ * a) GIMR = 0 / IRRx > 0 -> no interrupts
++ * b) GIMR = 0 / IRRx = 0 -> no interrupts
++ * c) GIMR = 1 / IRRx > 0 -> interrupts
++ * d) GIMR = 1 / IRRx = 0 -> rare interrupts in SMP environment
++ *
++ * Combination d) seems to trigger interrupts only on a VPE if the other VPE
++ * has GIMR = 0 and IRRx > 0. E.g. busy without interrupts allowed. To provide
++ * IRQ balancing features in SMP this driver will handle the registers as
++ * follows:
++ *
++ * 1) set IRRx > 0 for VPE where the interrupt is desired
++ * 2) set IRRx = 0 for VPE where the interrupt is not desired
++ * 3) set both GIMR = 0 to mask (disabled) interrupt
++ * 4) set GIMR = 1 to unmask (enable) interrupt but only for VPE where IRRx > 0
+ */
+ #define IRR_OFFSET(idx) (4 * (3 - (idx * 4) / 32))
+ #define IRR_SHIFT(idx) ((idx * 4) % 32)
+
++static u32 read_irr(void __iomem *irr0, int idx)
+{
+ return (readl(irr0 + IRR_OFFSET(idx)) >> IRR_SHIFT(idx)) & 0xf;
+}
+
-+static inline void write_irr(void __iomem *irr0, int idx, u32 value)
+ static void write_irr(void __iomem *irr0, int idx, u32 value)
+ {
+ unsigned int offset = IRR_OFFSET(idx);
+@@ -48,16 +83,33 @@ static void write_irr(void __iomem *irr0
+ writel(irr, irr0 + offset);
+ }
+
++static void enable_gimr(int hwirq, int cpu)
+{
-+ unsigned int offset = IRR_OFFSET(idx);
-+ unsigned int shift = IRR_SHIFT(idx);
-+ u32 irr;
++ u32 value;
+
-+ irr = readl(irr0 + offset) & ~(0xf << shift);
-+ irr |= (value & 0xf) << shift;
-+ writel(irr, irr0 + offset);
++ value = readl(REG(RTL_ICTL_GIMR, cpu));
++ value |= (BIT(hwirq) & realtek_ictl_unmask[cpu]);
++ writel(value, REG(RTL_ICTL_GIMR, cpu));
+}
-
++
++static void disable_gimr(int hwirq, int cpu)
++{
++ u32 value;
++
++ value = readl(REG(RTL_ICTL_GIMR, cpu));
++ value &= ~BIT(hwirq);
++ writel(value, REG(RTL_ICTL_GIMR, cpu));
++}
++
static void realtek_ictl_unmask_irq(struct irq_data *i)
{
unsigned long flags;
- u32 value;
+- u32 value;
+ int cpu;
raw_spin_lock_irqsave(&irq_lock, flags);
- value = readl(REG(RTL_ICTL_GIMR));
- value |= BIT(i->hwirq);
- writel(value, REG(RTL_ICTL_GIMR));
-+ for_each_cpu(cpu, &realtek_ictl_cpu_configurable) {
-+ value = readl(REG(RTL_ICTL_GIMR, cpu));
-+ value |= BIT(i->hwirq);
-+ writel(value, REG(RTL_ICTL_GIMR, cpu));
-+ }
++ for_each_cpu(cpu, &realtek_ictl_cpu_configurable)
++ enable_gimr(i->hwirq, cpu);
raw_spin_unlock_irqrestore(&irq_lock, flags);
}
-@@ -44,52 +86,137 @@ static void realtek_ictl_mask_irq(struct
+@@ -65,110 +117,253 @@ static void realtek_ictl_unmask_irq(stru
+ static void realtek_ictl_mask_irq(struct irq_data *i)
{
unsigned long flags;
- u32 value;
+- u32 value;
+ int cpu;
raw_spin_lock_irqsave(&irq_lock, flags);
- value = readl(REG(RTL_ICTL_GIMR));
- value &= ~BIT(i->hwirq);
- writel(value, REG(RTL_ICTL_GIMR));
-+ for_each_cpu(cpu, &realtek_ictl_cpu_configurable) {
-+ value = readl(REG(RTL_ICTL_GIMR, cpu));
-+ value &= ~BIT(i->hwirq);
-+ writel(value, REG(RTL_ICTL_GIMR, cpu));
-+ }
++ for_each_cpu(cpu, &realtek_ictl_cpu_configurable)
++ disable_gimr(i->hwirq, cpu);
raw_spin_unlock_irqrestore(&irq_lock, flags);
}
+ cpumask_and(&cpu_enable, &cpu_configure, dest);
+ cpumask_andnot(&cpu_disable, &cpu_configure, dest);
+
-+ for_each_cpu(cpu, &cpu_disable)
++ for_each_cpu(cpu, &cpu_disable) {
+ write_irr(REG(RTL_ICTL_IRR0, cpu), i->hwirq, 0);
++ realtek_ictl_unmask[cpu] &= ~BIT(i->hwirq);
++ disable_gimr(i->hwirq, cpu);
++ }
+
-+ for_each_cpu(cpu, &cpu_enable)
++ for_each_cpu(cpu, &cpu_enable) {
+ write_irr(REG(RTL_ICTL_IRR0, cpu), i->hwirq, output->output_index + 1);
++ realtek_ictl_unmask[cpu] |= BIT(i->hwirq);
++ enable_gimr(i->hwirq, cpu);
++ }
+
+ irq_data_update_effective_affinity(i, &cpu_enable);
+
static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
{
+ struct realtek_ictl_output *output = d->host_data;
-+ unsigned long flags;
-+
+ unsigned long flags;
+
irq_set_chip_and_handler(irq, &realtek_ictl_irq, handle_level_irq);
-+ raw_spin_lock_irqsave(&irq_lock, flags);
+ raw_spin_lock_irqsave(&irq_lock, flags);
+- write_irr(REG(RTL_ICTL_IRR0), hw, 1);
+
+ output->child_mask |= BIT(hw);
+ write_irr(REG(RTL_ICTL_IRR0, 0), hw, output->output_index + 1);
++ realtek_ictl_unmask[0] |= BIT(hw);
+
-+ raw_spin_unlock_irqrestore(&irq_lock, flags);
-+
+ raw_spin_unlock_irqrestore(&irq_lock, flags);
+
return 0;
}
out:
chained_irq_exit(chip, desc);
-@@ -102,85 +229,110 @@ out:
- * thus go into 4 IRRs. A routing value of '0' means the interrupt is left
- * disconnected. Routing values {1..15} connect to output lines {0..14}.
- */
--static int __init map_interrupts(struct device_node *node, struct irq_domain *domain)
-+static int __init setup_parent_interrupts(struct device_node *node, int *parents,
-+ unsigned int num_parents)
- {
-- struct device_node *cpu_ictl;
-- const __be32 *imap;
-- u32 imaplen, soc_int, cpu_int, tmp, regs[4];
-- int ret, i, irr_regs[] = {
-- RTL_ICTL_IRR3,
-- RTL_ICTL_IRR2,
-- RTL_ICTL_IRR1,
-- RTL_ICTL_IRR0,
-- };
-- u8 mips_irqs_set;
+ }
+
++static int __init setup_parent_interrupts(struct device_node *node, int *parents,
++ int num_parents)
++ {
+ struct realtek_ictl_output *outputs;
+ struct realtek_ictl_output *output;
+ struct irq_domain *domain;
+ unsigned int p;
-
-- ret = of_property_read_u32(node, "#address-cells", &tmp);
-- if (ret || tmp)
-- return -EINVAL;
-+ outputs = kcalloc(num_parents, sizeof(*outputs), GFP_KERNEL);
++ int ret;
++
++ outputs = kcalloc(num_parents, sizeof(struct realtek_ictl_output *), GFP_KERNEL);
+ if (!outputs)
+ return -ENOMEM;
-
-- imap = of_get_property(node, "interrupt-map", &imaplen);
-- if (!imap || imaplen % 3)
-- return -EINVAL;
++
+ for (p = 0; p < num_parents; p++) {
+ output = outputs + p;
-
-- mips_irqs_set = 0;
-- memset(regs, 0, sizeof(regs));
-- for (i = 0; i < imaplen; i += 3 * sizeof(u32)) {
-- soc_int = be32_to_cpup(imap);
-- if (soc_int > 31)
-- return -EINVAL;
--
-- cpu_ictl = of_find_node_by_phandle(be32_to_cpup(imap + 1));
-- if (!cpu_ictl)
-- return -EINVAL;
-- ret = of_property_read_u32(cpu_ictl, "#interrupt-cells", &tmp);
-- of_node_put(cpu_ictl);
-- if (ret || tmp != 1)
-- return -EINVAL;
--
-- cpu_int = be32_to_cpup(imap + 2);
-- if (cpu_int > 7 || cpu_int < 2)
-- return -EINVAL;
--
-- if (!(mips_irqs_set & BIT(cpu_int))) {
-- irq_set_chained_handler_and_data(cpu_int, realtek_irq_dispatch,
-- domain);
-- mips_irqs_set |= BIT(cpu_int);
-- }
++
+ domain = irq_domain_add_linear(node, RTL_ICTL_NUM_INPUTS, &irq_domain_ops, output);
+ if (!domain)
+ goto domain_err;
-
-- /* Use routing values (1..6) for CPU interrupts (2..7) */
-- regs[(soc_int * 4) / 32] |= (cpu_int - 1) << (soc_int * 4) % 32;
-- imap += 3;
-- }
++
+ output->fwnode = of_node_to_fwnode(node);
+ output->output_index = p;
+ output->domain = domain;
-
-- for (i = 0; i < 4; i++)
-- writel(regs[i], REG(irr_regs[i]));
++
+ irq_set_chained_handler_and_data(parents[p], realtek_irq_dispatch, output);
+ }
-
- return 0;
++
++ return 0;
+
+domain_err:
+ while (p--) {
+ kfree(outputs);
+
+ return -ENOMEM;
- }
-
++}
++
static int __init realtek_rtl_of_init(struct device_node *node, struct device_node *parent)
{
-- struct irq_domain *domain;
-- int ret;
+ int parent_irqs[RTL_ICTL_NUM_OUTPUTS];
-+ struct of_phandle_args oirq;
+ struct of_phandle_args oirq;
+- struct irq_domain *domain;
+ unsigned int num_parents;
-+ unsigned int soc_irq;
+ unsigned int soc_irq;
+- int parent_irq;
+ unsigned int p;
+ int cpu;
-+
+
+- realtek_ictl_base = of_iomap(node, 0);
+- if (!realtek_ictl_base)
+- return -ENXIO;
+-
+- /* Disable all cascaded interrupts and clear routing */
+- writel(0, REG(RTL_ICTL_GIMR));
+- for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++)
+- write_irr(REG(RTL_ICTL_IRR0), soc_irq, 0);
+-
+- if (WARN_ON(!of_irq_count(node))) {
+- /*
+- * If DT contains no parent interrupts, assume MIPS CPU IRQ 2
+- * (HW0) is connected to the first output. This is the case for
+- * all known hardware anyway. "interrupt-map" is deprecated, so
+- * don't bother trying to parse that.
+- */
+- oirq.np = of_find_compatible_node(NULL, NULL, "mti,cpu-interrupt-controller");
+- oirq.args_count = 1;
+- oirq.args[0] = 2;
+-
+- parent_irq = irq_create_of_mapping(&oirq);
+-
+- of_node_put(oirq.np);
+- } else {
+- parent_irq = of_irq_get(node, 0);
+- }
+-
+- if (parent_irq < 0)
+- return parent_irq;
+- else if (!parent_irq)
+- return -ENODEV;
+ cpumask_clear(&realtek_ictl_cpu_configurable);
-+
+
+- domain = irq_domain_add_linear(node, RTL_ICTL_NUM_INPUTS, &irq_domain_ops, NULL);
+- if (!domain)
+- return -ENOMEM;
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ realtek_ictl_base[cpu] = of_iomap(node, cpu);
+ if (realtek_ictl_base[cpu]) {
+ cpumask_set_cpu(cpu, &realtek_ictl_cpu_configurable);
+
+ /* Disable all cascaded interrupts and clear routing */
-+ writel(0, REG(RTL_ICTL_GIMR, cpu));
-+ for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++)
++ for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++) {
+ write_irr(REG(RTL_ICTL_IRR0, cpu), soc_irq, 0);
++ realtek_ictl_unmask[cpu] &= ~BIT(soc_irq);
++ disable_gimr(soc_irq, cpu);
++ }
+ }
+ }
-- realtek_ictl_base = of_iomap(node, 0);
-- if (!realtek_ictl_base)
+- irq_set_chained_handler_and_data(parent_irq, realtek_irq_dispatch, domain);
+ if (cpumask_empty(&realtek_ictl_cpu_configurable))
- return -ENXIO;
++ return -ENXIO;
-- /* Disable all cascaded interrupts */
-- writel(0, REG(RTL_ICTL_GIMR));
+- return 0;
+ num_parents = of_irq_count(node);
+ if (num_parents > RTL_ICTL_NUM_OUTPUTS) {
+ pr_err("too many parent interrupts\n");
+ return -EINVAL;
+ }
-
-- domain = irq_domain_add_simple(node, 32, 0,
-- &irq_domain_ops, NULL);
-+ for (p = 0; p < num_parents; p++)
-+ parent_irqs[p] = of_irq_get(node, p);
-
-- ret = map_interrupts(node, domain);
-- if (ret) {
-- pr_err("invalid interrupt map\n");
-- return ret;
++
+ if (WARN_ON(!num_parents)) {
-+ /*
-+ * If DT contains no parent interrupts, assume MIPS CPU IRQ 2
-+ * (HW0) is connected to the first output. This is the case for
-+ * all known hardware anyway. "interrupt-map" is deprecated, so
-+ * don't bother trying to parse that.
++ /*
++ * If DT contains no parent interrupts, assume MIPS CPU IRQ 2
++ * (HW0) is connected to the first output. This is the case for
++ * all known hardware anyway. "interrupt-map" is deprecated, so
++ * don't bother trying to parse that.
+ * Since this is to account for old devicetrees with one-cell
-+ * interrupt specifiers, only one output domain is needed.
-+ */
-+ oirq.np = of_find_compatible_node(NULL, NULL, "mti,cpu-interrupt-controller");
++ * interrupt specifiers, only one output domain/parent is needed.
++ */
++ oirq.np = of_find_compatible_node(NULL, NULL, "mti,cpu-interrupt-controller");
+ if (oirq.np) {
+ oirq.args_count = 1;
+ oirq.args[0] = 2;
+ num_parents = 1;
+ }
+
-+ of_node_put(oirq.np);
- }
-
-- return 0;
++ of_node_put(oirq.np);
++ } else {
++ for (p = 0; p < num_parents; p++)
++ parent_irqs[p] = of_irq_get(node, p);
++ }
++
+ /* Ensure we haven't collected any errors before proceeding */
+ for (p = 0; p < num_parents; p++) {
+ if (parent_irqs[p] < 0)
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
-@@ -405,6 +405,7 @@ source "drivers/clk/mstar/Kconfig"
+@@ -454,6 +454,7 @@ source "drivers/clk/microchip/Kconfig"
source "drivers/clk/mvebu/Kconfig"
source "drivers/clk/pistachio/Kconfig"
source "drivers/clk/qcom/Kconfig"
source "drivers/clk/rockchip/Kconfig"
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
-@@ -101,6 +101,7 @@ obj-$(CONFIG_COMMON_CLK_PISTACHIO) += pi
+@@ -108,6 +108,7 @@ obj-$(CONFIG_COMMON_CLK_PISTACHIO) += pi
obj-$(CONFIG_COMMON_CLK_PXA) += pxa/
obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
obj-y += ralink/
+++ /dev/null
-From 2cd00b51470a30198b048a5fca48a04db77e29cc Mon Sep 17 00:00:00 2001
-From: INAGAKI Hiroshi <musashino.open@gmail.com>
-Date: Fri, 21 May 2021 23:16:37 +0900
-Subject: [PATCH] realtek: backport irq-realtek-rtl driver from 5.12 to 5.10
-
-This patch backports "irq-realtek-rtl" driver to Kernel 5.10 from 5.12.
-"MACH_REALTEK_RTL" is used as a platform name in upstream, but "RTL838X"
-is used in OpenWrt, so update the dependency by the additional patch.
-
-Submitted-by: INAGAKI Hiroshi <musashino.open@gmail.com>
----
- drivers/irqchip/irq-realtek-rtl.c | 38 +++++++++++------
- 1 files changed, 58 insertions(+), 20 deletions(-)
-
---- a/drivers/irqchip/irq-realtek-rtl.c
-+++ b/drivers/irqchip/irq-realtek-rtl.c
-@@ -28,6 +28,7 @@ static DEFINE_RAW_SPINLOCK(irq_lock);
-
- #define REG(offset, cpu) (realtek_ictl_base[cpu] + offset)
-
-+static u32 realtek_ictl_unmask[NR_CPUS];
- static void __iomem *realtek_ictl_base[NR_CPUS];
- static cpumask_t realtek_ictl_cpu_configurable;
-
-@@ -41,11 +42,29 @@ struct realtek_ictl_output {
- };
-
- /*
-- * IRR0-IRR3 store 4 bits per interrupt, but Realtek uses inverted numbering,
-- * placing IRQ 31 in the first four bits. A routing value of '0' means the
-- * interrupt is left disconnected. Routing values {1..15} connect to output
-- * lines {0..14}.
-+ * Per CPU we have a set of 5 registers that determine interrupt handling for
-+ * 32 external interrupts. GIMR (enable/disable interrupt) plus IRR0-IRR3 that
-+ * contain "routing" or "priority" values. GIMR uses one bit for each interrupt
-+ * and IRRx store 4 bits per interrupt. Realtek uses inverted numbering,
-+ * placing IRQ 31 in the first four bits. The register combinations give the
-+ * following results for a single interrupt in the wild:
-+ *
-+ * a) GIMR = 0 / IRRx > 0 -> no interrupts
-+ * b) GIMR = 0 / IRRx = 0 -> no interrupts
-+ * c) GIMR = 1 / IRRx > 0 -> interrupts
-+ * d) GIMR = 1 / IRRx = 0 -> rare interrupts in SMP environment
-+ *
-+ * Combination d) seems to trigger interrupts only on a VPE if the other VPE
-+ * has GIMR = 0 and IRRx > 0. E.g. busy without interrupts allowed. To provide
-+ * IRQ balancing features in SMP this driver will handle the registers as
-+ * follows:
-+ *
-+ * 1) set IRRx > 0 for VPE where the interrupt is desired
-+ * 2) set IRRx = 0 for VPE where the interrupt is not desired
-+ * 3) set both GIMR = 0 to mask (disabled) interrupt
-+ * 4) set GIMR = 1 to unmask (enable) interrupt but only for VPE where IRRx > 0
- */
-+
- #define IRR_OFFSET(idx) (4 * (3 - (idx * 4) / 32))
- #define IRR_SHIFT(idx) ((idx * 4) % 32)
-
-@@ -65,19 +84,33 @@ static inline void write_irr(void __iome
- writel(irr, irr0 + offset);
- }
-
-+static inline void enable_gimr(int hwirq, int cpu)
-+{
-+ u32 value;
-+
-+ value = readl(REG(RTL_ICTL_GIMR, cpu));
-+ value |= (BIT(hwirq) & realtek_ictl_unmask[cpu]);
-+ writel(value, REG(RTL_ICTL_GIMR, cpu));
-+}
-+
-+static inline void disable_gimr(int hwirq, int cpu)
-+{
-+ u32 value;
-+
-+ value = readl(REG(RTL_ICTL_GIMR, cpu));
-+ value &= ~BIT(hwirq);
-+ writel(value, REG(RTL_ICTL_GIMR, cpu));
-+}
-+
- static void realtek_ictl_unmask_irq(struct irq_data *i)
- {
- unsigned long flags;
-- u32 value;
- int cpu;
-
- raw_spin_lock_irqsave(&irq_lock, flags);
-
-- for_each_cpu(cpu, &realtek_ictl_cpu_configurable) {
-- value = readl(REG(RTL_ICTL_GIMR, cpu));
-- value |= BIT(i->hwirq);
-- writel(value, REG(RTL_ICTL_GIMR, cpu));
-- }
-+ for_each_cpu(cpu, &realtek_ictl_cpu_configurable)
-+ enable_gimr(i->hwirq, cpu);
-
- raw_spin_unlock_irqrestore(&irq_lock, flags);
- }
-@@ -85,16 +118,12 @@ static void realtek_ictl_unmask_irq(stru
- static void realtek_ictl_mask_irq(struct irq_data *i)
- {
- unsigned long flags;
-- u32 value;
- int cpu;
-
- raw_spin_lock_irqsave(&irq_lock, flags);
-
-- for_each_cpu(cpu, &realtek_ictl_cpu_configurable) {
-- value = readl(REG(RTL_ICTL_GIMR, cpu));
-- value &= ~BIT(i->hwirq);
-- writel(value, REG(RTL_ICTL_GIMR, cpu));
-- }
-+ for_each_cpu(cpu, &realtek_ictl_cpu_configurable)
-+ disable_gimr(i->hwirq, cpu);
-
- raw_spin_unlock_irqrestore(&irq_lock, flags);
- }
-@@ -116,11 +145,17 @@ static int __maybe_unused realtek_ictl_i
- cpumask_and(&cpu_enable, &cpu_configure, dest);
- cpumask_andnot(&cpu_disable, &cpu_configure, dest);
-
-- for_each_cpu(cpu, &cpu_disable)
-+ for_each_cpu(cpu, &cpu_disable) {
- write_irr(REG(RTL_ICTL_IRR0, cpu), i->hwirq, 0);
-+ realtek_ictl_unmask[cpu] &= ~BIT(i->hwirq);
-+ disable_gimr(i->hwirq, cpu);
-+ }
-
-- for_each_cpu(cpu, &cpu_enable)
-+ for_each_cpu(cpu, &cpu_enable) {
- write_irr(REG(RTL_ICTL_IRR0, cpu), i->hwirq, output->output_index + 1);
-+ realtek_ictl_unmask[cpu] |= BIT(i->hwirq);
-+ enable_gimr(i->hwirq, cpu);
-+ }
-
- irq_data_update_effective_affinity(i, &cpu_enable);
-
-@@ -149,6 +184,7 @@ static int intc_map(struct irq_domain *d
-
- output->child_mask |= BIT(hw);
- write_irr(REG(RTL_ICTL_IRR0, 0), hw, output->output_index + 1);
-+ realtek_ictl_unmask[0] |= BIT(hw);
-
- raw_spin_unlock_irqrestore(&irq_lock, flags);
-
-@@ -285,9 +321,11 @@ static int __init realtek_rtl_of_init(st
- cpumask_set_cpu(cpu, &realtek_ictl_cpu_configurable);
-
- /* Disable all cascaded interrupts and clear routing */
-- writel(0, REG(RTL_ICTL_GIMR, cpu));
-- for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++)
-+ for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++) {
- write_irr(REG(RTL_ICTL_IRR0, cpu), soc_irq, 0);
-+ realtek_ictl_unmask[cpu] &= ~BIT(soc_irq);
-+ disable_gimr(soc_irq, cpu);
-+ }
- }
- }
-
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
-@@ -85,6 +85,8 @@ source "drivers/net/dsa/sja1105/Kconfig"
+@@ -87,6 +87,8 @@ source "drivers/net/dsa/xrs700x/Kconfig"
- source "drivers/net/dsa/xrs700x/Kconfig"
+ source "drivers/net/dsa/realtek/Kconfig"
+source "drivers/net/dsa/rtl83xx/Kconfig"
+
- config NET_DSA_REALTEK_SMI
- tristate "Realtek SMI Ethernet switch family support"
- select NET_DSA_TAG_RTL4_A
+ config NET_DSA_RZN1_A5PSW
+ tristate "Renesas RZ/N1 A5PSW Ethernet switch support"
+ depends on OF && ARCH_RZN1
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
-@@ -24,5 +24,6 @@ obj-y += microchip/
- obj-y += mv88e6xxx/
+@@ -24,5 +24,6 @@ obj-y += mv88e6xxx/
obj-y += ocelot/
obj-y += qca/
+ obj-y += realtek/
+obj-y += rtl83xx/
obj-y += sja1105/
obj-y += xrs700x/
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
-@@ -166,6 +166,13 @@ source "drivers/net/ethernet/rdc/Kconfig
+@@ -171,6 +171,13 @@ source "drivers/net/ethernet/rdc/Kconfig
source "drivers/net/ethernet/realtek/Kconfig"
source "drivers/net/ethernet/renesas/Kconfig"
source "drivers/net/ethernet/rocker/Kconfig"
source "drivers/net/ethernet/sgi/Kconfig"
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
-@@ -77,6 +77,7 @@ obj-$(CONFIG_NET_VENDOR_REALTEK) += real
+@@ -81,6 +81,7 @@ obj-$(CONFIG_NET_VENDOR_REALTEK) += real
obj-$(CONFIG_NET_VENDOR_RENESAS) += renesas/
obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
obj-$(CONFIG_NET_VENDOR_ROCKER) += rocker/
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
-@@ -943,6 +943,10 @@ struct phy_driver {
- int (*get_sqi)(struct phy_device *dev);
- /** @get_sqi_max: Get the maximum signal quality indication */
- int (*get_sqi_max)(struct phy_device *dev);
+@@ -1083,6 +1083,11 @@ struct phy_driver {
+ */
+ int (*led_polarity_set)(struct phy_device *dev, int index,
+ unsigned long modes);
++
+ int (*get_port)(struct phy_device *dev);
+ int (*set_port)(struct phy_device *dev, int port);
+ int (*get_eee)(struct phy_device *dev, struct ethtool_eee *e);
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
-@@ -1942,6 +1942,11 @@ int phylink_ethtool_ksettings_set(struct
+@@ -2245,6 +2245,11 @@ int phylink_ethtool_ksettings_set(struct
* the presence of a PHY, this should not be changed as that
* should be determined from the media side advertisement.
*/
return phy_ethtool_ksettings_set(pl->phydev, kset);
}
-@@ -2245,8 +2250,11 @@ int phylink_ethtool_get_eee(struct phyli
+@@ -2548,8 +2553,11 @@ int phylink_ethtool_get_eee(struct phyli
ASSERT_RTNL();
return ret;
}
-@@ -2263,8 +2271,11 @@ int phylink_ethtool_set_eee(struct phyli
+@@ -2566,8 +2574,11 @@ int phylink_ethtool_set_eee(struct phyli
ASSERT_RTNL();
Submitted-by: Birger Koblitz <git@birger-koblitz.de>
---
+ drivers/net/phy/phy-core.c | 1 +
drivers/net/phy/phylink.c | 2 ++
include/linux/phy.h | 3 +++
2 file changed, 5 insertions(+)
+--- a/drivers/net/phy/phy-core.c
++++ b/drivers/net/phy/phy-core.c
+@@ -123,6 +123,7 @@ int phy_interface_num_ports(phy_interfac
+ case PHY_INTERFACE_MODE_XLGMII:
+ case PHY_INTERFACE_MODE_MOCA:
+ case PHY_INTERFACE_MODE_TRGMII:
++ case PHY_INTERFACE_MODE_HSGMII:
+ case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_SMII:
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
-@@ -403,6 +403,7 @@ void phylink_get_linkmodes(unsigned long
+@@ -205,6 +205,7 @@ static int phylink_interface_max_speed(p
+ case PHY_INTERFACE_MODE_5GBASER:
+ return SPEED_5000;
+
++ case PHY_INTERFACE_MODE_HSGMII:
+ case PHY_INTERFACE_MODE_XGMII:
+ case PHY_INTERFACE_MODE_RXAUI:
+ case PHY_INTERFACE_MODE_XAUI:
+@@ -495,6 +496,7 @@ unsigned long phylink_get_capabilities(p
case PHY_INTERFACE_MODE_XGMII:
case PHY_INTERFACE_MODE_RXAUI:
case PHY_INTERFACE_MODE_XAUI:
case PHY_INTERFACE_MODE_10GBASER:
case PHY_INTERFACE_MODE_10GKR:
-@@ -657,6 +658,7 @@ static int phylink_parse_mode(struct phy
+@@ -856,6 +858,7 @@ static int phylink_parse_mode(struct phy
fallthrough;
case PHY_INTERFACE_MODE_USXGMII:
case PHY_INTERFACE_MODE_10GKR:
phylink_set(pl->supported, 10baseT_Full);
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
-@@ -138,6 +138,7 @@ typedef enum {
+@@ -142,6 +142,7 @@ typedef enum {
PHY_INTERFACE_MODE_XGMII,
PHY_INTERFACE_MODE_XLGMII,
PHY_INTERFACE_MODE_MOCA,
+ PHY_INTERFACE_MODE_HSGMII,
+ PHY_INTERFACE_MODE_PSGMII,
PHY_INTERFACE_MODE_QSGMII,
PHY_INTERFACE_MODE_TRGMII,
- PHY_INTERFACE_MODE_100BASEX,
-@@ -243,6 +244,8 @@ static inline const char *phy_modes(phy_
+@@ -250,6 +251,8 @@ static inline const char *phy_modes(phy_
return "xlgmii";
case PHY_INTERFACE_MODE_MOCA:
return "moca";
+ case PHY_INTERFACE_MODE_HSGMII:
+ return "hsgmii";
+ case PHY_INTERFACE_MODE_PSGMII:
+ return "psgmii";
case PHY_INTERFACE_MODE_QSGMII:
- return "qsgmii";
- case PHY_INTERFACE_MODE_TRGMII:
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
-@@ -356,6 +356,12 @@ config REALTEK_PHY
+@@ -371,6 +371,12 @@ config REALTEK_PHY
help
Supports the Realtek 821x PHY.
help
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
-@@ -93,6 +93,7 @@ obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp
- obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o
+@@ -92,6 +92,7 @@ obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja
+ obj-y += qcom/
obj-$(CONFIG_QSEMI_PHY) += qsemi.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
+obj-$(CONFIG_REALTEK_SOC_PHY) += rtl83xx-phy.o
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
-@@ -279,7 +279,7 @@ static inline const char *phy_modes(phy_
+@@ -291,7 +291,7 @@ static inline const char *phy_modes(phy_
#define PHY_INIT_TIMEOUT 100000
#define PHY_FORCE_TIMEOUT 10
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
-@@ -2153,6 +2153,13 @@ static void sfp_sm_module(struct sfp *sf
+@@ -2174,6 +2174,13 @@ static void sfp_sm_module(struct sfp *sf
return;
}
+MODULE_LICENSE("GPL");
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
-@@ -60,6 +60,7 @@ config SFP
+@@ -68,6 +68,7 @@ config SFP
depends on I2C && PHYLINK
depends on HWMON || HWMON=n
select MDIO_I2C
--- a/include/linux/mdio/mdio-i2c.h
+++ b/include/linux/mdio/mdio-i2c.h
-@@ -12,5 +12,8 @@ struct i2c_adapter;
- struct mii_bus;
+@@ -18,7 +18,10 @@ enum mdio_i2c_proto {
+ MDIO_I2C_ROLLBALL,
+ };
- struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c);
-+struct mii_bus *mdio_smbus_alloc(struct device *parent, struct i2c_adapter *i2c);
+bool i2c_mii_valid_phy_id(int phy_id);
+unsigned int i2c_mii_phy_addr(int phy_id);
+ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
+ enum mdio_i2c_proto protocol);
++struct mii_bus *mdio_smbus_alloc(struct device *parent, struct i2c_adapter *i2c);
#endif
--- a/drivers/net/mdio/mdio-i2c.c
+++ b/drivers/net/mdio/mdio-i2c.c
-@@ -18,12 +18,12 @@
+@@ -20,12 +20,12 @@
* specified to be present in SFP modules. These correspond with PHY
* addresses 16 and 17. Disallow access to these "phy" addresses.
*/
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
-@@ -549,32 +549,72 @@ static int sfp_i2c_write(struct sfp *sfp
- return ret == ARRAY_SIZE(msgs) ? len : 0;
+@@ -507,6 +507,35 @@ static void sfp_gpio_set_state(struct sf
+ }
}
+static int sfp_smbus_read(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
+ return sfp->i2c_mii->write(sfp->i2c_mii, bus_addr, dev_addr, val);
+}
+
- static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
+ static int sfp_i2c_read(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
+ size_t len)
{
-- struct mii_bus *i2c_mii;
-+ struct mii_bus *mii;
- int ret;
+@@ -576,12 +605,17 @@ static int sfp_i2c_write(struct sfp *sfp
+ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
+ {
- if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
-- return -EINVAL;
--
++ if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA)) {
++ sfp->read = sfp_smbus_read;
++ sfp->write = sfp_smbus_write;
++ } else if (i2c_check_functionality(i2c, I2C_FUNC_I2C)) {
++ sfp->read = sfp_i2c_read;
++ sfp->write = sfp_i2c_write;
++ } else {
+ return -EINVAL;
++ }
+
sfp->i2c = i2c;
- sfp->read = sfp_i2c_read;
- sfp->write = sfp_i2c_write;
-- i2c_mii = mdio_i2c_alloc(sfp->dev, i2c);
+ return 0;
+ }
+@@ -591,11 +625,21 @@ static int sfp_i2c_mdiobus_create(struct
+ struct mii_bus *i2c_mii;
+ int ret;
+
+- i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c, sfp->mdio_protocol);
- if (IS_ERR(i2c_mii))
- return PTR_ERR(i2c_mii);
-+ if (i2c_check_functionality(i2c, I2C_FUNC_I2C)) {
-+ sfp->read = sfp_i2c_read;
-+ sfp->write = sfp_i2c_write;
++ if (i2c_check_functionality(sfp->i2c, I2C_FUNC_SMBUS_BYTE_DATA)) {
++ i2c_mii = mdio_smbus_alloc(sfp->dev, sfp->i2c);
++ if (IS_ERR(i2c_mii))
++ return PTR_ERR(i2c_mii);
+
-+ mii = mdio_i2c_alloc(sfp->dev, i2c);
-+ if (IS_ERR(mii))
-+ return PTR_ERR(mii);
-+
-+ mii->name = "SFP I2C Bus";
-+ } else if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA)) {
-+ sfp->read = sfp_smbus_read;
-+ sfp->write = sfp_smbus_write;
-+
-+ mii = mdio_smbus_alloc(sfp->dev, i2c);
-+ if (IS_ERR(mii))
-+ return PTR_ERR(mii);
++ i2c_mii->name = "SFP SMBus";
++ } else if (i2c_check_functionality(sfp->i2c, I2C_FUNC_I2C)) {
++ i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c, sfp->mdio_protocol);
++ if (IS_ERR(i2c_mii))
++ return PTR_ERR(i2c_mii);
- i2c_mii->name = "SFP I2C Bus";
-- i2c_mii->phy_mask = ~0;
-+ mii->name = "SFP SMBus";
++ i2c_mii->name = "SFP I2C Bus";
+ } else {
+ return -EINVAL;
+ }
+ i2c_mii->phy_mask = ~0;
-- ret = mdiobus_register(i2c_mii);
-+ mii->phy_mask = ~0;
-+ ret = mdiobus_register(mii);
- if (ret < 0) {
-- mdiobus_free(i2c_mii);
-+ mdiobus_free(mii);
- return ret;
- }
-
-- sfp->i2c_mii = i2c_mii;
-+ sfp->i2c_mii = mii;
-
- return 0;
- }
+ ret = mdiobus_register(i2c_mii);
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
-@@ -742,6 +742,32 @@ out:
+@@ -749,6 +749,32 @@ out:
}
/**
* __mdiobus_read - Unlocked version of the mdiobus_read function
* @bus: the mii_bus struct
* @addr: the phy address
-@@ -757,7 +783,10 @@ int __mdiobus_read(struct mii_bus *bus,
+@@ -764,7 +790,10 @@ int __mdiobus_read(struct mii_bus *bus,
lockdep_assert_held_once(&bus->mdio_lock);
trace_mdio_access(bus, 1, addr, regnum, retval, retval);
mdiobus_stats_acct(&bus->stats[addr], true, retval);
-@@ -767,6 +796,40 @@ int __mdiobus_read(struct mii_bus *bus,
+@@ -774,6 +803,40 @@ int __mdiobus_read(struct mii_bus *bus,
EXPORT_SYMBOL(__mdiobus_read);
/**
* __mdiobus_write - Unlocked version of the mdiobus_write function
* @bus: the mii_bus struct
* @addr: the phy address
-@@ -783,7 +846,10 @@ int __mdiobus_write(struct mii_bus *bus,
+@@ -790,7 +853,10 @@ int __mdiobus_write(struct mii_bus *bus,
lockdep_assert_held_once(&bus->mdio_lock);
trace_mdio_access(bus, 0, addr, regnum, val, err);
mdiobus_stats_acct(&bus->stats[addr], false, err);
-@@ -793,6 +859,39 @@ int __mdiobus_write(struct mii_bus *bus,
+@@ -800,6 +866,39 @@ int __mdiobus_write(struct mii_bus *bus,
EXPORT_SYMBOL(__mdiobus_write);
/**
* __mdiobus_modify_changed - Unlocked version of the mdiobus_modify function
* @bus: the mii_bus struct
* @addr: the phy address
-@@ -825,6 +924,43 @@ int __mdiobus_modify_changed(struct mii_
- EXPORT_SYMBOL_GPL(__mdiobus_modify_changed);
+@@ -926,6 +1025,43 @@ static int __mdiobus_c45_modify_changed(
+ }
/**
+ * __mdiobus_modify_changed_paged - Unlocked version of the mdiobus_modify_paged function
* mdiobus_read_nested - Nested version of the mdiobus_read function
* @bus: the mii_bus struct
* @addr: the phy address
-@@ -850,6 +986,79 @@ int mdiobus_read_nested(struct mii_bus *
+@@ -951,6 +1087,79 @@ int mdiobus_read_nested(struct mii_bus *
EXPORT_SYMBOL(mdiobus_read_nested);
/**
* mdiobus_read - Convenience function for reading a given MII mgmt register
* @bus: the mii_bus struct
* @addr: the phy address
-@@ -872,6 +1081,29 @@ int mdiobus_read(struct mii_bus *bus, in
- EXPORT_SYMBOL(mdiobus_read);
+@@ -996,6 +1205,29 @@ int mdiobus_c45_read(struct mii_bus *bus
+ EXPORT_SYMBOL(mdiobus_c45_read);
/**
+ * mdiobus_read_paged - Convenience function for reading a given paged MII mgmt register
* mdiobus_write_nested - Nested version of the mdiobus_write function
* @bus: the mii_bus struct
* @addr: the phy address
-@@ -898,6 +1130,33 @@ int mdiobus_write_nested(struct mii_bus
+@@ -1022,6 +1254,33 @@ int mdiobus_write_nested(struct mii_bus
EXPORT_SYMBOL(mdiobus_write_nested);
/**
* mdiobus_write - Convenience function for writing a given MII mgmt register
* @bus: the mii_bus struct
* @addr: the phy address
-@@ -921,6 +1180,30 @@ int mdiobus_write(struct mii_bus *bus, i
- EXPORT_SYMBOL(mdiobus_write);
+@@ -1070,6 +1329,30 @@ int mdiobus_c45_write(struct mii_bus *bu
+ EXPORT_SYMBOL(mdiobus_c45_write);
/**
+ * mdiobus_write_paged - Convenience function for writing a given paged MII mgmt register
* mdiobus_modify - Convenience function for modifying a given mdio device
* register
* @bus: the mii_bus struct
-@@ -942,6 +1225,51 @@ int mdiobus_modify(struct mii_bus *bus,
- EXPORT_SYMBOL_GPL(mdiobus_modify);
+@@ -1160,6 +1443,51 @@ int mdiobus_c45_modify_changed(struct mi
+ EXPORT_SYMBOL_GPL(mdiobus_c45_modify_changed);
/**
+ * mdiobus_modify_paged - Convenience function for modifying a given mdio device
* @dev: target MDIO device
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
-@@ -482,10 +482,16 @@ int __phy_read_mmd(struct phy_device *ph
+@@ -554,10 +554,16 @@ int __phy_read_mmd(struct phy_device *ph
struct mii_bus *bus = phydev->mdio.bus;
int phy_addr = phydev->mdio.addr;
}
return val;
}
-@@ -538,12 +544,18 @@ int __phy_write_mmd(struct phy_device *p
+@@ -610,12 +616,18 @@ int __phy_write_mmd(struct phy_device *p
struct mii_bus *bus = phydev->mdio.bus;
int phy_addr = phydev->mdio.addr;
}
return ret;
}
-@@ -749,6 +761,13 @@ EXPORT_SYMBOL_GPL(phy_modify_mmd);
+@@ -821,6 +833,13 @@ EXPORT_SYMBOL_GPL(phy_modify_mmd);
static int __phy_read_page(struct phy_device *phydev)
{
if (WARN_ONCE(!phydev->drv->read_page, "read_page callback not available, PHY driver not loaded?\n"))
return -EOPNOTSUPP;
-@@ -757,6 +776,13 @@ static int __phy_read_page(struct phy_de
+@@ -829,6 +848,13 @@ static int __phy_read_page(struct phy_de
static int __phy_write_page(struct phy_device *phydev, int page)
{
if (WARN_ONCE(!phydev->drv->write_page, "write_page callback not available, PHY driver not loaded?\n"))
return -EOPNOTSUPP;
-@@ -858,6 +884,18 @@ int phy_read_paged(struct phy_device *ph
+@@ -930,6 +956,18 @@ int phy_read_paged(struct phy_device *ph
{
int ret = 0, oldpage;
oldpage = phy_select_page(phydev, page);
if (oldpage >= 0)
ret = __phy_read(phydev, regnum);
-@@ -879,6 +917,18 @@ int phy_write_paged(struct phy_device *p
+@@ -951,6 +989,18 @@ int phy_write_paged(struct phy_device *p
{
int ret = 0, oldpage;
#define MII_DEVADDR_C45_SHIFT 16
#define MII_DEVADDR_C45_MASK GENMASK(20, 16)
#define MII_REGADDR_C45_MASK GENMASK(15, 0)
-@@ -340,11 +341,19 @@ static inline void mii_10gbt_stat_mod_li
- advertising, lpa & MDIO_AN_10GBT_STAT_LP10G);
+@@ -410,11 +411,19 @@ static inline u32 linkmode_adv_to_mii_t1
+ return result;
}
+int __mdiobus_select_page(struct mii_bus *bus, int addr, u16 page);
int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum);
int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum);
int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
-@@ -352,11 +361,51 @@ int mdiobus_write_nested(struct mii_bus
- int mdiobus_modify(struct mii_bus *bus, int addr, u32 regnum, u16 mask,
- u16 set);
+@@ -459,11 +468,51 @@ static inline int mdiodev_modify_changed
+ mask, set);
+ }
+int mdiobus_read_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum);
+int mdiobus_read_nested_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum);
static inline u16 mdiobus_c45_regad(u32 regnum)
{
return FIELD_GET(MII_REGADDR_C45_MASK, regnum);
-@@ -380,6 +429,19 @@ static inline int __mdiobus_c45_write(st
- val);
+@@ -489,6 +538,19 @@ static inline int mdiodev_c45_modify_cha
+ regnum, mask, set);
}
+static inline int __mdiobus_c22_mmd_read(struct mii_bus *bus, int prtad,
+ val);
+}
+
- static inline int mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
- u16 regnum)
- {
+ int mdiobus_register_device(struct mdio_device *mdiodev);
+ int mdiobus_unregister_device(struct mdio_device *mdiodev);
+ bool mdiobus_is_registered_device(struct mii_bus *bus, int addr);
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
-@@ -80,6 +80,7 @@ extern const int phy_10gbit_features_arr
+@@ -81,6 +81,7 @@ extern const int phy_10gbit_features_arr
#define PHY_IS_INTERNAL 0x00000001
#define PHY_RST_AFTER_CLK_EN 0x00000002
#define PHY_POLL_CABLE_TEST 0x00000004
#define MDIO_DEVICE_IS_PHY 0x80000000
/**
-@@ -420,6 +421,22 @@ struct mii_bus {
+@@ -437,6 +438,22 @@ struct mii_bus {
/** @shared: shared state across different PHYs */
struct phy_package_shared *shared[PHY_MAX_ADDR];
};
#define to_mii_bus(d) container_of(d, struct mii_bus, dev)
-@@ -1754,6 +1771,66 @@ static inline int __phy_package_read(str
+@@ -1908,6 +1925,66 @@ static inline int __phy_package_read(str
return __mdiobus_read(phydev->mdio.bus, shared->addr, regnum);
}
static inline int phy_package_write(struct phy_device *phydev,
u32 regnum, u16 val)
{
-@@ -1776,6 +1853,72 @@ static inline int __phy_package_write(st
+@@ -1930,6 +2007,72 @@ static inline int __phy_package_write(st
return __mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
}