diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-04 01:55:55 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-04 01:55:55 +0200 |
commit | 807249d3ada1ff28a47c4054ca4edd479421b671 (patch) | |
tree | a9051ff7b4c31670ac89bb037c90d5baf90d449d /drivers | |
parent | Merge tag 'powerpc-4.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/po... (diff) | |
parent | Merge branch '4.2-fixes' into mips-for-linux-next (diff) | |
download | linux-807249d3ada1ff28a47c4054ca4edd479421b671.tar.xz linux-807249d3ada1ff28a47c4054ca4edd479421b671.zip |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle:
"This is the main pull request for 4.3 for MIPS. Here's the summary:
Three fixes that didn't make 4.2-stable:
- a -Os build might compile the kernel using the MIPS16 instruction
set but the R2 optimized inline functions in <uapi/asm/swab.h> are
implemented using 32-bit wide instructions which is invalid.
- a build error in pgtable-bits.h for a particular kernel
configuration.
- accessing registers of the CM GCR might have been compiled to use
64 bit accesses but these registers are onl 32 bit wide.
And also a few new bits:
- move the ATH79 GPIO driver to drivers/gpio
- the definition of IRQCHIP_DECLARE has moved to linux/irqchip.h,
change ATH79 accordingly.
- fix definition of pgprot_writecombine
- add an implementation of dma_map_ops.mmap
- fix alignment of quiet build output for vmlinuz link
- BCM47xx: Use kmemdup rather than duplicating its implementation
- Netlogic: Fix 0x0x prefixes of constants.
- merge Bjorn Helgaas' series to remove most of the weak keywords
from function declarations.
- CP0 and CP1 registers are best considered treated as unsigned
values to avoid large values from becoming negative values.
- improve support for the MIPS GIC timer.
- enable common clock framework for Malta and SEAD3.
- a number of improvments and fixes to dump_tlb().
- document the MIPS TLB dump functionality in Magic SysRq.
- Cavium Octeon CN68XX improvments.
- NetLogic improvments.
- irq: Use access helper irq_data_get_affinity_mask.
- handle MSA unaligned accesses.
- a number of R6-related math-emu fixes.
- support for I6400.
- improvments to MSA support.
- add uprobes support.
- move from deprecated __initcall to arch_initcall.
- remove finish_arch_switch().
- IRQ cleanups by Thomas Gleixner.
- migrate to new 'set-state' interface.
- random small cleanups"
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (148 commits)
MIPS: UAPI: Fix unrecognized opcode WSBH/DSBH/DSHD when using MIPS16.
MIPS: Fix alignment of quiet build output for vmlinuz link
MIPS: math-emu: Remove unused handle_dsemul function declaration
MIPS: math-emu: Add support for the MIPS R6 MAX{, A} FPU instruction
MIPS: math-emu: Add support for the MIPS R6 MIN{, A} FPU instruction
MIPS: math-emu: Add support for the MIPS R6 CLASS FPU instruction
MIPS: math-emu: Add support for the MIPS R6 RINT FPU instruction
MIPS: math-emu: Add support for the MIPS R6 MSUBF FPU instruction
MIPS: math-emu: Add support for the MIPS R6 MADDF FPU instruction
MIPS: math-emu: Add support for the MIPS R6 SELNEZ FPU instruction
MIPS: math-emu: Add support for the MIPS R6 SELEQZ FPU instruction
MIPS: math-emu: Add support for the CMP.condn.fmt R6 instruction
MIPS: inst.h: Add new MIPS R6 FPU opcodes
MIPS: Octeon: Fix management port MII address on Kontron S1901
MIPS: BCM47xx: Use kmemdup rather than duplicating its implementation
STAGING: Octeon: Use common helpers for determining interface and port
MIPS: Octeon: Support interfaces 4 and 5
MIPS: Octeon: Set up 1:1 mapping between CN68XX PKO queues and ports
MIPS: Octeon: Initialize CN68XX PKO
STAGING: Octeon: Support CN68XX style WQE
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/pata_rb532_cf.c | 3 | ||||
-rw-r--r-- | drivers/bus/mips_cdmm.c | 14 | ||||
-rw-r--r-- | drivers/clocksource/Kconfig | 4 | ||||
-rw-r--r-- | drivers/clocksource/Makefile | 1 | ||||
-rw-r--r-- | drivers/clocksource/mips-gic-timer.c | 65 | ||||
-rw-r--r-- | drivers/clocksource/time-pistachio.c | 217 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-ath79.c | 204 | ||||
-rw-r--r-- | drivers/input/misc/rb532_button.c | 1 | ||||
-rw-r--r-- | drivers/irqchip/irq-mips-gic.c | 142 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/cpmac.c | 2 | ||||
-rw-r--r-- | drivers/staging/octeon/ethernet-rx.c | 133 | ||||
-rw-r--r-- | drivers/staging/octeon/ethernet-tx.c | 19 | ||||
-rw-r--r-- | drivers/staging/octeon/ethernet-util.h | 22 | ||||
-rw-r--r-- | drivers/staging/octeon/ethernet.c | 7 | ||||
-rw-r--r-- | drivers/tty/mips_ejtag_fdc.c | 9 |
16 files changed, 718 insertions, 126 deletions
diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c index 6d08446b877c..12fe0f3bb7e9 100644 --- a/drivers/ata/pata_rb532_cf.c +++ b/drivers/ata/pata_rb532_cf.c @@ -27,12 +27,11 @@ #include <linux/io.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/gpio.h> #include <linux/libata.h> #include <scsi/scsi_host.h> -#include <asm/gpio.h> - #define DRV_NAME "pata-rb532-cf" #define DRV_VERSION "0.1.0" #define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash" diff --git a/drivers/bus/mips_cdmm.c b/drivers/bus/mips_cdmm.c index ab3bde16ecb4..1c543effe062 100644 --- a/drivers/bus/mips_cdmm.c +++ b/drivers/bus/mips_cdmm.c @@ -332,6 +332,18 @@ static phys_addr_t mips_cdmm_cur_base(void) } /** + * mips_cdmm_phys_base() - Choose a physical base address for CDMM region. + * + * Picking a suitable physical address at which to map the CDMM region is + * platform specific, so this weak function can be overridden by platform + * code to pick a suitable value if none is configured by the bootloader. + */ +phys_addr_t __weak mips_cdmm_phys_base(void) +{ + return 0; +} + +/** * mips_cdmm_setup() - Ensure the CDMM bus is initialised and usable. * @bus: Pointer to bus information for current CPU. * IS_ERR(bus) is checked, so no need for caller to check. @@ -368,7 +380,7 @@ static int mips_cdmm_setup(struct mips_cdmm_bus *bus) if (!bus->phys) bus->phys = mips_cdmm_cur_base(); /* Otherwise, ask platform code for suggestions */ - if (!bus->phys && mips_cdmm_phys_base) + if (!bus->phys) bus->phys = mips_cdmm_phys_base(); /* Otherwise, copy what other CPUs have done */ if (!bus->phys) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index c03f04d82c6a..552c9b134cc5 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -111,6 +111,10 @@ config CLKSRC_LPC32XX select CLKSRC_MMIO select CLKSRC_OF +config CLKSRC_PISTACHIO + bool + select CLKSRC_OF + config CLKSRC_STM32 bool "Clocksource for STM32 SoCs" if !ARCH_STM32 depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index f228354961ca..066337e24737 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o obj-$(CONFIG_MTK_TIMER) += mtk_timer.o +obj-$(CONFIG_CLKSRC_PISTACHIO) += time-pistachio.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index c3810b61c815..02a1945e5093 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -72,6 +72,13 @@ static void gic_clockevent_cpu_exit(struct clock_event_device *cd) disable_percpu_irq(gic_timer_irq); } +static void gic_update_frequency(void *data) +{ + unsigned long rate = (unsigned long)data; + + clockevents_update_freq(this_cpu_ptr(&gic_clockevent_device), rate); +} + static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, void *data) { @@ -87,18 +94,40 @@ static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, return NOTIFY_OK; } +static int gic_clk_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct clk_notifier_data *cnd = data; + + if (action == POST_RATE_CHANGE) + on_each_cpu(gic_update_frequency, (void *)cnd->new_rate, 1); + + return NOTIFY_OK; +} + + static struct notifier_block gic_cpu_nb = { .notifier_call = gic_cpu_notifier, }; +static struct notifier_block gic_clk_nb = { + .notifier_call = gic_clk_notifier, +}; + static int gic_clockevent_init(void) { + int ret; + if (!cpu_has_counter || !gic_frequency) return -ENXIO; - setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); + ret = setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); + if (ret < 0) + return ret; - register_cpu_notifier(&gic_cpu_nb); + ret = register_cpu_notifier(&gic_cpu_nb); + if (ret < 0) + pr_warn("GIC: Unable to register CPU notifier\n"); gic_clockevent_cpu_init(this_cpu_ptr(&gic_clockevent_device)); @@ -118,18 +147,17 @@ static struct clocksource gic_clocksource = { static void __init __gic_clocksource_init(void) { + int ret; + /* Set clocksource mask. */ gic_clocksource.mask = CLOCKSOURCE_MASK(gic_get_count_width()); /* Calculate a somewhat reasonable rating value. */ gic_clocksource.rating = 200 + gic_frequency / 10000000; - clocksource_register_hz(&gic_clocksource, gic_frequency); - - gic_clockevent_init(); - - /* And finally start the counter */ - gic_start_count(); + ret = clocksource_register_hz(&gic_clocksource, gic_frequency); + if (ret < 0) + pr_warn("GIC: Unable to register clocksource\n"); } void __init gic_clocksource_init(unsigned int frequency) @@ -139,11 +167,16 @@ void __init gic_clocksource_init(unsigned int frequency) GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE); __gic_clocksource_init(); + gic_clockevent_init(); + + /* And finally start the counter */ + gic_start_count(); } static void __init gic_clocksource_of_init(struct device_node *node) { struct clk *clk; + int ret; if (WARN_ON(!gic_present || !node->parent || !of_device_is_compatible(node->parent, "mti,gic"))) @@ -151,8 +184,13 @@ static void __init gic_clocksource_of_init(struct device_node *node) clk = of_clk_get(node, 0); if (!IS_ERR(clk)) { + if (clk_prepare_enable(clk) < 0) { + pr_err("GIC failed to enable clock\n"); + clk_put(clk); + return; + } + gic_frequency = clk_get_rate(clk); - clk_put(clk); } else if (of_property_read_u32(node, "clock-frequency", &gic_frequency)) { pr_err("GIC frequency not specified.\n"); @@ -165,6 +203,15 @@ static void __init gic_clocksource_of_init(struct device_node *node) } __gic_clocksource_init(); + + ret = gic_clockevent_init(); + if (!ret && !IS_ERR(clk)) { + if (clk_notifier_register(clk, &gic_clk_nb) < 0) + pr_warn("GIC: Unable to register clock notifier\n"); + } + + /* And finally start the counter */ + gic_start_count(); } CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", gic_clocksource_of_init); diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/time-pistachio.c new file mode 100644 index 000000000000..18d4266c2986 --- /dev/null +++ b/drivers/clocksource/time-pistachio.c @@ -0,0 +1,217 @@ +/* + * Pistachio clocksource based on general-purpose timers + * + * Copyright (C) 2015 Imagination Technologies + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/clk.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/mfd/syscon.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/sched_clock.h> +#include <linux/time.h> + +/* Top level reg */ +#define CR_TIMER_CTRL_CFG 0x00 +#define TIMER_ME_GLOBAL BIT(0) +#define CR_TIMER_REV 0x10 + +/* Timer specific registers */ +#define TIMER_CFG 0x20 +#define TIMER_ME_LOCAL BIT(0) +#define TIMER_RELOAD_VALUE 0x24 +#define TIMER_CURRENT_VALUE 0x28 +#define TIMER_CURRENT_OVERFLOW_VALUE 0x2C +#define TIMER_IRQ_STATUS 0x30 +#define TIMER_IRQ_CLEAR 0x34 +#define TIMER_IRQ_MASK 0x38 + +#define PERIP_TIMER_CONTROL 0x90 + +/* Timer specific configuration Values */ +#define RELOAD_VALUE 0xffffffff + +struct pistachio_clocksource { + void __iomem *base; + raw_spinlock_t lock; + struct clocksource cs; +}; + +static struct pistachio_clocksource pcs_gpt; + +#define to_pistachio_clocksource(cs) \ + container_of(cs, struct pistachio_clocksource, cs) + +static inline u32 gpt_readl(void __iomem *base, u32 offset, u32 gpt_id) +{ + return readl(base + 0x20 * gpt_id + offset); +} + +static inline void gpt_writel(void __iomem *base, u32 value, u32 offset, + u32 gpt_id) +{ + writel(value, base + 0x20 * gpt_id + offset); +} + +static cycle_t pistachio_clocksource_read_cycles(struct clocksource *cs) +{ + struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); + u32 counter, overflw; + unsigned long flags; + + /* + * The counter value is only refreshed after the overflow value is read. + * And they must be read in strict order, hence raw spin lock added. + */ + + raw_spin_lock_irqsave(&pcs->lock, flags); + overflw = gpt_readl(pcs->base, TIMER_CURRENT_OVERFLOW_VALUE, 0); + counter = gpt_readl(pcs->base, TIMER_CURRENT_VALUE, 0); + raw_spin_unlock_irqrestore(&pcs->lock, flags); + + return ~(cycle_t)counter; +} + +static u64 notrace pistachio_read_sched_clock(void) +{ + return pistachio_clocksource_read_cycles(&pcs_gpt.cs); +} + +static void pistachio_clksrc_set_mode(struct clocksource *cs, int timeridx, + int enable) +{ + struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); + u32 val; + + val = gpt_readl(pcs->base, TIMER_CFG, timeridx); + if (enable) + val |= TIMER_ME_LOCAL; + else + val &= ~TIMER_ME_LOCAL; + + gpt_writel(pcs->base, val, TIMER_CFG, timeridx); +} + +static void pistachio_clksrc_enable(struct clocksource *cs, int timeridx) +{ + struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); + + /* Disable GPT local before loading reload value */ + pistachio_clksrc_set_mode(cs, timeridx, false); + gpt_writel(pcs->base, RELOAD_VALUE, TIMER_RELOAD_VALUE, timeridx); + pistachio_clksrc_set_mode(cs, timeridx, true); +} + +static void pistachio_clksrc_disable(struct clocksource *cs, int timeridx) +{ + /* Disable GPT local */ + pistachio_clksrc_set_mode(cs, timeridx, false); +} + +static int pistachio_clocksource_enable(struct clocksource *cs) +{ + pistachio_clksrc_enable(cs, 0); + return 0; +} + +static void pistachio_clocksource_disable(struct clocksource *cs) +{ + pistachio_clksrc_disable(cs, 0); +} + +/* Desirable clock source for pistachio platform */ +static struct pistachio_clocksource pcs_gpt = { + .cs = { + .name = "gptimer", + .rating = 300, + .enable = pistachio_clocksource_enable, + .disable = pistachio_clocksource_disable, + .read = pistachio_clocksource_read_cycles, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS | + CLOCK_SOURCE_SUSPEND_NONSTOP, + }, +}; + +static void __init pistachio_clksrc_of_init(struct device_node *node) +{ + struct clk *sys_clk, *fast_clk; + struct regmap *periph_regs; + unsigned long rate; + int ret; + + pcs_gpt.base = of_iomap(node, 0); + if (!pcs_gpt.base) { + pr_err("cannot iomap\n"); + return; + } + + periph_regs = syscon_regmap_lookup_by_phandle(node, "img,cr-periph"); + if (IS_ERR(periph_regs)) { + pr_err("cannot get peripheral regmap (%lu)\n", + PTR_ERR(periph_regs)); + return; + } + + /* Switch to using the fast counter clock */ + ret = regmap_update_bits(periph_regs, PERIP_TIMER_CONTROL, + 0xf, 0x0); + if (ret) + return; + + sys_clk = of_clk_get_by_name(node, "sys"); + if (IS_ERR(sys_clk)) { + pr_err("clock get failed (%lu)\n", PTR_ERR(sys_clk)); + return; + } + + fast_clk = of_clk_get_by_name(node, "fast"); + if (IS_ERR(fast_clk)) { + pr_err("clock get failed (%lu)\n", PTR_ERR(fast_clk)); + return; + } + + ret = clk_prepare_enable(sys_clk); + if (ret < 0) { + pr_err("failed to enable clock (%d)\n", ret); + return; + } + + ret = clk_prepare_enable(fast_clk); + if (ret < 0) { + pr_err("failed to enable clock (%d)\n", ret); + clk_disable_unprepare(sys_clk); + return; + } + + rate = clk_get_rate(fast_clk); + + /* Disable irq's for clocksource usage */ + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 0); + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 1); + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 2); + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 3); + + /* Enable timer block */ + writel(TIMER_ME_GLOBAL, pcs_gpt.base); + + raw_spin_lock_init(&pcs_gpt.lock); + sched_clock_register(pistachio_read_sched_clock, 32, rate); + clocksource_register_hz(&pcs_gpt.cs, rate); +} +CLOCKSOURCE_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer", + pistachio_clksrc_of_init); diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index f82cd678ce08..2b64f6177e33 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o +obj-$(CONFIG_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c new file mode 100644 index 000000000000..03b995304ad6 --- /dev/null +++ b/drivers/gpio/gpio-ath79.c @@ -0,0 +1,204 @@ +/* + * Atheros AR71XX/AR724X/AR913X GPIO API support + * + * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> + * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * + * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/gpio.h> +#include <linux/platform_data/gpio-ath79.h> +#include <linux/of_device.h> + +#include <asm/mach-ath79/ar71xx_regs.h> + +static void __iomem *ath79_gpio_base; +static u32 ath79_gpio_count; +static DEFINE_SPINLOCK(ath79_gpio_lock); + +static void __ath79_gpio_set_value(unsigned gpio, int value) +{ + void __iomem *base = ath79_gpio_base; + + if (value) + __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_SET); + else + __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_CLEAR); +} + +static int __ath79_gpio_get_value(unsigned gpio) +{ + return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1; +} + +static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset) +{ + return __ath79_gpio_get_value(offset); +} + +static void ath79_gpio_set_value(struct gpio_chip *chip, + unsigned offset, int value) +{ + __ath79_gpio_set_value(offset, value); +} + +static int ath79_gpio_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + void __iomem *base = ath79_gpio_base; + unsigned long flags; + + spin_lock_irqsave(&ath79_gpio_lock, flags); + + __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset), + base + AR71XX_GPIO_REG_OE); + + spin_unlock_irqrestore(&ath79_gpio_lock, flags); + + return 0; +} + +static int ath79_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + void __iomem *base = ath79_gpio_base; + unsigned long flags; + + spin_lock_irqsave(&ath79_gpio_lock, flags); + + if (value) + __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET); + else + __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR); + + __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset), + base + AR71XX_GPIO_REG_OE); + + spin_unlock_irqrestore(&ath79_gpio_lock, flags); + + return 0; +} + +static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + void __iomem *base = ath79_gpio_base; + unsigned long flags; + + spin_lock_irqsave(&ath79_gpio_lock, flags); + + __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset), + base + AR71XX_GPIO_REG_OE); + + spin_unlock_irqrestore(&ath79_gpio_lock, flags); + + return 0; +} + +static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + void __iomem *base = ath79_gpio_base; + unsigned long flags; + + spin_lock_irqsave(&ath79_gpio_lock, flags); + + if (value) + __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET); + else + __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR); + + __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset), + base + AR71XX_GPIO_REG_OE); + + spin_unlock_irqrestore(&ath79_gpio_lock, flags); + + return 0; +} + +static struct gpio_chip ath79_gpio_chip = { + .label = "ath79", + .get = ath79_gpio_get_value, + .set = ath79_gpio_set_value, + .direction_input = ath79_gpio_direction_input, + .direction_output = ath79_gpio_direction_output, + .base = 0, +}; + +static const struct of_device_id ath79_gpio_of_match[] = { + { .compatible = "qca,ar7100-gpio" }, + { .compatible = "qca,ar9340-gpio" }, + {}, +}; + +static int ath79_gpio_probe(struct platform_device *pdev) +{ + struct ath79_gpio_platform_data *pdata = pdev->dev.platform_data; + struct device_node *np = pdev->dev.of_node; + struct resource *res; + bool oe_inverted; + int err; + + if (np) { + err = of_property_read_u32(np, "ngpios", &ath79_gpio_count); + if (err) { + dev_err(&pdev->dev, "ngpios property is not valid\n"); + return err; + } + if (ath79_gpio_count >= 32) { + dev_err(&pdev->dev, "ngpios must be less than 32\n"); + return -EINVAL; + } + oe_inverted = of_device_is_compatible(np, "qca,ar9340-gpio"); + } else if (pdata) { + ath79_gpio_count = pdata->ngpios; + oe_inverted = pdata->oe_inverted; + } else { + dev_err(&pdev->dev, "No DT node or platform data found\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ath79_gpio_base = devm_ioremap_nocache( + &pdev->dev, res->start, resource_size(res)); + if (!ath79_gpio_base) + return -ENOMEM; + + ath79_gpio_chip.dev = &pdev->dev; + ath79_gpio_chip.ngpio = ath79_gpio_count; + if (oe_inverted) { + ath79_gpio_chip.direction_input = ar934x_gpio_direction_input; + ath79_gpio_chip.direction_output = ar934x_gpio_direction_output; + } + + err = gpiochip_add(&ath79_gpio_chip); + if (err) { + dev_err(&pdev->dev, + "cannot add AR71xx GPIO chip, error=%d", err); + return err; + } + + return 0; +} + +static struct platform_driver ath79_gpio_driver = { + .driver = { + .name = "ath79-gpio", + .of_match_table = ath79_gpio_of_match, + }, + .probe = ath79_gpio_probe, +}; + +module_platform_driver(ath79_gpio_driver); diff --git a/drivers/input/misc/rb532_button.c b/drivers/input/misc/rb532_button.c index e956e81cd4e6..62c5814c796b 100644 --- a/drivers/input/misc/rb532_button.c +++ b/drivers/input/misc/rb532_button.c @@ -7,6 +7,7 @@ #include <linux/input-polldev.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/gpio.h> #include <asm/mach-rc32434/gpio.h> #include <asm/mach-rc32434/rb.h> diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index dae591457883..1764bcf8ee6b 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -41,20 +41,46 @@ static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; static void __gic_irq_dispatch(void); -static inline unsigned int gic_read(unsigned int reg) +static inline u32 gic_read32(unsigned int reg) { return __raw_readl(gic_base + reg); } -static inline void gic_write(unsigned int reg, unsigned int val) +static inline u64 gic_read64(unsigned int reg) { - __raw_writel(val, gic_base + reg); + return __raw_readq(gic_base + reg); } -static inline void gic_update_bits(unsigned int reg, unsigned int mask, - unsigned int val) +static inline unsigned long gic_read(unsigned int reg) { - unsigned int regval; + if (!mips_cm_is64) + return gic_read32(reg); + else + return gic_read64(reg); +} + +static inline void gic_write32(unsigned int reg, u32 val) +{ + return __raw_writel(val, gic_base + reg); +} + +static inline void gic_write64(unsigned int reg, u64 val) +{ + return __raw_writeq(val, gic_base + reg); +} + +static inline void gic_write(unsigned int reg, unsigned long val) +{ + if (!mips_cm_is64) + return gic_write32(reg, (u32)val); + else + return gic_write64(reg, (u64)val); +} + +static inline void gic_update_bits(unsigned int reg, unsigned long mask, + unsigned long val) +{ + unsigned long regval; regval = gic_read(reg); regval &= ~mask; @@ -65,40 +91,40 @@ static inline void gic_update_bits(unsigned int reg, unsigned int mask, static inline void gic_reset_mask(unsigned int intr) { gic_write(GIC_REG(SHARED, GIC_SH_RMASK) + GIC_INTR_OFS(intr), - 1 << GIC_INTR_BIT(intr)); + 1ul << GIC_INTR_BIT(intr)); } static inline void gic_set_mask(unsigned int intr) { gic_write(GIC_REG(SHARED, GIC_SH_SMASK) + GIC_INTR_OFS(intr), - 1 << GIC_INTR_BIT(intr)); + 1ul << GIC_INTR_BIT(intr)); } static inline void gic_set_polarity(unsigned int intr, unsigned int pol) { gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_POLARITY) + - GIC_INTR_OFS(intr), 1 << GIC_INTR_BIT(intr), - pol << GIC_INTR_BIT(intr)); + GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr), + (unsigned long)pol << GIC_INTR_BIT(intr)); } static inline void gic_set_trigger(unsigned int intr, unsigned int trig) { gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_TRIGGER) + - GIC_INTR_OFS(intr), 1 << GIC_INTR_BIT(intr), - trig << GIC_INTR_BIT(intr)); + GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr), + (unsigned long)trig << GIC_INTR_BIT(intr)); } static inline void gic_set_dual_edge(unsigned int intr, unsigned int dual) { gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_DUAL) + GIC_INTR_OFS(intr), - 1 << GIC_INTR_BIT(intr), - dual << GIC_INTR_BIT(intr)); + 1ul << GIC_INTR_BIT(intr), + (unsigned long)dual << GIC_INTR_BIT(intr)); } static inline void gic_map_to_pin(unsigned int intr, unsigned int pin) { - gic_write(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) + - GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin); + gic_write32(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) + + GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin); } static inline void gic_map_to_vpe(unsigned int intr, unsigned int vpe) @@ -113,10 +139,13 @@ cycle_t gic_read_count(void) { unsigned int hi, hi2, lo; + if (mips_cm_is64) + return (cycle_t)gic_read(GIC_REG(SHARED, GIC_SH_COUNTER)); + do { - hi = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); - lo = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_31_00)); - hi2 = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); + hi = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); + lo = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_31_00)); + hi2 = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); } while (hi2 != hi); return (((cycle_t) hi) << 32) + lo; @@ -135,10 +164,14 @@ unsigned int gic_get_count_width(void) void gic_write_compare(cycle_t cnt) { - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), - (int)(cnt >> 32)); - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), - (int)(cnt & 0xffffffff)); + if (mips_cm_is64) { + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE), cnt); + } else { + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), + (int)(cnt >> 32)); + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), + (int)(cnt & 0xffffffff)); + } } void gic_write_cpu_compare(cycle_t cnt, int cpu) @@ -148,10 +181,15 @@ void gic_write_cpu_compare(cycle_t cnt, int cpu) local_irq_save(flags); gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), - (int)(cnt >> 32)); - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), - (int)(cnt & 0xffffffff)); + + if (mips_cm_is64) { + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE), cnt); + } else { + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), + (int)(cnt >> 32)); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), + (int)(cnt & 0xffffffff)); + } local_irq_restore(flags); } @@ -160,8 +198,11 @@ cycle_t gic_read_compare(void) { unsigned int hi, lo; - hi = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI)); - lo = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO)); + if (mips_cm_is64) + return (cycle_t)gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE)); + + hi = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI)); + lo = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO)); return (((cycle_t) hi) << 32) + lo; } @@ -196,7 +237,7 @@ static bool gic_local_irq_is_routable(int intr) if (cpu_has_veic) return true; - vpe_ctl = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_CTL)); + vpe_ctl = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_CTL)); switch (intr) { case GIC_LOCAL_INT_TIMER: return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK; @@ -262,7 +303,7 @@ int gic_get_c0_fdc_int(void) static void gic_handle_shared_int(bool chained) { - unsigned int i, intr, virq; + unsigned int i, intr, virq, gic_reg_step = mips_cm_is64 ? 8 : 4; unsigned long *pcpu_mask; unsigned long pending_reg, intrmask_reg; DECLARE_BITMAP(pending, GIC_MAX_INTRS); @@ -277,8 +318,8 @@ static void gic_handle_shared_int(bool chained) for (i = 0; i < BITS_TO_LONGS(gic_shared_intrs); i++) { pending[i] = gic_read(pending_reg); intrmask[i] = gic_read(intrmask_reg); - pending_reg += 0x4; - intrmask_reg += 0x4; + pending_reg += gic_reg_step; + intrmask_reg += gic_reg_step; } bitmap_and(pending, pending, intrmask, gic_shared_intrs); @@ -425,8 +466,8 @@ static void gic_handle_local_int(bool chained) unsigned long pending, masked; unsigned int intr, virq; - pending = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_PEND)); - masked = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_MASK)); + pending = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_PEND)); + masked = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_MASK)); bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS); @@ -449,14 +490,14 @@ static void gic_mask_local_irq(struct irq_data *d) { int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr); + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr); } static void gic_unmask_local_irq(struct irq_data *d) { int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr); + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr); } static struct irq_chip gic_local_irq_controller = { @@ -474,7 +515,7 @@ static void gic_mask_local_irq_all_vpes(struct irq_data *d) spin_lock_irqsave(&gic_lock, flags); for (i = 0; i < gic_vpes; i++) { gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr); } spin_unlock_irqrestore(&gic_lock, flags); } @@ -488,7 +529,7 @@ static void gic_unmask_local_irq_all_vpes(struct irq_data *d) spin_lock_irqsave(&gic_lock, flags); for (i = 0; i < gic_vpes; i++) { gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr); } spin_unlock_irqrestore(&gic_lock, flags); } @@ -608,7 +649,7 @@ static void __init gic_basic_init(void) for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) { if (!gic_local_irq_is_routable(j)) continue; - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j); } } } @@ -653,27 +694,32 @@ static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq, switch (intr) { case GIC_LOCAL_INT_WD: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val); break; case GIC_LOCAL_INT_COMPARE: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), + val); break; case GIC_LOCAL_INT_TIMER: /* CONFIG_MIPS_CMP workaround (see __gic_init) */ val = GIC_MAP_TO_PIN_MSK | timer_cpu_pin; - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), + val); break; case GIC_LOCAL_INT_PERFCTR: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), + val); break; case GIC_LOCAL_INT_SWINT0: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP), + val); break; case GIC_LOCAL_INT_SWINT1: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP), + val); break; case GIC_LOCAL_INT_FDC: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val); break; default: pr_err("Invalid local IRQ %d\n", intr); @@ -778,7 +824,7 @@ static void __init __gic_init(unsigned long gic_base_addr, */ if (IS_ENABLED(CONFIG_MIPS_CMP) && gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) { - timer_cpu_pin = gic_read(GIC_REG(VPE_LOCAL, + timer_cpu_pin = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_TIMER_MAP)) & GIC_MAP_MSK; irq_set_chained_handler(MIPS_CPU_IRQ_BASE + diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index dd9430043536..cba3d9fcb465 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -41,6 +41,8 @@ #include <linux/gpio.h> #include <linux/atomic.h> +#include <asm/mach-ar7/ar7.h> + MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>"); MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index 22853d33da05..d1a33a927f6d 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -70,7 +70,14 @@ static irqreturn_t cvm_oct_do_interrupt(int cpl, void *dev_id) */ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) { - if ((work->word2.snoip.err_code == 10) && (work->len <= 64)) { + int port; + + if (octeon_has_feature(OCTEON_FEATURE_PKND)) + port = work->word0.pip.cn68xx.pknd; + else + port = work->word1.cn38xx.ipprt; + + if ((work->word2.snoip.err_code == 10) && (work->word1.len <= 64)) { /* * Ignore length errors on min size packets. Some * equipment incorrectly pads packets to 64+4FCS @@ -87,8 +94,8 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) * packet to determine if we can remove a non spec * preamble and generate a correct packet. */ - int interface = cvmx_helper_get_interface_num(work->ipprt); - int index = cvmx_helper_get_interface_index_num(work->ipprt); + int interface = cvmx_helper_get_interface_num(port); + int index = cvmx_helper_get_interface_index_num(port); union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl; gmxx_rxx_frm_ctl.u64 = @@ -99,7 +106,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) cvmx_phys_to_ptr(work->packet_ptr.s.addr); int i = 0; - while (i < work->len - 1) { + while (i < work->word1.len - 1) { if (*ptr != 0x55) break; ptr++; @@ -109,18 +116,18 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) if (*ptr == 0xd5) { /* printk_ratelimited("Port %d received 0xd5 preamble\n", - work->ipprt); + port); */ work->packet_ptr.s.addr += i + 1; - work->len -= i + 5; + work->word1.len -= i + 5; } else if ((*ptr & 0xf) == 0xd) { /* printk_ratelimited("Port %d received 0x?d preamble\n", - work->ipprt); + port); */ work->packet_ptr.s.addr += i; - work->len -= i + 4; - for (i = 0; i < work->len; i++) { + work->word1.len -= i + 4; + for (i = 0; i < work->word1.len; i++) { *ptr = ((*ptr & 0xf0) >> 4) | ((*(ptr + 1) & 0xf) << 4); @@ -128,7 +135,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) } } else { printk_ratelimited("Port %d unknown preamble, packet dropped\n", - work->ipprt); + port); /* cvmx_helper_dump_packet(work); */ @@ -138,7 +145,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) } } else { printk_ratelimited("Port %d receive error code %d, packet dropped\n", - work->ipprt, work->word2.snoip.err_code); + port, work->word2.snoip.err_code); cvm_oct_free_work(work); return 1; } @@ -172,9 +179,16 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) } /* Only allow work for our group (and preserve priorities) */ - old_group_mask = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(coreid)); - cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), - (old_group_mask & ~0xFFFFull) | 1 << pow_receive_group); + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + old_group_mask = cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); + cvmx_write_csr(CVMX_SSO_PPX_GRP_MSK(coreid), + 1ull << pow_receive_group); + cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); /* Flush */ + } else { + old_group_mask = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(coreid)); + cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), + (old_group_mask & ~0xFFFFull) | 1 << pow_receive_group); + } if (USE_ASYNC_IOBDMA) { cvmx_pow_work_request_async(CVMX_SCR_SCRATCH, CVMX_POW_NO_WAIT); @@ -186,6 +200,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) struct sk_buff **pskb = NULL; int skb_in_hw; cvmx_wqe_t *work; + int port; if (USE_ASYNC_IOBDMA && did_work_request) work = cvmx_pow_work_response_async(CVMX_SCR_SCRATCH); @@ -195,12 +210,19 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) prefetch(work); did_work_request = 0; if (work == NULL) { - union cvmx_pow_wq_int wq_int; + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + cvmx_write_csr(CVMX_SSO_WQ_IQ_DIS, + 1ull << pow_receive_group); + cvmx_write_csr(CVMX_SSO_WQ_INT, + 1ull << pow_receive_group); + } else { + union cvmx_pow_wq_int wq_int; - wq_int.u64 = 0; - wq_int.s.iq_dis = 1 << pow_receive_group; - wq_int.s.wq_int = 1 << pow_receive_group; - cvmx_write_csr(CVMX_POW_WQ_INT, wq_int.u64); + wq_int.u64 = 0; + wq_int.s.iq_dis = 1 << pow_receive_group; + wq_int.s.wq_int = 1 << pow_receive_group; + cvmx_write_csr(CVMX_POW_WQ_INT, wq_int.u64); + } break; } pskb = (struct sk_buff **)(cvm_oct_get_buffer_ptr(work->packet_ptr) - @@ -220,7 +242,13 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) prefetch(&skb->head); prefetch(&skb->len); } - prefetch(cvm_oct_device[work->ipprt]); + + if (octeon_has_feature(OCTEON_FEATURE_PKND)) + port = work->word0.pip.cn68xx.pknd; + else + port = work->word1.cn38xx.ipprt; + + prefetch(cvm_oct_device[port]); /* Immediately throw away all packets with receive errors */ if (unlikely(work->word2.snoip.rcv_error)) { @@ -237,7 +265,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) skb->data = skb->head + work->packet_ptr.s.addr - cvmx_ptr_to_phys(skb->head); prefetch(skb->data); - skb->len = work->len; + skb->len = work->word1.len; skb_set_tail_pointer(skb, skb->len); packet_not_copied = 1; } else { @@ -245,7 +273,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) * We have to copy the packet. First allocate * an skbuff for it. */ - skb = dev_alloc_skb(work->len); + skb = dev_alloc_skb(work->word1.len); if (!skb) { cvm_oct_free_work(work); continue; @@ -268,13 +296,14 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) else ptr += 6; } - memcpy(skb_put(skb, work->len), ptr, work->len); + memcpy(skb_put(skb, work->word1.len), ptr, + work->word1.len); /* No packet buffers to free */ } else { int segments = work->word2.s.bufs; union cvmx_buf_ptr segment_ptr = work->packet_ptr; - int len = work->len; + int len = work->word1.len; while (segments--) { union cvmx_buf_ptr next_ptr = @@ -310,10 +339,9 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) } packet_not_copied = 0; } - - if (likely((work->ipprt < TOTAL_NUMBER_OF_PORTS) && - cvm_oct_device[work->ipprt])) { - struct net_device *dev = cvm_oct_device[work->ipprt]; + if (likely((port < TOTAL_NUMBER_OF_PORTS) && + cvm_oct_device[port])) { + struct net_device *dev = cvm_oct_device[port]; struct octeon_ethernet *priv = netdev_priv(dev); /* @@ -333,7 +361,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) skb->ip_summed = CHECKSUM_UNNECESSARY; /* Increment RX stats for virtual ports */ - if (work->ipprt >= CVMX_PIP_NUM_INPUT_PORTS) { + if (port >= CVMX_PIP_NUM_INPUT_PORTS) { #ifdef CONFIG_64BIT atomic64_add(1, (atomic64_t *)&priv->stats.rx_packets); @@ -368,7 +396,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) * doesn't exist. */ printk_ratelimited("Port %d not controlled by Linux, packet dropped\n", - work->ipprt); + port); dev_kfree_skb_irq(skb); } /* @@ -390,7 +418,13 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) } } /* Restore the original POW group mask */ - cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), old_group_mask); + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + cvmx_write_csr(CVMX_SSO_PPX_GRP_MSK(coreid), old_group_mask); + cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); /* Flush */ + } else { + cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), old_group_mask); + } + if (USE_ASYNC_IOBDMA) { /* Restore the scratch area */ cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch); @@ -422,8 +456,6 @@ void cvm_oct_rx_initialize(void) { int i; struct net_device *dev_for_napi = NULL; - union cvmx_pow_wq_int_thrx int_thr; - union cvmx_pow_wq_int_pc int_pc; for (i = 0; i < TOTAL_NUMBER_OF_PORTS; i++) { if (cvm_oct_device[i]) { @@ -449,15 +481,34 @@ void cvm_oct_rx_initialize(void) disable_irq_nosync(OCTEON_IRQ_WORKQ0 + pow_receive_group); - int_thr.u64 = 0; - int_thr.s.tc_en = 1; - int_thr.s.tc_thr = 1; /* Enable POW interrupt when our port has at least one packet */ - cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), int_thr.u64); - - int_pc.u64 = 0; - int_pc.s.pc_thr = 5; - cvmx_write_csr(CVMX_POW_WQ_INT_PC, int_pc.u64); + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + union cvmx_sso_wq_int_thrx int_thr; + union cvmx_pow_wq_int_pc int_pc; + + int_thr.u64 = 0; + int_thr.s.tc_en = 1; + int_thr.s.tc_thr = 1; + cvmx_write_csr(CVMX_SSO_WQ_INT_THRX(pow_receive_group), + int_thr.u64); + + int_pc.u64 = 0; + int_pc.s.pc_thr = 5; + cvmx_write_csr(CVMX_SSO_WQ_INT_PC, int_pc.u64); + } else { + union cvmx_pow_wq_int_thrx int_thr; + union cvmx_pow_wq_int_pc int_pc; + + int_thr.u64 = 0; + int_thr.s.tc_en = 1; + int_thr.s.tc_thr = 1; + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), + int_thr.u64); + + int_pc.u64 = 0; + int_pc.s.pc_thr = 5; + cvmx_write_csr(CVMX_POW_WQ_INT_PC, int_pc.u64); + } /* Schedule NAPI now. This will indirectly enable the interrupt. */ napi_schedule(&cvm_oct_napi); diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index e2df041ca82d..9e2116f4c915 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -591,13 +591,14 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) * Fill in some of the work queue fields. We may need to add * more if the software at the other end needs them. */ - work->hw_chksum = skb->csum; - work->len = skb->len; - work->ipprt = priv->port; - work->qos = priv->port & 0x7; - work->grp = pow_send_group; - work->tag_type = CVMX_HELPER_INPUT_TAG_TYPE; - work->tag = pow_send_group; /* FIXME */ + if (!OCTEON_IS_MODEL(OCTEON_CN68XX)) + work->word0.pip.cn38xx.hw_chksum = skb->csum; + work->word1.len = skb->len; + cvmx_wqe_set_port(work, priv->port); + cvmx_wqe_set_qos(work, priv->port & 0x7); + cvmx_wqe_set_grp(work, pow_send_group); + work->word1.tag_type = CVMX_HELPER_INPUT_TAG_TYPE; + work->word1.tag = pow_send_group; /* FIXME */ /* Default to zero. Sets of zero later are commented out */ work->word2.u64 = 0; work->word2.s.bufs = 1; @@ -677,8 +678,8 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) } /* Submit the packet to the POW */ - cvmx_pow_work_submit(work, work->tag, work->tag_type, work->qos, - work->grp); + cvmx_pow_work_submit(work, work->word1.tag, work->word1.tag_type, + cvmx_wqe_get_qos(work), cvmx_wqe_get_grp(work)); priv->stats.tx_packets++; priv->stats.tx_bytes += skb->len; dev_consume_skb_any(skb); diff --git a/drivers/staging/octeon/ethernet-util.h b/drivers/staging/octeon/ethernet-util.h index 1ba789a7741b..45f024bc5e33 100644 --- a/drivers/staging/octeon/ethernet-util.h +++ b/drivers/staging/octeon/ethernet-util.h @@ -8,6 +8,10 @@ * published by the Free Software Foundation. */ +#include <asm/octeon/cvmx-pip.h> +#include <asm/octeon/cvmx-helper.h> +#include <asm/octeon/cvmx-helper-util.h> + /** * cvm_oct_get_buffer_ptr - convert packet data address to pointer * @packet_ptr: Packet data hardware address @@ -28,14 +32,12 @@ static inline void *cvm_oct_get_buffer_ptr(union cvmx_buf_ptr packet_ptr) */ static inline int INTERFACE(int ipd_port) { - if (ipd_port < 32) /* Interface 0 or 1 for RGMII,GMII,SPI, etc */ - return ipd_port >> 4; - else if (ipd_port < 36) /* Interface 2 for NPI */ - return 2; - else if (ipd_port < 40) /* Interface 3 for loopback */ - return 3; - else if (ipd_port == 40) /* Non existent interface for POW0 */ - return 4; + int interface = cvmx_helper_get_interface_num(ipd_port); + + if (interface >= 0) + return interface; + else if (ipd_port == CVMX_PIP_NUM_INPUT_PORTS) + return 10; panic("Illegal ipd_port %d passed to INTERFACE\n", ipd_port); } @@ -47,7 +49,5 @@ static inline int INTERFACE(int ipd_port) */ static inline int INDEX(int ipd_port) { - if (ipd_port < 32) - return ipd_port & 15; - return ipd_port & 3; + return cvmx_helper_get_interface_index_num(ipd_port); } diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index 0718b35f7335..7274fda0b77b 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -152,7 +152,7 @@ static void cvm_oct_configure_common_hw(void) num_packet_buffers); if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, - CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128); + CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 1024); #ifdef __LITTLE_ENDIAN { @@ -860,7 +860,10 @@ static int cvm_oct_remove(struct platform_device *pdev) int port; /* Disable POW interrupt */ - cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0); + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + cvmx_write_csr(CVMX_SSO_WQ_INT_THRX(pow_receive_group), 0); + else + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0); cvmx_ipd_disable(); diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index 358323c83b4f..a8c8cfd52a23 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -879,6 +879,11 @@ static const struct tty_operations mips_ejtag_fdc_tty_ops = { .chars_in_buffer = mips_ejtag_fdc_tty_chars_in_buffer, }; +int __weak get_c0_fdc_int(void) +{ + return -1; +} + static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) { int ret, nport; @@ -967,9 +972,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) wake_up_process(priv->thread); /* Look for an FDC IRQ */ - priv->irq = -1; - if (get_c0_fdc_int) - priv->irq = get_c0_fdc_int(); + priv->irq = get_c0_fdc_int(); /* Try requesting the IRQ */ if (priv->irq >= 0) { |