Release 4.14 arch/mips/bcm63xx/irq.c
/*
* 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.
*
* Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
* Copyright (C) 2008 Nicolas Schichan <nschichan@freebox.fr>
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/spinlock.h>
#include <asm/irq_cpu.h>
#include <asm/mipsregs.h>
#include <bcm63xx_cpu.h>
#include <bcm63xx_regs.h>
#include <bcm63xx_io.h>
#include <bcm63xx_irq.h>
static DEFINE_SPINLOCK(ipic_lock);
static DEFINE_SPINLOCK(epic_lock);
static u32 irq_stat_addr[2];
static u32 irq_mask_addr[2];
static void (*dispatch_internal)(int cpu);
static int is_ext_irq_cascaded;
static unsigned int ext_irq_count;
static unsigned int ext_irq_start, ext_irq_end;
static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2;
static void (*internal_irq_mask)(struct irq_data *d);
static void (*internal_irq_unmask)(struct irq_data *d, const struct cpumask *m);
static inline u32 get_ext_irq_perf_reg(int irq)
{
if (irq < 4)
return ext_irq_cfg_reg1;
return ext_irq_cfg_reg2;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jonas Gorski | 22 | 100.00% | 1 | 100.00% |
Total | 22 | 100.00% | 1 | 100.00% |
static inline void handle_internal(int intbit)
{
if (is_ext_irq_cascaded &&
intbit >= ext_irq_start && intbit <= ext_irq_end)
do_IRQ(intbit - ext_irq_start + IRQ_EXTERNAL_BASE);
else
do_IRQ(intbit + IRQ_INTERNAL_BASE);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jonas Gorski | 37 | 94.87% | 1 | 50.00% |
Maxime Bizon | 2 | 5.13% | 1 | 50.00% |
Total | 39 | 100.00% | 2 | 100.00% |
static inline int enable_irq_for_cpu(int cpu, struct irq_data *d,
const struct cpumask *m)
{
bool enable = cpu_online(cpu);
#ifdef CONFIG_SMP
if (m)
enable &= cpumask_test_cpu(cpu, m);
else if (irqd_affinity_was_set(d))
enable &= cpumask_test_cpu(cpu, irq_data_get_affinity_mask(d));
#endif
return enable;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jonas Gorski | 65 | 92.86% | 1 | 33.33% |
Jiang Liu | 3 | 4.29% | 1 | 33.33% |
Rusty Russell | 2 | 2.86% | 1 | 33.33% |
Total | 70 | 100.00% | 3 | 100.00% |
/*
* dispatch internal devices IRQ (uart, enet, watchdog, ...). do not
* prioritize any interrupt relatively to another. the static counter
* will resume the loop where it ended the last time we left this
* function.
*/
#define BUILD_IPIC_INTERNAL(width) \
void __dispatch_internal_##width(int cpu) \
{ \
u32 pending[width / 32]; \
unsigned int src, tgt; \
bool irqs_pending = false; \
static unsigned int i[2]; \
unsigned int *next = &i[cpu]; \
unsigned long flags; \
\
/* read registers in reverse order */ \
spin_lock_irqsave(&ipic_lock, flags); \
for (src = 0, tgt = (width / 32); src < (width / 32); src++) { \
u32 val; \
\
val = bcm_readl(irq_stat_addr[cpu] + src * sizeof(u32)); \
val &= bcm_readl(irq_mask_addr[cpu] + src * sizeof(u32)); \
pending[--tgt] = val; \
\
if (val) \
irqs_pending = true; \
} \
spin_unlock_irqrestore(&ipic_lock, flags); \
\
if (!irqs_pending) \
return; \
\
while (1) { \
unsigned int to_call = *next; \
\
*next = (*next + 1) & (width - 1); \
if (pending[to_call / 32] & (1 << (to_call & 0x1f))) { \
handle_internal(to_call); \
break; \
} \
} \
} \
\
static void __internal_irq_mask_##width(struct irq_data *d) \
{ \
u32 val; \
unsigned irq = d->irq - IRQ_INTERNAL_BASE; \
unsigned reg = (irq / 32) ^ (width/32 - 1); \
unsigned bit = irq & 0x1f; \
unsigned long flags; \
int cpu; \
\
spin_lock_irqsave(&ipic_lock, flags); \
for_each_present_cpu(cpu) { \
if (!irq_mask_addr[cpu]) \
break; \
\
val = bcm_readl(irq_mask_addr[cpu] + reg * sizeof(u32));\
val &= ~(1 << bit); \
bcm_writel(val, irq_mask_addr[cpu] + reg * sizeof(u32));\
} \
spin_unlock_irqrestore(&ipic_lock, flags); \
} \
\
static void __internal_irq_unmask_##width(struct irq_data *d, \
const struct cpumask *m) \
{ \
u32 val; \
unsigned irq = d->irq - IRQ_INTERNAL_BASE; \
unsigned reg = (irq / 32) ^ (width/32 - 1); \
unsigned bit = irq & 0x1f; \
unsigned long flags; \
int cpu; \
\
spin_lock_irqsave(&ipic_lock, flags); \
for_each_present_cpu(cpu) { \
if (!irq_mask_addr[cpu]) \
break; \
\
val = bcm_readl(irq_mask_addr[cpu] + reg * sizeof(u32));\
if (enable_irq_for_cpu(cpu, d, m)) \
val |= (1 << bit); \
else \
val &= ~(1 << bit); \
bcm_writel(val, irq_mask_addr[cpu] + reg * sizeof(u32));\
} \
spin_unlock_irqrestore(&ipic_lock, flags); \
}
BUILD_IPIC_INTERNAL(32);
BUILD_IPIC_INTERNAL(64);
asmlinkage void plat_irq_dispatch(void)
{
u32 cause;
do {
cause = read_c0_cause() & read_c0_status() & ST0_IM;
if (!cause)
break;
if (cause & CAUSEF_IP7)
do_IRQ(7);
if (cause & CAUSEF_IP0)
do_IRQ(0);
if (cause & CAUSEF_IP1)
do_IRQ(1);
if (cause & CAUSEF_IP2)
dispatch_internal(0);
if (is_ext_irq_cascaded) {
if (cause & CAUSEF_IP3)
dispatch_internal(1);
} else {
if (cause & CAUSEF_IP3)
do_IRQ(IRQ_EXT_0);
if (cause & CAUSEF_IP4)
do_IRQ(IRQ_EXT_1);
if (cause & CAUSEF_IP5)
do_IRQ(IRQ_EXT_2);
if (cause & CAUSEF_IP6)
do_IRQ(IRQ_EXT_3);
}
} while (1);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jonas Gorski | 135 | 94.41% | 4 | 50.00% |
Maxime Bizon | 8 | 5.59% | 4 | 50.00% |
Total | 143 | 100.00% | 8 | 100.00% |
/*
* internal IRQs operations: only mask/unmask on PERF irq mask
* register.
*/
static void bcm63xx_internal_irq_mask(struct irq_data *d)
{
internal_irq_mask(d);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jonas Gorski | 11 | 68.75% | 1 | 50.00% |
Maxime Bizon | 5 | 31.25% | 1 | 50.00% |
Total | 16 | 100.00% | 2 | 100.00% |
static void bcm63xx_internal_irq_unmask(struct irq_data *d)
{
internal_irq_unmask(d, NULL);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jonas Gorski | 9 | 50.00% | 2 | 50.00% |
Maxime Bizon | 9 | 50.00% | 2 | 50.00% |
Total | 18 | 100.00% | 4 | 100.00% |
/*
* external IRQs operations: mask/unmask and clear on PERF external
* irq control register.
*/
static void bcm63xx_external_irq_mask(struct irq_data *d)
{
unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
u32 reg, regaddr;
unsigned long flags;
regaddr = get_ext_irq_perf_reg(irq);
spin_lock_irqsave(&epic_lock, flags);
reg = bcm_perf_readl(regaddr);
if (BCMCPU_IS_6348())
reg &= ~EXTIRQ_CFG_MASK_6348(irq % 4);
else
reg &= ~EXTIRQ_CFG_MASK(irq % 4);
bcm_perf_writel(reg, regaddr);
spin_unlock_irqrestore(&epic_lock, flags);
if (is_ext_irq_cascaded)
internal_irq_mask(irq_get_irq_data(irq + ext_irq_start));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jonas Gorski | 89 | 83.18% | 3 | 75.00% |
Maxime Bizon | 18 | 16.82% | 1 | 25.00% |
Total | 107 | 100.00% | 4 | 100.00% |
static void bcm63xx_external_irq_unmask(struct irq_data *d)
{
unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
u32 reg, regaddr;
unsigned long flags;
regaddr = get_ext_irq_perf_reg(irq);
spin_lock_irqsave(&epic_lock, flags);
reg = bcm_perf_readl(regaddr);
if (BCMCPU_IS_6348())
reg |= EXTIRQ_CFG_MASK_6348(irq % 4);
else
reg |= EXTIRQ_CFG_MASK(irq % 4);
bcm_perf_writel(reg, regaddr);
spin_unlock_irqrestore(&epic_lock, flags);
if (is_ext_irq_cascaded)
internal_irq_unmask(irq_get_irq_data(irq + ext_irq_start),
NULL);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jonas Gorski | 94 | 87.85% | 4 | 80.00% |
Maxime Bizon | 13 | 12.15% | 1 | 20.00% |
Total | 107 | 100.00% | 5 | 100.00% |
static void bcm63xx_external_irq_clear(struct irq_data *d)
{
unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
u32 reg, regaddr;
unsigned long flags;
regaddr = get_ext_irq_perf_reg(irq);
spin_lock_irqsave(&epic_lock, flags);
reg = bcm_perf_readl(regaddr);
if (BCMCPU_IS_6348())
reg |= EXTIRQ_CFG_CLEAR_6348(irq % 4);
else
reg |= EXTIRQ_CFG_CLEAR(irq % 4);
bcm_perf_writel(reg, regaddr);
spin_unlock_irqrestore(&epic_lock, flags);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jonas Gorski | 70 | 76.92% | 2 | 66.67% |
Maxime Bizon | 21 | 23.08% | 1 | 33.33% |
Total | 91 | 100.00% | 3 | 100.00% |
static int bcm63xx_external_irq_set_type(struct irq_data *d,
unsigned int flow_type)
{
unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
u32 reg, regaddr;
int levelsense, sense, bothedge;
unsigned long flags;
flow_type &= IRQ_TYPE_SENSE_MASK;
if (flow_type == IRQ_TYPE_NONE)
flow_type = IRQ_TYPE_LEVEL_LOW;
levelsense = sense = bothedge = 0;
switch (flow_type) {
case IRQ_TYPE_EDGE_BOTH:
bothedge = 1;
break;
case IRQ_TYPE_EDGE_RISING:
sense = 1;
break;
case IRQ_TYPE_EDGE_FALLING:
break;
case IRQ_TYPE_LEVEL_HIGH:
levelsense = 1;
sense = 1;
break;
case IRQ_TYPE_LEVEL_LOW:
levelsense = 1;
break;
default:
pr_err("bogus flow type combination given !\n");
return -EINVAL;
}
regaddr = get_ext_irq_perf_reg(irq);
spin_lock_irqsave(&epic_lock, flags);
reg = bcm_perf_readl(regaddr);
irq %= 4;
switch (bcm63xx_get_cpu_id()) {
case BCM6348_CPU_ID:
if (levelsense)
reg |= EXTIRQ_CFG_LEVELSENSE_6348(irq);
else
reg &= ~EXTIRQ_CFG_LEVELSENSE_6348(irq);
if (sense)
reg |= EXTIRQ_CFG_SENSE_6348(irq);
else
reg &= ~EXTIRQ_CFG_SENSE_6348(irq);
if (bothedge)
reg |= EXTIRQ_CFG_BOTHEDGE_6348(irq);
else
reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq);
break;
case BCM3368_CPU_ID:
case BCM6328_CPU_ID:
case BCM6338_CPU_ID:
case BCM6345_CPU_ID:
case BCM6358_CPU_ID:
case BCM6362_CPU_ID:
case BCM6368_CPU_ID:
if (levelsense)
reg |= EXTIRQ_CFG_LEVELSENSE(irq);
else
reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
if (sense)
reg |= EXTIRQ_CFG_SENSE(irq);
else
reg &= ~EXTIRQ_CFG_SENSE(irq);
if (bothedge)
reg |= EXTIRQ_CFG_BOTHEDGE(irq);
else
reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
break;
default:
BUG();
}
bcm_perf_writel(reg, regaddr);
spin_unlock_irqrestore(&epic_lock, flags);
irqd_set_trigger_type(d, flow_type);
if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
irq_set_handler_locked(d, handle_level_irq);
else
irq_set_handler_locked(d, handle_edge_irq);
return IRQ_SET_MASK_OK_NOCOPY;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jonas Gorski | 247 | 70.17% | 2 | 22.22% |
Maxime Bizon | 96 | 27.27% | 4 | 44.44% |
Kevin Cernekee | 6 | 1.70% | 1 | 11.11% |
Thomas Gleixner | 2 | 0.57% | 1 | 11.11% |
Gregory Fong | 1 | 0.28% | 1 | 11.11% |
Total | 352 | 100.00% | 9 | 100.00% |
#ifdef CONFIG_SMP
static int bcm63xx_internal_set_affinity(struct irq_data *data,
const struct cpumask *dest,
bool force)
{
if (!irqd_irq_disabled(data))
internal_irq_unmask(data, dest);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jonas Gorski | 38 | 100.00% | 1 | 100.00% |
Total | 38 | 100.00% | 1 | 100.00% |
#endif
static struct irq_chip bcm63xx_internal_irq_chip = {
.name = "bcm63xx_ipic",
.irq_mask = bcm63xx_internal_irq_mask,
.irq_unmask = bcm63xx_internal_irq_unmask,
};
static struct irq_chip bcm63xx_external_irq_chip = {
.name = "bcm63xx_epic",
.irq_ack = bcm63xx_external_irq_clear,
.irq_mask = bcm63xx_external_irq_mask,
.irq_unmask = bcm63xx_external_irq_unmask,
.irq_set_type = bcm63xx_external_irq_set_type,
};
static struct irqaction cpu_ip2_cascade_action = {
.handler = no_action,
.name = "cascade_ip2",
.flags = IRQF_NO_THREAD,
};
#ifdef CONFIG_SMP
static struct irqaction cpu_ip3_cascade_action = {
.handler = no_action,
.name = "cascade_ip3",
.flags = IRQF_NO_THREAD,
};
#endif
static struct irqaction cpu_ext_cascade_action = {
.handler = no_action,
.name = "cascade_extirq",
.flags = IRQF_NO_THREAD,
};
static void bcm63xx_init_irq(void)
{
int irq_bits;
irq_stat_addr[0] = bcm63xx_regset_address(RSET_PERF);
irq_mask_addr[0] = bcm63xx_regset_address(RSET_PERF);
irq_stat_addr[1] = bcm63xx_regset_address(RSET_PERF);
irq_mask_addr[1] = bcm63xx_regset_address(RSET_PERF);
switch (bcm63xx_get_cpu_id()) {
case BCM3368_CPU_ID:
irq_stat_addr[0] += PERF_IRQSTAT_3368_REG;
irq_mask_addr[0] += PERF_IRQMASK_3368_REG;
irq_stat_addr[1] = 0;
irq_mask_addr[1] = 0;
irq_bits = 32;
ext_irq_count = 4;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_3368;
break;
case BCM6328_CPU_ID:
irq_stat_addr[0] += PERF_IRQSTAT_6328_REG(0);
irq_mask_addr[0] += PERF_IRQMASK_6328_REG(0);
irq_stat_addr[1] += PERF_IRQSTAT_6328_REG(1);
irq_mask_addr[1] += PERF_IRQMASK_6328_REG(1);
irq_bits = 64;
ext_irq_count = 4;
is_ext_irq_cascaded = 1;
ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE;
ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328;
break;
case BCM6338_CPU_ID:
irq_stat_addr[0] += PERF_IRQSTAT_6338_REG;
irq_mask_addr[0] += PERF_IRQMASK_6338_REG;
irq_stat_addr[1] = 0;
irq_mask_addr[1] = 0;
irq_bits = 32;
ext_irq_count = 4;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6338;
break;
case BCM6345_CPU_ID:
irq_stat_addr[0] += PERF_IRQSTAT_6345_REG;
irq_mask_addr[0] += PERF_IRQMASK_6345_REG;
irq_stat_addr[1] = 0;
irq_mask_addr[1] = 0;
irq_bits = 32;
ext_irq_count = 4;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6345;
break;
case BCM6348_CPU_ID:
irq_stat_addr[0] += PERF_IRQSTAT_6348_REG;
irq_mask_addr[0] += PERF_IRQMASK_6348_REG;
irq_stat_addr[1] = 0;
irq_mask_addr[1] = 0;
irq_bits = 32;
ext_irq_count = 4;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348;
break;
case BCM6358_CPU_ID:
irq_stat_addr[0] += PERF_IRQSTAT_6358_REG(0);
irq_mask_addr[0] += PERF_IRQMASK_6358_REG(0);
irq_stat_addr[1] += PERF_IRQSTAT_6358_REG(1);
irq_mask_addr[1] += PERF_IRQMASK_6358_REG(1);
irq_bits = 32;
ext_irq_count = 4;
is_ext_irq_cascaded = 1;
ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE;
ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358;
break;
case BCM6362_CPU_ID:
irq_stat_addr[0] += PERF_IRQSTAT_6362_REG(0);
irq_mask_addr[0] += PERF_IRQMASK_6362_REG(0);
irq_stat_addr[1] += PERF_IRQSTAT_6362_REG(1);
irq_mask_addr[1] += PERF_IRQMASK_6362_REG(1);
irq_bits = 64;
ext_irq_count = 4;
is_ext_irq_cascaded = 1;
ext_irq_start = BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE;
ext_irq_end = BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6362;
break;
case BCM6368_CPU_ID:
irq_stat_addr[0] += PERF_IRQSTAT_6368_REG(0);
irq_mask_addr[0] += PERF_IRQMASK_6368_REG(0);
irq_stat_addr[1] += PERF_IRQSTAT_6368_REG(1);
irq_mask_addr[1] += PERF_IRQMASK_6368_REG(1);
irq_bits = 64;
ext_irq_count = 6;
is_ext_irq_cascaded = 1;
ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE;
ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368;
ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368;
break;
default:
BUG();
}
if (irq_bits == 32) {
dispatch_internal = __dispatch_internal_32;
internal_irq_mask = __internal_irq_mask_32;
internal_irq_unmask = __internal_irq_unmask_32;
} else {
dispatch_internal = __dispatch_internal_64;
internal_irq_mask = __internal_irq_mask_64;
internal_irq_unmask = __internal_irq_unmask_64;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jonas Gorski | 468 | 82.83% | 3 | 30.00% |
Maxime Bizon | 91 | 16.11% | 4 | 40.00% |
Thomas Gleixner | 3 | 0.53% | 1 | 10.00% |
Julia Lawall | 2 | 0.35% | 1 | 10.00% |
Wu Zhangjin | 1 | 0.18% | 1 | 10.00% |
Total | 565 | 100.00% | 10 | 100.00% |
void __init arch_init_irq(void)
{
int i;
bcm63xx_init_irq();
mips_cpu_irq_init();
for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i)
irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip,
handle_level_irq);
for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + ext_irq_count; ++i)
irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip,
handle_edge_irq);
if (!is_ext_irq_cascaded) {
for (i = 3; i < 3 + ext_irq_count; ++i)
setup_irq(MIPS_CPU_IRQ_BASE + i, &cpu_ext_cascade_action);
}
setup_irq(MIPS_CPU_IRQ_BASE + 2, &cpu_ip2_cascade_action);
#ifdef CONFIG_SMP
if (is_ext_irq_cascaded) {
setup_irq(MIPS_CPU_IRQ_BASE + 3, &cpu_ip3_cascade_action);
bcm63xx_internal_irq_chip.irq_set_affinity =
bcm63xx_internal_set_affinity;
cpumask_clear(irq_default_affinity);
cpumask_set_cpu(smp_processor_id(), irq_default_affinity);
}
#endif
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Maxime Bizon | 105 | 71.43% | 4 | 57.14% |
Jonas Gorski | 40 | 27.21% | 2 | 28.57% |
Thomas Gleixner | 2 | 1.36% | 1 | 14.29% |
Total | 147 | 100.00% | 7 | 100.00% |
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jonas Gorski | 1514 | 75.93% | 10 | 35.71% |
Maxime Bizon | 454 | 22.77% | 7 | 25.00% |
Thomas Gleixner | 7 | 0.35% | 3 | 10.71% |
Kevin Cernekee | 6 | 0.30% | 1 | 3.57% |
David Howells | 3 | 0.15% | 1 | 3.57% |
Jiang Liu | 3 | 0.15% | 1 | 3.57% |
Julia Lawall | 2 | 0.10% | 1 | 3.57% |
Rusty Russell | 2 | 0.10% | 1 | 3.57% |
Florian Fainelli | 1 | 0.05% | 1 | 3.57% |
Gregory Fong | 1 | 0.05% | 1 | 3.57% |
Wu Zhangjin | 1 | 0.05% | 1 | 3.57% |
Total | 1994 | 100.00% | 28 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.