mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 20:51:44 +00:00
Merge master.kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6: sh: Fix stacktrace simplification fallout. sh: SH7760 DMABRG support. sh: clockevent/clocksource/hrtimers/nohz TMU support. sh: Truncate MAX_ACTIVE_REGIONS for the common case. rtc: rtc-sh: Fix rtc_dev pointer for rtc_update_irq(). sh: Convert to common die chain. sh: Wire up utimensat syscall. sh: landisk mv_nr_irqs definition. sh: Fixup ndelay() xloops calculation for alternate HZ. sh: Add 32-bit opcode feature CPU flag. sh: Fix PC adjustments for varying opcode length. sh: Support for SH-2A 32-bit opcodes. sh: Kill off redundant __div64_32 symbol export. sh: Share exception vector table for SH-3/4. sh: Always define TRAPA_BUG_OPCODE. sh: __GFP_REPEAT for pte allocations, too. rtc: rtc-sh: Fix up dev_dbg() warnings. sh: generic quicklist support.
This commit is contained in:
commit
d84c4124c4
@ -52,6 +52,9 @@ config GENERIC_IOMAP
|
||||
config GENERIC_TIME
|
||||
def_bool n
|
||||
|
||||
config GENERIC_CLOCKEVENTS
|
||||
def_bool n
|
||||
|
||||
config SYS_SUPPORTS_APM_EMULATION
|
||||
bool
|
||||
|
||||
@ -436,11 +439,11 @@ endmenu
|
||||
|
||||
menu "Timer and clock configuration"
|
||||
|
||||
if !GENERIC_TIME
|
||||
|
||||
config SH_TMU
|
||||
bool "TMU timer support"
|
||||
depends on CPU_SH3 || CPU_SH4
|
||||
select GENERIC_TIME
|
||||
select GENERIC_CLOCKEVENTS
|
||||
default y
|
||||
help
|
||||
This enables the use of the TMU as the system timer.
|
||||
@ -459,8 +462,6 @@ config SH_MTU2
|
||||
help
|
||||
This enables the use of the MTU2 as the system timer.
|
||||
|
||||
endif
|
||||
|
||||
config SH_TIMER_IRQ
|
||||
int
|
||||
default "28" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785
|
||||
@ -468,24 +469,6 @@ config SH_TIMER_IRQ
|
||||
default "140" if CPU_SUBTYPE_SH7206
|
||||
default "16"
|
||||
|
||||
config NO_IDLE_HZ
|
||||
bool "Dynamic tick timer"
|
||||
help
|
||||
Select this option if you want to disable continuous timer ticks
|
||||
and have them programmed to occur as required. This option saves
|
||||
power as the system can remain in idle state for longer.
|
||||
|
||||
By default dynamic tick is disabled during the boot, and can be
|
||||
manually enabled with:
|
||||
|
||||
echo 1 > /sys/devices/system/timer/timer0/dyn_tick
|
||||
|
||||
Alternatively, if you want dynamic tick automatically enabled
|
||||
during boot, pass "dyntick=enable" via the kernel command string.
|
||||
|
||||
Please note that dynamic tick may affect the accuracy of
|
||||
timekeeping on some platforms depending on the implementation.
|
||||
|
||||
config SH_PCLK_FREQ
|
||||
int "Peripheral clock frequency (in Hz)"
|
||||
default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343
|
||||
@ -509,6 +492,8 @@ config SH_CLK_MD
|
||||
help
|
||||
MD2 - MD0 pin setting.
|
||||
|
||||
source "kernel/time/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
menu "CPU Frequency scaling"
|
||||
|
@ -93,6 +93,7 @@ static void __init landisk_setup(char **cmdline_p)
|
||||
*/
|
||||
struct sh_machine_vector mv_landisk __initmv = {
|
||||
.mv_name = "LANDISK",
|
||||
.mv_nr_irqs = 72,
|
||||
.mv_setup = landisk_setup,
|
||||
.mv_init_irq = init_landisk_IRQ,
|
||||
};
|
||||
|
@ -2,8 +2,9 @@
|
||||
# Makefile for the Linux SuperH-specific device drivers.
|
||||
#
|
||||
|
||||
obj-y += dma/
|
||||
|
||||
obj-$(CONFIG_PCI) += pci/
|
||||
obj-$(CONFIG_SH_DMA) += dma/
|
||||
obj-$(CONFIG_SUPERHYWAY) += superhyway/
|
||||
obj-$(CONFIG_PUSH_SWITCH) += push-switch.o
|
||||
obj-$(CONFIG_HEARTBEAT) += heartbeat.o
|
||||
|
@ -1,12 +1,12 @@
|
||||
menu "DMA support"
|
||||
|
||||
config SH_DMA
|
||||
bool "DMA controller (DMAC) support"
|
||||
help
|
||||
Selecting this option will provide same API as PC's Direct Memory
|
||||
Access Controller(8237A) for SuperH DMAC.
|
||||
config SH_DMA_API
|
||||
bool
|
||||
|
||||
If unsure, say N.
|
||||
config SH_DMA
|
||||
bool "SuperH on-chip DMA controller (DMAC) support"
|
||||
select SH_DMA_API
|
||||
default n
|
||||
|
||||
config NR_ONCHIP_DMA_CHANNELS
|
||||
depends on SH_DMA
|
||||
@ -53,4 +53,12 @@ config DMA_PAGE_OPS_CHANNEL
|
||||
in case channel 3 is unavailable. On the SH4, channels 1,2, and 3
|
||||
are dual-address capable.
|
||||
|
||||
config SH_DMABRG
|
||||
bool "SH7760 DMABRG support"
|
||||
depends on CPU_SUBTYPE_SH7760
|
||||
help
|
||||
The DMABRG does data transfers from main memory to Audio/USB units
|
||||
of the SH7760.
|
||||
Say Y if you want to use Audio/USB DMA on your SH7760 board.
|
||||
|
||||
endmenu
|
||||
|
@ -2,8 +2,8 @@
|
||||
# Makefile for the SuperH DMA specific kernel interface routines under Linux.
|
||||
#
|
||||
|
||||
obj-y += dma-api.o
|
||||
obj-$(CONFIG_SH_DMA_API) += dma-api.o dma-sysfs.o
|
||||
obj-$(CONFIG_ISA_DMA_API) += dma-isa.o
|
||||
obj-$(CONFIG_SYSFS) += dma-sysfs.o
|
||||
obj-$(CONFIG_SH_DMA) += dma-sh.o
|
||||
obj-$(CONFIG_SH_DREAMCAST) += dma-pvr2.o dma-g2.o
|
||||
obj-$(CONFIG_SH_DMABRG) += dmabrg.o
|
||||
|
196
arch/sh/drivers/dma/dmabrg.c
Normal file
196
arch/sh/drivers/dma/dmabrg.c
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* SH7760 DMABRG IRQ handling
|
||||
*
|
||||
* (c) 2007 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
|
||||
* licensed under the GPLv2.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/dmabrg.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* The DMABRG is a special DMA unit within the SH7760. It does transfers
|
||||
* from USB-SRAM/Audio units to main memory (and also the LCDC; but that
|
||||
* part is sensibly placed in the LCDC registers and requires no irqs)
|
||||
* It has 3 IRQ lines which trigger 10 events, and works independently
|
||||
* from the traditional SH DMAC (although it blocks usage of DMAC 0)
|
||||
*
|
||||
* BRGIRQID | component | dir | meaning | source
|
||||
* -----------------------------------------------------
|
||||
* 0 | USB-DMA | ... | xfer done | DMABRGI1
|
||||
* 1 | USB-UAE | ... | USB addr err.| DMABRGI0
|
||||
* 2 | HAC0/SSI0 | play| all done | DMABRGI1
|
||||
* 3 | HAC0/SSI0 | play| half done | DMABRGI2
|
||||
* 4 | HAC0/SSI0 | rec | all done | DMABRGI1
|
||||
* 5 | HAC0/SSI0 | rec | half done | DMABRGI2
|
||||
* 6 | HAC1/SSI1 | play| all done | DMABRGI1
|
||||
* 7 | HAC1/SSI1 | play| half done | DMABRGI2
|
||||
* 8 | HAC1/SSI1 | rec | all done | DMABRGI1
|
||||
* 9 | HAC1/SSI1 | rec | half done | DMABRGI2
|
||||
*
|
||||
* all can be enabled/disabled in the DMABRGCR register,
|
||||
* as well as checked if they occured.
|
||||
*
|
||||
* DMABRGI0 services USB DMA Address errors, but it still must be
|
||||
* enabled/acked in the DMABRGCR register. USB-DMA complete indicator
|
||||
* is grouped together with the audio buffer end indicators, too bad...
|
||||
*
|
||||
* DMABRGCR: Bits 31-24: audio-dma ENABLE flags,
|
||||
* Bits 23-16: audio-dma STATUS flags,
|
||||
* Bits 9-8: USB error/xfer ENABLE,
|
||||
* Bits 1-0: USB error/xfer STATUS.
|
||||
* Ack an IRQ by writing 0 to the STATUS flag.
|
||||
* Mask IRQ by writing 0 to ENABLE flag.
|
||||
*
|
||||
* Usage is almost like with any other IRQ:
|
||||
* dmabrg_request_irq(BRGIRQID, handler, data)
|
||||
* dmabrg_free_irq(BRGIRQID)
|
||||
*
|
||||
* handler prototype: void brgirqhandler(void *data)
|
||||
*/
|
||||
|
||||
#define DMARSRA 0xfe090000
|
||||
#define DMAOR 0xffa00040
|
||||
#define DMACHCR0 0xffa0000c
|
||||
#define DMABRGCR 0xfe3c0000
|
||||
|
||||
#define DMAOR_BRG 0x0000c000
|
||||
#define DMAOR_DMEN 0x00000001
|
||||
|
||||
#define DMABRGI0 68
|
||||
#define DMABRGI1 69
|
||||
#define DMABRGI2 70
|
||||
|
||||
struct dmabrg_handler {
|
||||
void (*handler)(void *);
|
||||
void *data;
|
||||
} *dmabrg_handlers;
|
||||
|
||||
static inline void dmabrg_call_handler(int i)
|
||||
{
|
||||
dmabrg_handlers[i].handler(dmabrg_handlers[i].data);
|
||||
}
|
||||
|
||||
/*
|
||||
* main DMABRG irq handler. It acks irqs and then
|
||||
* handles every set and unmasked bit sequentially.
|
||||
* No locking and no validity checks; it should be
|
||||
* as fast as possible (audio!)
|
||||
*/
|
||||
static irqreturn_t dmabrg_irq(int irq, void *data)
|
||||
{
|
||||
unsigned long dcr;
|
||||
unsigned int i;
|
||||
|
||||
dcr = ctrl_inl(DMABRGCR);
|
||||
ctrl_outl(dcr & ~0x00ff0003, DMABRGCR); /* ack all */
|
||||
dcr &= dcr >> 8; /* ignore masked */
|
||||
|
||||
/* USB stuff, get it out of the way first */
|
||||
if (dcr & 1)
|
||||
dmabrg_call_handler(DMABRGIRQ_USBDMA);
|
||||
if (dcr & 2)
|
||||
dmabrg_call_handler(DMABRGIRQ_USBDMAERR);
|
||||
|
||||
/* Audio */
|
||||
dcr >>= 16;
|
||||
while (dcr) {
|
||||
i = __ffs(dcr);
|
||||
dcr &= dcr - 1;
|
||||
dmabrg_call_handler(i + DMABRGIRQ_A0TXF);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void dmabrg_disable_irq(unsigned int dmairq)
|
||||
{
|
||||
unsigned long dcr;
|
||||
dcr = ctrl_inl(DMABRGCR);
|
||||
dcr &= ~(1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8));
|
||||
ctrl_outl(dcr, DMABRGCR);
|
||||
}
|
||||
|
||||
static void dmabrg_enable_irq(unsigned int dmairq)
|
||||
{
|
||||
unsigned long dcr;
|
||||
dcr = ctrl_inl(DMABRGCR);
|
||||
dcr |= (1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8));
|
||||
ctrl_outl(dcr, DMABRGCR);
|
||||
}
|
||||
|
||||
int dmabrg_request_irq(unsigned int dmairq, void(*handler)(void*),
|
||||
void *data)
|
||||
{
|
||||
if ((dmairq > 9) || !handler)
|
||||
return -ENOENT;
|
||||
if (dmabrg_handlers[dmairq].handler)
|
||||
return -EBUSY;
|
||||
|
||||
dmabrg_handlers[dmairq].handler = handler;
|
||||
dmabrg_handlers[dmairq].data = data;
|
||||
|
||||
dmabrg_enable_irq(dmairq);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dmabrg_request_irq);
|
||||
|
||||
void dmabrg_free_irq(unsigned int dmairq)
|
||||
{
|
||||
if (likely(dmairq < 10)) {
|
||||
dmabrg_disable_irq(dmairq);
|
||||
dmabrg_handlers[dmairq].handler = NULL;
|
||||
dmabrg_handlers[dmairq].data = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dmabrg_free_irq);
|
||||
|
||||
static int __init dmabrg_init(void)
|
||||
{
|
||||
unsigned long or;
|
||||
int ret;
|
||||
|
||||
dmabrg_handlers = kzalloc(10 * sizeof(struct dmabrg_handler),
|
||||
GFP_KERNEL);
|
||||
if (!dmabrg_handlers)
|
||||
return -ENOMEM;
|
||||
|
||||
#ifdef CONFIG_SH_DMA
|
||||
/* request DMAC channel 0 before anyone else can get it */
|
||||
ret = request_dma(0, "DMAC 0 (DMABRG)");
|
||||
if (ret < 0)
|
||||
printk(KERN_INFO "DMABRG: DMAC ch0 not reserved!\n");
|
||||
#endif
|
||||
|
||||
ctrl_outl(0, DMABRGCR);
|
||||
ctrl_outl(0, DMACHCR0);
|
||||
ctrl_outl(0x94000000, DMARSRA); /* enable DMABRG in DMAC 0 */
|
||||
|
||||
/* enable DMABRG mode, enable the DMAC */
|
||||
or = ctrl_inl(DMAOR);
|
||||
ctrl_outl(or | DMAOR_BRG | DMAOR_DMEN, DMAOR);
|
||||
|
||||
ret = request_irq(DMABRGI0, dmabrg_irq, IRQF_DISABLED,
|
||||
"DMABRG USB address error", NULL);
|
||||
if (ret)
|
||||
goto out0;
|
||||
|
||||
ret = request_irq(DMABRGI1, dmabrg_irq, IRQF_DISABLED,
|
||||
"DMABRG Transfer End", NULL);
|
||||
if (ret)
|
||||
goto out1;
|
||||
|
||||
ret = request_irq(DMABRGI2, dmabrg_irq, IRQF_DISABLED,
|
||||
"DMABRG Transfer Half", NULL);
|
||||
if (ret == 0)
|
||||
return ret;
|
||||
|
||||
free_irq(DMABRGI1, 0);
|
||||
out1: free_irq(DMABRGI0, 0);
|
||||
out0: kfree(dmabrg_handlers);
|
||||
return ret;
|
||||
}
|
||||
subsys_initcall(dmabrg_init);
|
@ -2,9 +2,8 @@
|
||||
# Makefile for the Linux/SuperH SH-2A backends.
|
||||
#
|
||||
|
||||
obj-y := common.o probe.o
|
||||
obj-y := common.o probe.o opcode_helper.o
|
||||
|
||||
common-y += $(addprefix ../sh2/, ex.o)
|
||||
common-y += $(addprefix ../sh2/, entry.o)
|
||||
common-y += $(addprefix ../sh2/, ex.o entry.o)
|
||||
|
||||
obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o
|
||||
|
55
arch/sh/kernel/cpu/sh2a/opcode_helper.c
Normal file
55
arch/sh/kernel/cpu/sh2a/opcode_helper.c
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* arch/sh/kernel/cpu/sh2a/opcode_helper.c
|
||||
*
|
||||
* Helper for the SH-2A 32-bit opcodes.
|
||||
*
|
||||
* Copyright (C) 2007 Paul Mundt
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
/*
|
||||
* Instructions on SH are generally fixed at 16-bits, however, SH-2A
|
||||
* introduces some 32-bit instructions. Since there are no real
|
||||
* constraints on their use (and they can be mixed and matched), we need
|
||||
* to check the instruction encoding to work out if it's a true 32-bit
|
||||
* instruction or not.
|
||||
*
|
||||
* Presently, 32-bit opcodes have only slight variations in what the
|
||||
* actual encoding looks like in the first-half of the instruction, which
|
||||
* makes it fairly straightforward to differentiate from the 16-bit ones.
|
||||
*
|
||||
* First 16-bits of encoding Used by
|
||||
*
|
||||
* 0011nnnnmmmm0001 mov.b, mov.w, mov.l, fmov.d,
|
||||
* fmov.s, movu.b, movu.w
|
||||
*
|
||||
* 0011nnnn0iii1001 bclr.b, bld.b, bset.b, bst.b, band.b,
|
||||
* bandnot.b, bldnot.b, bor.b, bornot.b,
|
||||
* bxor.b
|
||||
*
|
||||
* 0000nnnniiii0000 movi20
|
||||
* 0000nnnniiii0001 movi20s
|
||||
*/
|
||||
unsigned int instruction_size(unsigned int insn)
|
||||
{
|
||||
/* Look for the common cases */
|
||||
switch ((insn & 0xf00f)) {
|
||||
case 0x0000: /* movi20 */
|
||||
case 0x0001: /* movi20s */
|
||||
case 0x3001: /* 32-bit mov/fmov/movu variants */
|
||||
return 4;
|
||||
}
|
||||
|
||||
/* And the special cases.. */
|
||||
switch ((insn & 0xf08f)) {
|
||||
case 0x3009: /* 32-bit b*.b bit operations */
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
@ -18,6 +18,7 @@ int __init detect_cpu_and_cache_system(void)
|
||||
{
|
||||
/* Just SH7206 for now .. */
|
||||
current_cpu_data.type = CPU_SH7206;
|
||||
current_cpu_data.flags |= CPU_HAS_OP32;
|
||||
|
||||
current_cpu_data.dcache.ways = 4;
|
||||
current_cpu_data.dcache.way_incr = (1 << 11);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* arch/sh/kernel/cpu/sh3/ex.S
|
||||
*
|
||||
* The SH-3 exception vector table.
|
||||
* The SH-3 and SH-4 exception vector table.
|
||||
|
||||
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
|
||||
* Copyright (C) 2003 - 2006 Paul Mundt
|
||||
@ -9,7 +9,6 @@
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include <linux/linkage.h>
|
||||
|
||||
@ -36,8 +35,12 @@ ENTRY(exception_handling_table)
|
||||
.long exception_error ! address error load
|
||||
.long exception_error ! address error store /* 100 */
|
||||
#endif
|
||||
.long exception_error ! fpu_exception /* 120 */
|
||||
.long exception_error /* 140 */
|
||||
#if defined(CONFIG_SH_FPU)
|
||||
.long do_fpu_error /* 120 */
|
||||
#else
|
||||
.long exception_error /* 120 */
|
||||
#endif
|
||||
.long exception_error /* 140 */
|
||||
.long system_call ! Unconditional Trap /* 160 */
|
||||
.long exception_error ! reserved_instruction (filled by trap_init) /* 180 */
|
||||
.long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/
|
||||
@ -55,4 +58,4 @@ ENTRY(user_break_point_trap)
|
||||
* away offsets can be manually inserted in to their appropriate
|
||||
* location via set_exception_table_{evt,vec}().
|
||||
*/
|
||||
.balign 4096,0,4096
|
||||
.balign 4096,0,4096
|
||||
|
@ -2,10 +2,10 @@
|
||||
# Makefile for the Linux/SuperH SH-4 backends.
|
||||
#
|
||||
|
||||
obj-y := ex.o probe.o common.o
|
||||
common-y += $(addprefix ../sh3/, entry.o)
|
||||
obj-y := probe.o common.o
|
||||
common-y += $(addprefix ../sh3/, entry.o ex.o)
|
||||
|
||||
obj-$(CONFIG_SH_FPU) += fpu.o
|
||||
obj-$(CONFIG_SH_FPU) += fpu.o
|
||||
obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
|
||||
|
||||
# CPU subtype setup
|
||||
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* arch/sh/kernel/cpu/sh4/ex.S
|
||||
*
|
||||
* The SH-4 exception vector table.
|
||||
|
||||
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
|
||||
* Copyright (C) 2003 - 2006 Paul Mundt
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include <linux/linkage.h>
|
||||
|
||||
.align 2
|
||||
.data
|
||||
|
||||
ENTRY(exception_handling_table)
|
||||
.long exception_error /* 000 */
|
||||
.long exception_error
|
||||
#if defined(CONFIG_MMU)
|
||||
.long tlb_miss_load /* 040 */
|
||||
.long tlb_miss_store
|
||||
.long initial_page_write
|
||||
.long tlb_protection_violation_load
|
||||
.long tlb_protection_violation_store
|
||||
.long address_error_load
|
||||
.long address_error_store /* 100 */
|
||||
#else
|
||||
.long exception_error ! tlb miss load /* 040 */
|
||||
.long exception_error ! tlb miss store
|
||||
.long exception_error ! initial page write
|
||||
.long exception_error ! tlb prot violation load
|
||||
.long exception_error ! tlb prot violation store
|
||||
.long exception_error ! address error load
|
||||
.long exception_error ! address error store /* 100 */
|
||||
#endif
|
||||
#if defined(CONFIG_SH_FPU)
|
||||
.long do_fpu_error /* 120 */
|
||||
#else
|
||||
.long exception_error /* 120 */
|
||||
#endif
|
||||
.long exception_error /* 140 */
|
||||
.long system_call ! Unconditional Trap /* 160 */
|
||||
.long exception_error ! reserved_instruction (filled by trap_init) /* 180 */
|
||||
.long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/
|
||||
ENTRY(nmi_slot)
|
||||
#if defined (CONFIG_KGDB_NMI)
|
||||
.long debug_enter /* 1C0 */ ! Allow trap to debugger
|
||||
#else
|
||||
.long exception_none /* 1C0 */ ! Not implemented yet
|
||||
#endif
|
||||
ENTRY(user_break_point_trap)
|
||||
.long break_point_trap /* 1E0 */
|
||||
|
||||
/*
|
||||
* Pad the remainder of the table out, exceptions residing in far
|
||||
* away offsets can be manually inserted in to their appropriate
|
||||
* location via set_exception_table_{evt,vec}().
|
||||
*/
|
||||
.balign 4096,0,4096
|
@ -16,6 +16,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/signal.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* The PR (precision) bit in the FP Status Register must be clear when
|
||||
@ -265,7 +266,7 @@ ieee_fpe_handler (struct pt_regs *regs)
|
||||
nextpc = regs->pr;
|
||||
finsn = *(unsigned short *) (regs->pc + 2);
|
||||
} else {
|
||||
nextpc = regs->pc + 2;
|
||||
nextpc = regs->pc + instruction_size(insn);
|
||||
finsn = insn;
|
||||
}
|
||||
|
||||
|
@ -15,9 +15,12 @@
|
||||
#include <linux/pm.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/kexec.h>
|
||||
#include <asm/kdebug.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/tick.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/ubc.h>
|
||||
|
||||
static int hlt_counter;
|
||||
@ -58,12 +61,15 @@ void cpu_idle(void)
|
||||
if (!idle)
|
||||
idle = default_idle;
|
||||
|
||||
tick_nohz_stop_sched_tick();
|
||||
while (!need_resched())
|
||||
idle();
|
||||
tick_nohz_restart_sched_tick();
|
||||
|
||||
preempt_enable_no_resched();
|
||||
schedule();
|
||||
preempt_disable();
|
||||
check_pgt_cache();
|
||||
}
|
||||
}
|
||||
|
||||
@ -495,9 +501,9 @@ asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
|
||||
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
|
||||
|
||||
/* Rewind */
|
||||
regs->pc -= 2;
|
||||
regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
|
||||
|
||||
if (notify_die(DIE_TRAP, regs, regs->tra & 0xff,
|
||||
if (notify_die(DIE_TRAP, "debug trap", regs, 0, regs->tra & 0xff,
|
||||
SIGTRAP) == NOTIFY_STOP)
|
||||
return;
|
||||
|
||||
@ -514,9 +520,9 @@ asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
|
||||
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
|
||||
|
||||
/* Rewind */
|
||||
regs->pc -= 2;
|
||||
regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
|
||||
|
||||
if (notify_die(DIE_TRAP, regs, TRAPA_BUG_OPCODE & 0xff,
|
||||
if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
|
||||
SIGTRAP) == NOTIFY_STOP)
|
||||
return;
|
||||
|
||||
|
@ -431,7 +431,7 @@ const char *get_cpu_subtype(struct sh_cpuinfo *c)
|
||||
/* Symbolic CPU flags, keep in sync with asm/cpu-features.h */
|
||||
static const char *cpu_flags[] = {
|
||||
"none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr",
|
||||
"ptea", "llsc", "l2", NULL
|
||||
"ptea", "llsc", "l2", "op32", NULL
|
||||
};
|
||||
|
||||
static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c)
|
||||
|
@ -58,8 +58,6 @@ EXPORT_SYMBOL(__udelay);
|
||||
EXPORT_SYMBOL(__ndelay);
|
||||
EXPORT_SYMBOL(__const_udelay);
|
||||
|
||||
EXPORT_SYMBOL(__div64_32);
|
||||
|
||||
#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
|
||||
|
||||
/* These symbols are generated by the compiler itself */
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include <linux/personality.h>
|
||||
#include <linux/binfmts.h>
|
||||
#include <linux/freezer.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/ucontext.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
@ -500,7 +500,9 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
}
|
||||
/* fallthrough */
|
||||
case -ERESTARTNOINTR:
|
||||
regs->pc -= 2;
|
||||
regs->pc -= instruction_size(
|
||||
ctrl_inw(regs->pc - 4));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* gUSA handling */
|
||||
@ -516,7 +518,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
regs->regs[15] = regs->regs[1];
|
||||
if (regs->pc < regs->regs[0])
|
||||
/* Go to rewind point #1 */
|
||||
regs->pc = regs->regs[0] + offset - 2;
|
||||
regs->pc = regs->regs[0] + offset -
|
||||
instruction_size(ctrl_inw(regs->pc-4));
|
||||
}
|
||||
#ifdef CONFIG_PREEMPT
|
||||
local_irq_restore(flags);
|
||||
@ -600,9 +603,9 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
|
||||
regs->regs[0] == -ERESTARTSYS ||
|
||||
regs->regs[0] == -ERESTARTNOINTR) {
|
||||
regs->regs[0] = save_r0;
|
||||
regs->pc -= 2;
|
||||
regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
|
||||
} else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) {
|
||||
regs->pc -= 2;
|
||||
regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
|
||||
regs->regs[3] = __NR_restart_syscall;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
/*
|
||||
* Save stack-backtrace addresses into a stack_trace buffer.
|
||||
*/
|
||||
void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
|
||||
void save_stack_trace(struct stack_trace *trace)
|
||||
{
|
||||
unsigned long *sp = (unsigned long *)current_stack_pointer;
|
||||
|
||||
|
@ -354,3 +354,4 @@ ENTRY(sys_call_table)
|
||||
.long sys_move_pages
|
||||
.long sys_getcpu
|
||||
.long sys_epoll_pwait
|
||||
.long sys_utimensat /* 320 */
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
|
||||
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
|
||||
* Copyright (C) 2002 - 2006 Paul Mundt
|
||||
* Copyright (C) 2002 - 2007 Paul Mundt
|
||||
* Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org>
|
||||
*
|
||||
* Some code taken from i386 version.
|
||||
@ -15,6 +15,7 @@
|
||||
#include <linux/profile.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <asm/clock.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/timer.h>
|
||||
@ -38,6 +39,14 @@ static int null_rtc_set_time(const time_t secs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Null high precision timer functions for systems lacking one.
|
||||
*/
|
||||
static cycle_t null_hpt_read(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
|
||||
int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
|
||||
|
||||
@ -101,6 +110,7 @@ int do_settimeofday(struct timespec *tv)
|
||||
EXPORT_SYMBOL(do_settimeofday);
|
||||
#endif /* !CONFIG_GENERIC_TIME */
|
||||
|
||||
#ifndef CONFIG_GENERIC_CLOCKEVENTS
|
||||
/* last time the RTC clock got updated */
|
||||
static long last_rtc_update;
|
||||
|
||||
@ -138,6 +148,7 @@ void handle_timer_tick(void)
|
||||
last_rtc_update = xtime.tv_sec - 600;
|
||||
}
|
||||
}
|
||||
#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int timer_suspend(struct sys_device *dev, pm_message_t state)
|
||||
@ -168,108 +179,6 @@ static struct sysdev_class timer_sysclass = {
|
||||
.resume = timer_resume,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_NO_IDLE_HZ
|
||||
static int timer_dyn_tick_enable(void)
|
||||
{
|
||||
struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
|
||||
unsigned long flags;
|
||||
int ret = -ENODEV;
|
||||
|
||||
if (dyn_tick) {
|
||||
spin_lock_irqsave(&dyn_tick->lock, flags);
|
||||
ret = 0;
|
||||
if (!(dyn_tick->state & DYN_TICK_ENABLED)) {
|
||||
ret = dyn_tick->enable();
|
||||
|
||||
if (ret == 0)
|
||||
dyn_tick->state |= DYN_TICK_ENABLED;
|
||||
}
|
||||
spin_unlock_irqrestore(&dyn_tick->lock, flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int timer_dyn_tick_disable(void)
|
||||
{
|
||||
struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
|
||||
unsigned long flags;
|
||||
int ret = -ENODEV;
|
||||
|
||||
if (dyn_tick) {
|
||||
spin_lock_irqsave(&dyn_tick->lock, flags);
|
||||
ret = 0;
|
||||
if (dyn_tick->state & DYN_TICK_ENABLED) {
|
||||
ret = dyn_tick->disable();
|
||||
|
||||
if (ret == 0)
|
||||
dyn_tick->state &= ~DYN_TICK_ENABLED;
|
||||
}
|
||||
spin_unlock_irqrestore(&dyn_tick->lock, flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reprogram the system timer for at least the calculated time interval.
|
||||
* This function should be called from the idle thread with IRQs disabled,
|
||||
* immediately before sleeping.
|
||||
*/
|
||||
void timer_dyn_reprogram(void)
|
||||
{
|
||||
struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
|
||||
unsigned long next, seq, flags;
|
||||
|
||||
if (!dyn_tick)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dyn_tick->lock, flags);
|
||||
if (dyn_tick->state & DYN_TICK_ENABLED) {
|
||||
next = next_timer_interrupt();
|
||||
do {
|
||||
seq = read_seqbegin(&xtime_lock);
|
||||
dyn_tick->reprogram(next - jiffies);
|
||||
} while (read_seqretry(&xtime_lock, seq));
|
||||
}
|
||||
spin_unlock_irqrestore(&dyn_tick->lock, flags);
|
||||
}
|
||||
|
||||
static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%i\n",
|
||||
(sys_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1);
|
||||
}
|
||||
|
||||
static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
unsigned int enable = simple_strtoul(buf, NULL, 2);
|
||||
|
||||
if (enable)
|
||||
timer_dyn_tick_enable();
|
||||
else
|
||||
timer_dyn_tick_disable();
|
||||
|
||||
return count;
|
||||
}
|
||||
static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick);
|
||||
|
||||
/*
|
||||
* dyntick=enable|disable
|
||||
*/
|
||||
static char dyntick_str[4] __initdata = "";
|
||||
|
||||
static int __init dyntick_setup(char *str)
|
||||
{
|
||||
if (str)
|
||||
strlcpy(dyntick_str, str, sizeof(dyntick_str));
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("dyntick=", dyntick_setup);
|
||||
#endif
|
||||
|
||||
static int __init timer_init_sysfs(void)
|
||||
{
|
||||
int ret = sysdev_class_register(&timer_sysclass);
|
||||
@ -277,27 +186,51 @@ static int __init timer_init_sysfs(void)
|
||||
return ret;
|
||||
|
||||
sys_timer->dev.cls = &timer_sysclass;
|
||||
ret = sysdev_register(&sys_timer->dev);
|
||||
|
||||
#ifdef CONFIG_NO_IDLE_HZ
|
||||
if (ret == 0 && sys_timer->dyn_tick) {
|
||||
ret = sysdev_create_file(&sys_timer->dev, &attr_dyn_tick);
|
||||
|
||||
/*
|
||||
* Turn on dynamic tick after calibrate delay
|
||||
* for correct bogomips
|
||||
*/
|
||||
if (ret == 0 && dyntick_str[0] == 'e')
|
||||
ret = timer_dyn_tick_enable();
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
return sysdev_register(&sys_timer->dev);
|
||||
}
|
||||
device_initcall(timer_init_sysfs);
|
||||
|
||||
void (*board_time_init)(void);
|
||||
|
||||
/*
|
||||
* Shamelessly based on the MIPS and Sparc64 work.
|
||||
*/
|
||||
static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
|
||||
unsigned long sh_hpt_frequency = 0;
|
||||
|
||||
#define NSEC_PER_CYC_SHIFT 10
|
||||
|
||||
struct clocksource clocksource_sh = {
|
||||
.name = "SuperH",
|
||||
.rating = 200,
|
||||
.mask = CLOCKSOURCE_MASK(32),
|
||||
.read = null_hpt_read,
|
||||
.shift = 16,
|
||||
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
||||
};
|
||||
|
||||
static void __init init_sh_clocksource(void)
|
||||
{
|
||||
if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read)
|
||||
return;
|
||||
|
||||
clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency,
|
||||
clocksource_sh.shift);
|
||||
|
||||
timer_ticks_per_nsec_quotient =
|
||||
clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT);
|
||||
|
||||
clocksource_register(&clocksource_sh);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GENERIC_TIME
|
||||
unsigned long long sched_clock(void)
|
||||
{
|
||||
unsigned long long ticks = clocksource_sh.read();
|
||||
return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT;
|
||||
}
|
||||
#endif
|
||||
|
||||
void __init time_init(void)
|
||||
{
|
||||
if (board_time_init)
|
||||
@ -316,10 +249,15 @@ void __init time_init(void)
|
||||
sys_timer = get_sys_timer();
|
||||
printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
|
||||
|
||||
#ifdef CONFIG_NO_IDLE_HZ
|
||||
if (sys_timer->dyn_tick)
|
||||
spin_lock_init(&sys_timer->dyn_tick->lock);
|
||||
#endif
|
||||
if (sys_timer->ops->read)
|
||||
clocksource_sh.read = sys_timer->ops->read;
|
||||
|
||||
init_sh_clocksource();
|
||||
|
||||
if (sh_hpt_frequency)
|
||||
printk("Using %lu.%03lu MHz high precision timer.\n",
|
||||
((sh_hpt_frequency + 500) / 1000) / 1000,
|
||||
((sh_hpt_frequency + 500) / 1000) % 1000);
|
||||
|
||||
#if defined(CONFIG_SH_KGDB)
|
||||
/*
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* arch/sh/kernel/timers/timer-tmu.c - TMU Timer Support
|
||||
*
|
||||
* Copyright (C) 2005 Paul Mundt
|
||||
* Copyright (C) 2005 - 2007 Paul Mundt
|
||||
*
|
||||
* TMU handling code hacked out of arch/sh/kernel/time.c
|
||||
*
|
||||
@ -18,6 +18,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/seqlock.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <asm/timer.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/io.h>
|
||||
@ -25,56 +26,75 @@
|
||||
#include <asm/clock.h>
|
||||
|
||||
#define TMU_TOCR_INIT 0x00
|
||||
#define TMU0_TCR_INIT 0x0020
|
||||
#define TMU_TSTR_INIT 1
|
||||
#define TMU_TCR_INIT 0x0020
|
||||
|
||||
#define TMU0_TCR_CALIB 0x0000
|
||||
|
||||
static unsigned long tmu_timer_get_offset(void)
|
||||
static int tmu_timer_start(void)
|
||||
{
|
||||
int count;
|
||||
static int count_p = 0x7fffffff; /* for the first call after boot */
|
||||
static unsigned long jiffies_p = 0;
|
||||
|
||||
/*
|
||||
* cache volatile jiffies temporarily; we have IRQs turned off.
|
||||
*/
|
||||
unsigned long jiffies_t;
|
||||
|
||||
/* timer count may underflow right here */
|
||||
count = ctrl_inl(TMU0_TCNT); /* read the latched count */
|
||||
|
||||
jiffies_t = jiffies;
|
||||
|
||||
/*
|
||||
* avoiding timer inconsistencies (they are rare, but they happen)...
|
||||
* there is one kind of problem that must be avoided here:
|
||||
* 1. the timer counter underflows
|
||||
*/
|
||||
|
||||
if (jiffies_t == jiffies_p) {
|
||||
if (count > count_p) {
|
||||
/* the nutcase */
|
||||
if (ctrl_inw(TMU0_TCR) & 0x100) { /* Check UNF bit */
|
||||
count -= LATCH;
|
||||
} else {
|
||||
printk("%s (): hardware timer problem?\n",
|
||||
__FUNCTION__);
|
||||
}
|
||||
}
|
||||
} else
|
||||
jiffies_p = jiffies_t;
|
||||
|
||||
count_p = count;
|
||||
|
||||
count = ((LATCH-1) - count) * TICK_SIZE;
|
||||
count = (count + LATCH/2) / LATCH;
|
||||
|
||||
return count;
|
||||
ctrl_outb(ctrl_inb(TMU_TSTR) | 0x3, TMU_TSTR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tmu0_timer_set_interval(unsigned long interval, unsigned int reload)
|
||||
{
|
||||
ctrl_outl(interval, TMU0_TCNT);
|
||||
|
||||
/*
|
||||
* TCNT reloads from TCOR on underflow, clear it if we don't
|
||||
* intend to auto-reload
|
||||
*/
|
||||
if (reload)
|
||||
ctrl_outl(interval, TMU0_TCOR);
|
||||
else
|
||||
ctrl_outl(0, TMU0_TCOR);
|
||||
|
||||
tmu_timer_start();
|
||||
}
|
||||
|
||||
static int tmu_timer_stop(void)
|
||||
{
|
||||
ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x3, TMU_TSTR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cycle_t tmu_timer_read(void)
|
||||
{
|
||||
return ~ctrl_inl(TMU1_TCNT);
|
||||
}
|
||||
|
||||
static int tmu_set_next_event(unsigned long cycles,
|
||||
struct clock_event_device *evt)
|
||||
{
|
||||
tmu0_timer_set_interval(cycles, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tmu_set_mode(enum clock_event_mode mode,
|
||||
struct clock_event_device *evt)
|
||||
{
|
||||
switch (mode) {
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
ctrl_outl(ctrl_inl(TMU0_TCNT), TMU0_TCOR);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
ctrl_outl(0, TMU0_TCOR);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_UNUSED:
|
||||
case CLOCK_EVT_MODE_SHUTDOWN:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct clock_event_device tmu0_clockevent = {
|
||||
.name = "tmu0",
|
||||
.shift = 32,
|
||||
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
|
||||
.set_mode = tmu_set_mode,
|
||||
.set_next_event = tmu_set_next_event,
|
||||
};
|
||||
|
||||
static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
|
||||
{
|
||||
struct clock_event_device *evt = &tmu0_clockevent;
|
||||
unsigned long timer_status;
|
||||
|
||||
/* Clear UNF bit */
|
||||
@ -82,72 +102,76 @@ static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
|
||||
timer_status &= ~0x100;
|
||||
ctrl_outw(timer_status, TMU0_TCR);
|
||||
|
||||
/*
|
||||
* Here we are in the timer irq handler. We just have irqs locally
|
||||
* disabled but we don't know if the timer_bh is running on the other
|
||||
* CPU. We need to avoid to SMP race with it. NOTE: we don' t need
|
||||
* the irq version of write_lock because as just said we have irq
|
||||
* locally disabled. -arca
|
||||
*/
|
||||
write_seqlock(&xtime_lock);
|
||||
handle_timer_tick();
|
||||
write_sequnlock(&xtime_lock);
|
||||
evt->event_handler(evt);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct irqaction tmu_irq = {
|
||||
.name = "timer",
|
||||
static struct irqaction tmu0_irq = {
|
||||
.name = "periodic timer",
|
||||
.handler = tmu_timer_interrupt,
|
||||
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
|
||||
.mask = CPU_MASK_NONE,
|
||||
};
|
||||
|
||||
static void tmu_clk_init(struct clk *clk)
|
||||
static void tmu0_clk_init(struct clk *clk)
|
||||
{
|
||||
u8 divisor = TMU0_TCR_INIT & 0x7;
|
||||
ctrl_outw(TMU0_TCR_INIT, TMU0_TCR);
|
||||
u8 divisor = TMU_TCR_INIT & 0x7;
|
||||
ctrl_outw(TMU_TCR_INIT, TMU0_TCR);
|
||||
clk->rate = clk->parent->rate / (4 << (divisor << 1));
|
||||
}
|
||||
|
||||
static void tmu_clk_recalc(struct clk *clk)
|
||||
static void tmu0_clk_recalc(struct clk *clk)
|
||||
{
|
||||
u8 divisor = ctrl_inw(TMU0_TCR) & 0x7;
|
||||
clk->rate = clk->parent->rate / (4 << (divisor << 1));
|
||||
}
|
||||
|
||||
static struct clk_ops tmu_clk_ops = {
|
||||
.init = tmu_clk_init,
|
||||
.recalc = tmu_clk_recalc,
|
||||
static struct clk_ops tmu0_clk_ops = {
|
||||
.init = tmu0_clk_init,
|
||||
.recalc = tmu0_clk_recalc,
|
||||
};
|
||||
|
||||
static struct clk tmu0_clk = {
|
||||
.name = "tmu0_clk",
|
||||
.ops = &tmu_clk_ops,
|
||||
.ops = &tmu0_clk_ops,
|
||||
};
|
||||
|
||||
static int tmu_timer_start(void)
|
||||
static void tmu1_clk_init(struct clk *clk)
|
||||
{
|
||||
ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
|
||||
return 0;
|
||||
u8 divisor = TMU_TCR_INIT & 0x7;
|
||||
ctrl_outw(divisor, TMU1_TCR);
|
||||
clk->rate = clk->parent->rate / (4 << (divisor << 1));
|
||||
}
|
||||
|
||||
static int tmu_timer_stop(void)
|
||||
static void tmu1_clk_recalc(struct clk *clk)
|
||||
{
|
||||
ctrl_outb(0, TMU_TSTR);
|
||||
return 0;
|
||||
u8 divisor = ctrl_inw(TMU1_TCR) & 0x7;
|
||||
clk->rate = clk->parent->rate / (4 << (divisor << 1));
|
||||
}
|
||||
|
||||
static struct clk_ops tmu1_clk_ops = {
|
||||
.init = tmu1_clk_init,
|
||||
.recalc = tmu1_clk_recalc,
|
||||
};
|
||||
|
||||
static struct clk tmu1_clk = {
|
||||
.name = "tmu1_clk",
|
||||
.ops = &tmu1_clk_ops,
|
||||
};
|
||||
|
||||
static int tmu_timer_init(void)
|
||||
{
|
||||
unsigned long interval;
|
||||
unsigned long frequency;
|
||||
|
||||
setup_irq(CONFIG_SH_TIMER_IRQ, &tmu_irq);
|
||||
setup_irq(CONFIG_SH_TIMER_IRQ, &tmu0_irq);
|
||||
|
||||
tmu0_clk.parent = clk_get(NULL, "module_clk");
|
||||
tmu1_clk.parent = clk_get(NULL, "module_clk");
|
||||
|
||||
/* Start TMU0 */
|
||||
tmu_timer_stop();
|
||||
|
||||
#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && \
|
||||
!defined(CONFIG_CPU_SUBTYPE_SH7760) && \
|
||||
!defined(CONFIG_CPU_SUBTYPE_SH7785)
|
||||
@ -155,15 +179,29 @@ static int tmu_timer_init(void)
|
||||
#endif
|
||||
|
||||
clk_register(&tmu0_clk);
|
||||
clk_register(&tmu1_clk);
|
||||
clk_enable(&tmu0_clk);
|
||||
clk_enable(&tmu1_clk);
|
||||
|
||||
interval = (clk_get_rate(&tmu0_clk) + HZ / 2) / HZ;
|
||||
printk(KERN_INFO "Interval = %ld\n", interval);
|
||||
frequency = clk_get_rate(&tmu0_clk);
|
||||
interval = (frequency + HZ / 2) / HZ;
|
||||
|
||||
ctrl_outl(interval, TMU0_TCOR);
|
||||
ctrl_outl(interval, TMU0_TCNT);
|
||||
sh_hpt_frequency = clk_get_rate(&tmu1_clk);
|
||||
ctrl_outl(~0, TMU1_TCNT);
|
||||
ctrl_outl(~0, TMU1_TCOR);
|
||||
|
||||
tmu_timer_start();
|
||||
tmu0_timer_set_interval(interval, 1);
|
||||
|
||||
tmu0_clockevent.mult = div_sc(frequency, NSEC_PER_SEC,
|
||||
tmu0_clockevent.shift);
|
||||
tmu0_clockevent.max_delta_ns =
|
||||
clockevent_delta2ns(-1, &tmu0_clockevent);
|
||||
tmu0_clockevent.min_delta_ns =
|
||||
clockevent_delta2ns(1, &tmu0_clockevent);
|
||||
|
||||
tmu0_clockevent.cpumask = cpumask_of_cpu(0);
|
||||
|
||||
clockevents_register_device(&tmu0_clockevent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -172,9 +210,7 @@ struct sys_timer_ops tmu_timer_ops = {
|
||||
.init = tmu_timer_init,
|
||||
.start = tmu_timer_start,
|
||||
.stop = tmu_timer_stop,
|
||||
#ifndef CONFIG_GENERIC_TIME
|
||||
.get_offset = tmu_timer_get_offset,
|
||||
#endif
|
||||
.read = tmu_timer_read,
|
||||
};
|
||||
|
||||
struct sys_timer tmu_timer = {
|
||||
|
@ -20,10 +20,10 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/debug_locks.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/limits.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/kdebug.h>
|
||||
|
||||
#ifdef CONFIG_SH_KGDB
|
||||
#include <asm/kgdb.h>
|
||||
@ -76,20 +76,6 @@ static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
|
||||
}
|
||||
}
|
||||
|
||||
ATOMIC_NOTIFIER_HEAD(shdie_chain);
|
||||
|
||||
int register_die_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_register(&shdie_chain, nb);
|
||||
}
|
||||
EXPORT_SYMBOL(register_die_notifier);
|
||||
|
||||
int unregister_die_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_unregister(&shdie_chain, nb);
|
||||
}
|
||||
EXPORT_SYMBOL(unregister_die_notifier);
|
||||
|
||||
static DEFINE_SPINLOCK(die_lock);
|
||||
|
||||
void die(const char * str, struct pt_regs * regs, long err)
|
||||
@ -505,7 +491,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
|
||||
simple:
|
||||
ret = handle_unaligned_ins(instruction,regs);
|
||||
if (ret==0)
|
||||
regs->pc += 2;
|
||||
regs->pc += instruction_size(instruction);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_CPU_SH2A */
|
||||
@ -682,7 +668,7 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
|
||||
|
||||
err = do_fpu_inst(inst, regs);
|
||||
if (!err) {
|
||||
regs->pc += 2;
|
||||
regs->pc += instruction_size(inst);
|
||||
return;
|
||||
}
|
||||
/* not a FPU inst. */
|
||||
|
@ -24,9 +24,10 @@ inline void __const_udelay(unsigned long xloops)
|
||||
__asm__("dmulu.l %0, %2\n\t"
|
||||
"sts mach, %0"
|
||||
: "=r" (xloops)
|
||||
: "0" (xloops), "r" (cpu_data[raw_smp_processor_id()].loops_per_jiffy)
|
||||
: "0" (xloops),
|
||||
"r" (HZ * cpu_data[raw_smp_processor_id()].loops_per_jiffy)
|
||||
: "macl", "mach");
|
||||
__delay(xloops * HZ);
|
||||
__delay(xloops);
|
||||
}
|
||||
|
||||
void __udelay(unsigned long usecs)
|
||||
|
@ -218,6 +218,9 @@ endmenu
|
||||
|
||||
menu "Memory management options"
|
||||
|
||||
config QUICKLIST
|
||||
def_bool y
|
||||
|
||||
config MMU
|
||||
bool "Support for memory management hardware"
|
||||
depends on !CPU_SH2
|
||||
@ -300,6 +303,10 @@ config NODES_SHIFT
|
||||
config ARCH_FLATMEM_ENABLE
|
||||
def_bool y
|
||||
|
||||
config MAX_ACTIVE_REGIONS
|
||||
int
|
||||
default "1"
|
||||
|
||||
config ARCH_POPULATES_NODE_MAP
|
||||
def_bool y
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <asm/kdebug.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
@ -67,6 +67,8 @@ void show_mem(void)
|
||||
printk("%d slab pages\n", slab);
|
||||
printk("%d pages shared\n", shared);
|
||||
printk("%d pages swap cached\n", cached);
|
||||
printk(KERN_INFO "Total of %ld pages in page table cache\n",
|
||||
quicklist_total_size());
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
|
@ -104,7 +104,7 @@ static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
|
||||
|
||||
writeb(tmp, rtc->regbase + RCR1);
|
||||
|
||||
rtc_update_irq(&rtc->rtc_dev, 1, events);
|
||||
rtc_update_irq(rtc->rtc_dev, 1, events);
|
||||
|
||||
spin_unlock(&rtc->lock);
|
||||
|
||||
@ -139,7 +139,7 @@ static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
|
||||
|
||||
rtc->rearm_aie = 1;
|
||||
|
||||
rtc_update_irq(&rtc->rtc_dev, 1, events);
|
||||
rtc_update_irq(rtc->rtc_dev, 1, events);
|
||||
}
|
||||
|
||||
spin_unlock(&rtc->lock);
|
||||
@ -153,7 +153,7 @@ static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
|
||||
|
||||
spin_lock(&rtc->lock);
|
||||
|
||||
rtc_update_irq(&rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
|
||||
rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
|
||||
|
||||
spin_unlock(&rtc->lock);
|
||||
|
||||
@ -341,7 +341,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
tm->tm_sec--;
|
||||
#endif
|
||||
|
||||
dev_dbg(&dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
|
||||
dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
|
||||
"mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
__FUNCTION__,
|
||||
tm->tm_sec, tm->tm_min, tm->tm_hour,
|
||||
|
@ -1,12 +1,12 @@
|
||||
#ifndef __ASM_SH_BUG_H
|
||||
#define __ASM_SH_BUG_H
|
||||
|
||||
#define TRAPA_BUG_OPCODE 0xc33e /* trapa #0x3e */
|
||||
|
||||
#ifdef CONFIG_BUG
|
||||
#define HAVE_ARCH_BUG
|
||||
#define HAVE_ARCH_WARN_ON
|
||||
|
||||
#define TRAPA_BUG_OPCODE 0xc33e /* trapa #0x3e */
|
||||
|
||||
/**
|
||||
* _EMIT_BUG_ENTRY
|
||||
* %1 - __FILE__
|
||||
|
@ -20,5 +20,6 @@
|
||||
#define CPU_HAS_PTEA 0x0020 /* PTEA register */
|
||||
#define CPU_HAS_LLSC 0x0040 /* movli.l/movco.l */
|
||||
#define CPU_HAS_L2_CACHE 0x0080 /* Secondary cache / URAM */
|
||||
#define CPU_HAS_OP32 0x0100 /* 32-bit instruction support */
|
||||
|
||||
#endif /* __ASM_SH_CPU_FEATURES_H */
|
||||
|
23
include/asm-sh/dmabrg.h
Normal file
23
include/asm-sh/dmabrg.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* SH7760 DMABRG (USB/Audio) support
|
||||
*/
|
||||
|
||||
#ifndef _DMABRG_H_
|
||||
#define _DMABRG_H_
|
||||
|
||||
/* IRQ sources */
|
||||
#define DMABRGIRQ_USBDMA 0
|
||||
#define DMABRGIRQ_USBDMAERR 1
|
||||
#define DMABRGIRQ_A0TXF 2
|
||||
#define DMABRGIRQ_A0TXH 3
|
||||
#define DMABRGIRQ_A0RXF 4
|
||||
#define DMABRGIRQ_A0RXH 5
|
||||
#define DMABRGIRQ_A1TXF 6
|
||||
#define DMABRGIRQ_A1TXH 7
|
||||
#define DMABRGIRQ_A1RXF 8
|
||||
#define DMABRGIRQ_A1RXH 9
|
||||
|
||||
extern int dmabrg_request_irq(unsigned int, void(*)(void *), void *);
|
||||
extern void dmabrg_free_irq(unsigned int);
|
||||
|
||||
#endif
|
@ -2,20 +2,6 @@
|
||||
#define __ASM_SH_KDEBUG_H
|
||||
|
||||
#include <linux/notifier.h>
|
||||
#include <asm-generic/kdebug.h>
|
||||
|
||||
struct pt_regs;
|
||||
|
||||
struct die_args {
|
||||
struct pt_regs *regs;
|
||||
int trapnr;
|
||||
};
|
||||
|
||||
int register_die_notifier(struct notifier_block *nb);
|
||||
int unregister_die_notifier(struct notifier_block *nb);
|
||||
int register_page_fault_notifier(struct notifier_block *nb);
|
||||
int unregister_page_fault_notifier(struct notifier_block *nb);
|
||||
extern struct atomic_notifier_head shdie_chain;
|
||||
|
||||
/* Grossly misnamed. */
|
||||
enum die_val {
|
||||
@ -23,14 +9,7 @@ enum die_val {
|
||||
DIE_PAGE_FAULT,
|
||||
};
|
||||
|
||||
static inline int notify_die(enum die_val val, struct pt_regs *regs,
|
||||
int trap, int sig)
|
||||
{
|
||||
struct die_args args = {
|
||||
.regs = regs,
|
||||
.trapnr = trap,
|
||||
};
|
||||
int register_page_fault_notifier(struct notifier_block *nb);
|
||||
int unregister_page_fault_notifier(struct notifier_block *nb);
|
||||
|
||||
return atomic_notifier_call_chain(&shdie_chain, val, &args);
|
||||
}
|
||||
#endif /* __ASM_SH_KDEBUG_H */
|
||||
|
@ -1,6 +1,12 @@
|
||||
#ifndef __ASM_SH_PGALLOC_H
|
||||
#define __ASM_SH_PGALLOC_H
|
||||
|
||||
#include <linux/quicklist.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#define QUICK_PGD 0 /* We preserve special mappings over free */
|
||||
#define QUICK_PT 1 /* Other page table pages that are zero on free */
|
||||
|
||||
static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
|
||||
pte_t *pte)
|
||||
{
|
||||
@ -13,48 +19,49 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
|
||||
set_pmd(pmd, __pmd((unsigned long)page_address(pte)));
|
||||
}
|
||||
|
||||
static inline void pgd_ctor(void *x)
|
||||
{
|
||||
pgd_t *pgd = x;
|
||||
|
||||
memcpy(pgd + USER_PTRS_PER_PGD,
|
||||
swapper_pg_dir + USER_PTRS_PER_PGD,
|
||||
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and free page tables.
|
||||
*/
|
||||
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
|
||||
{
|
||||
pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT);
|
||||
|
||||
if (pgd) {
|
||||
memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
|
||||
memcpy(pgd + USER_PTRS_PER_PGD,
|
||||
swapper_pg_dir + USER_PTRS_PER_PGD,
|
||||
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
|
||||
}
|
||||
|
||||
return pgd;
|
||||
return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor);
|
||||
}
|
||||
|
||||
static inline void pgd_free(pgd_t *pgd)
|
||||
{
|
||||
free_page((unsigned long)pgd);
|
||||
quicklist_free(QUICK_PGD, NULL, pgd);
|
||||
}
|
||||
|
||||
static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
|
||||
unsigned long address)
|
||||
{
|
||||
return (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
|
||||
return quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
|
||||
}
|
||||
|
||||
static inline struct page *pte_alloc_one(struct mm_struct *mm,
|
||||
unsigned long address)
|
||||
{
|
||||
return alloc_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
|
||||
void *pg = quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
|
||||
return pg ? virt_to_page(pg) : NULL;
|
||||
}
|
||||
|
||||
static inline void pte_free_kernel(pte_t *pte)
|
||||
{
|
||||
free_page((unsigned long)pte);
|
||||
quicklist_free(QUICK_PT, NULL, pte);
|
||||
}
|
||||
|
||||
static inline void pte_free(struct page *pte)
|
||||
{
|
||||
__free_page(pte);
|
||||
quicklist_free_page(QUICK_PT, NULL, pte);
|
||||
}
|
||||
|
||||
#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
|
||||
@ -66,6 +73,11 @@ static inline void pte_free(struct page *pte)
|
||||
|
||||
#define pmd_free(x) do { } while (0)
|
||||
#define __pmd_free_tlb(tlb,x) do { } while (0)
|
||||
#define check_pgt_cache() do { } while (0)
|
||||
|
||||
static inline void check_pgt_cache(void)
|
||||
{
|
||||
quicklist_trim(QUICK_PGD, NULL, 25, 16);
|
||||
quicklist_trim(QUICK_PT, NULL, 25, 16);
|
||||
}
|
||||
|
||||
#endif /* __ASM_SH_PGALLOC_H */
|
||||
|
@ -255,6 +255,15 @@ static inline void *set_exception_table_evt(unsigned int evt, void *handler)
|
||||
return set_exception_table_vec(evt >> 5, handler);
|
||||
}
|
||||
|
||||
/*
|
||||
* SH-2A has both 16 and 32-bit opcodes, do lame encoding checks.
|
||||
*/
|
||||
#ifdef CONFIG_CPU_SH2A
|
||||
extern unsigned int instruction_size(unsigned int insn);
|
||||
#else
|
||||
#define instruction_size(insn) (2)
|
||||
#endif
|
||||
|
||||
/* XXX
|
||||
* disable hlt during certain critical i/o operations
|
||||
*/
|
||||
|
@ -2,12 +2,14 @@
|
||||
#define __ASM_SH_TIMER_H
|
||||
|
||||
#include <linux/sysdev.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <asm/cpu/timer.h>
|
||||
|
||||
struct sys_timer_ops {
|
||||
int (*init)(void);
|
||||
int (*start)(void);
|
||||
int (*stop)(void);
|
||||
cycle_t (*read)(void);
|
||||
#ifndef CONFIG_GENERIC_TIME
|
||||
unsigned long (*get_offset)(void);
|
||||
#endif
|
||||
@ -18,29 +20,8 @@ struct sys_timer {
|
||||
|
||||
struct sys_device dev;
|
||||
struct sys_timer_ops *ops;
|
||||
|
||||
#ifdef CONFIG_NO_IDLE_HZ
|
||||
struct dyn_tick_timer *dyn_tick;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_NO_IDLE_HZ
|
||||
#define DYN_TICK_ENABLED (1 << 1)
|
||||
|
||||
struct dyn_tick_timer {
|
||||
spinlock_t lock;
|
||||
unsigned int state; /* Current state */
|
||||
int (*enable)(void); /* Enables dynamic tick */
|
||||
int (*disable)(void); /* Disables dynamic tick */
|
||||
void (*reprogram)(unsigned long); /* Reprograms the timer */
|
||||
int (*handler)(int, void *);
|
||||
};
|
||||
|
||||
void timer_dyn_reprogram(void);
|
||||
#else
|
||||
#define timer_dyn_reprogram() do { } while (0)
|
||||
#endif
|
||||
|
||||
#define TICK_SIZE (tick_nsec / 1000)
|
||||
|
||||
extern struct sys_timer tmu_timer, cmt_timer, mtu2_timer;
|
||||
@ -58,5 +39,7 @@ struct sys_timer *get_sys_timer(void);
|
||||
|
||||
/* arch/sh/kernel/time.c */
|
||||
void handle_timer_tick(void);
|
||||
extern unsigned long sh_hpt_frequency;
|
||||
extern struct clocksource clocksource_sh;
|
||||
|
||||
#endif /* __ASM_SH_TIMER_H */
|
||||
|
@ -85,7 +85,7 @@
|
||||
#define __NR_sigpending 73
|
||||
#define __NR_sethostname 74
|
||||
#define __NR_setrlimit 75
|
||||
#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
|
||||
#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
|
||||
#define __NR_getrusage 77
|
||||
#define __NR_gettimeofday 78
|
||||
#define __NR_settimeofday 79
|
||||
@ -328,8 +328,9 @@
|
||||
#define __NR_move_pages 317
|
||||
#define __NR_getcpu 318
|
||||
#define __NR_epoll_pwait 319
|
||||
#define __NR_utimensat 320
|
||||
|
||||
#define NR_syscalls 320
|
||||
#define NR_syscalls 321
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
|
@ -166,5 +166,5 @@ config ZONE_DMA_FLAG
|
||||
config NR_QUICK
|
||||
int
|
||||
depends on QUICKLIST
|
||||
default "2" if SUPERH
|
||||
default "1"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user