forked from luck/tmp_suning_uos_patched
Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus: Staging: octeon-ethernet: Fix race freeing transmit buffers. Staging: octeon-ethernet: Convert to use net_device_ops. MIPS: Cavium: Add CPU hotplugging code. MIPS: SMP: Allow suspend and hibernation if CPU hotplug is available MIPS: Add arch generic CPU hotplug DMA: txx9dmac: use dma_unmap_single if DMA_COMPL_{SRC,DEST}_UNMAP_SINGLE set MIPS: Sibyte: Fix build error if CONFIG_SERIAL_SB1250_DUART is undefined. MIPS: MIPSsim: Fix build error if MSC01E_INT_BASE is undefined. MIPS: Hibernation: Remove SMP TLB and cacheflushing code. MIPS: Build fix - include <linux/smp.h> into all smp_processor_id() users. MIPS: bug.h Build fix - include <linux/compiler.h>.
This commit is contained in:
commit
c82e6d450f
|
@ -601,6 +601,7 @@ config CAVIUM_OCTEON_SIMULATOR
|
|||
select SYS_SUPPORTS_64BIT_KERNEL
|
||||
select SYS_SUPPORTS_BIG_ENDIAN
|
||||
select SYS_SUPPORTS_HIGHMEM
|
||||
select SYS_SUPPORTS_HOTPLUG_CPU
|
||||
select SYS_HAS_CPU_CAVIUM_OCTEON
|
||||
help
|
||||
The Octeon simulator is software performance model of the Cavium
|
||||
|
@ -615,6 +616,7 @@ config CAVIUM_OCTEON_REFERENCE_BOARD
|
|||
select SYS_SUPPORTS_64BIT_KERNEL
|
||||
select SYS_SUPPORTS_BIG_ENDIAN
|
||||
select SYS_SUPPORTS_HIGHMEM
|
||||
select SYS_SUPPORTS_HOTPLUG_CPU
|
||||
select SYS_HAS_EARLY_PRINTK
|
||||
select SYS_HAS_CPU_CAVIUM_OCTEON
|
||||
select SWAP_IO_SPACE
|
||||
|
@ -784,8 +786,17 @@ config SYS_HAS_EARLY_PRINTK
|
|||
bool
|
||||
|
||||
config HOTPLUG_CPU
|
||||
bool "Support for hot-pluggable CPUs"
|
||||
depends on SMP && HOTPLUG && SYS_SUPPORTS_HOTPLUG_CPU
|
||||
help
|
||||
Say Y here to allow turning CPUs off and on. CPUs can be
|
||||
controlled through /sys/devices/system/cpu.
|
||||
(Note: power management support will enable this option
|
||||
automatically on SMP systems. )
|
||||
Say N if you want to disable CPU hotplug.
|
||||
|
||||
config SYS_SUPPORTS_HOTPLUG_CPU
|
||||
bool
|
||||
default n
|
||||
|
||||
config I8259
|
||||
bool
|
||||
|
@ -2136,11 +2147,11 @@ menu "Power management options"
|
|||
|
||||
config ARCH_HIBERNATION_POSSIBLE
|
||||
def_bool y
|
||||
depends on !SMP
|
||||
depends on SYS_SUPPORTS_HOTPLUG_CPU
|
||||
|
||||
config ARCH_SUSPEND_POSSIBLE
|
||||
def_bool y
|
||||
depends on !SMP
|
||||
depends on SYS_SUPPORTS_HOTPLUG_CPU
|
||||
|
||||
source "kernel/power/Kconfig"
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/octeon/octeon.h>
|
||||
#include <asm/octeon/cvmx-pexp-defs.h>
|
||||
|
@ -501,3 +501,62 @@ asmlinkage void plat_irq_dispatch(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static int is_irq_enabled_on_cpu(unsigned int irq, unsigned int cpu)
|
||||
{
|
||||
unsigned int isset;
|
||||
#ifdef CONFIG_SMP
|
||||
int coreid = cpu_logical_map(cpu);
|
||||
#else
|
||||
int coreid = cvmx_get_core_num();
|
||||
#endif
|
||||
int bit = (irq < OCTEON_IRQ_WDOG0) ?
|
||||
irq - OCTEON_IRQ_WORKQ0 : irq - OCTEON_IRQ_WDOG0;
|
||||
if (irq < 64) {
|
||||
isset = (cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2)) &
|
||||
(1ull << bit)) >> bit;
|
||||
} else {
|
||||
isset = (cvmx_read_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1)) &
|
||||
(1ull << bit)) >> bit;
|
||||
}
|
||||
return isset;
|
||||
}
|
||||
|
||||
void fixup_irqs(void)
|
||||
{
|
||||
int irq;
|
||||
|
||||
for (irq = OCTEON_IRQ_SW0; irq <= OCTEON_IRQ_TIMER; irq++)
|
||||
octeon_irq_core_disable_local(irq);
|
||||
|
||||
for (irq = OCTEON_IRQ_WORKQ0; irq <= OCTEON_IRQ_GPIO15; irq++) {
|
||||
if (is_irq_enabled_on_cpu(irq, smp_processor_id())) {
|
||||
/* ciu irq migrates to next cpu */
|
||||
octeon_irq_chip_ciu0.disable(irq);
|
||||
octeon_irq_ciu0_set_affinity(irq, &cpu_online_map);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (irq = OCTEON_IRQ_MBOX0; irq <= OCTEON_IRQ_MBOX1; irq++)
|
||||
octeon_irq_mailbox_mask(irq);
|
||||
#endif
|
||||
for (irq = OCTEON_IRQ_UART0; irq <= OCTEON_IRQ_BOOTDMA; irq++) {
|
||||
if (is_irq_enabled_on_cpu(irq, smp_processor_id())) {
|
||||
/* ciu irq migrates to next cpu */
|
||||
octeon_irq_chip_ciu0.disable(irq);
|
||||
octeon_irq_ciu0_set_affinity(irq, &cpu_online_map);
|
||||
}
|
||||
}
|
||||
|
||||
for (irq = OCTEON_IRQ_UART2; irq <= OCTEON_IRQ_RESERVED135; irq++) {
|
||||
if (is_irq_enabled_on_cpu(irq, smp_processor_id())) {
|
||||
/* ciu irq migrates to next cpu */
|
||||
octeon_irq_chip_ciu1.disable(irq);
|
||||
octeon_irq_ciu1_set_affinity(irq, &cpu_online_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_HOTPLUG_CPU */
|
||||
|
|
70
arch/mips/cavium-octeon/octeon_boot.h
Normal file
70
arch/mips/cavium-octeon/octeon_boot.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* (C) Copyright 2004, 2005 Cavium Networks
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __OCTEON_BOOT_H__
|
||||
#define __OCTEON_BOOT_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct boot_init_vector {
|
||||
uint32_t stack_addr;
|
||||
uint32_t code_addr;
|
||||
uint32_t app_start_func_addr;
|
||||
uint32_t k0_val;
|
||||
uint32_t flags;
|
||||
uint32_t boot_info_addr;
|
||||
uint32_t pad;
|
||||
uint32_t pad2;
|
||||
};
|
||||
|
||||
/* similar to bootloader's linux_app_boot_info but without global data */
|
||||
struct linux_app_boot_info {
|
||||
uint32_t labi_signature;
|
||||
uint32_t start_core0_addr;
|
||||
uint32_t avail_coremask;
|
||||
uint32_t pci_console_active;
|
||||
uint32_t icache_prefetch_disable;
|
||||
uint32_t InitTLBStart_addr;
|
||||
uint32_t start_app_addr;
|
||||
uint32_t cur_exception_base;
|
||||
uint32_t no_mark_private_data;
|
||||
uint32_t compact_flash_common_base_addr;
|
||||
uint32_t compact_flash_attribute_base_addr;
|
||||
uint32_t led_display_base_addr;
|
||||
};
|
||||
|
||||
/* If not to copy a lot of bootloader's structures
|
||||
here is only offset of requested member */
|
||||
#define AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK 0x765c
|
||||
|
||||
/* hardcoded in bootloader */
|
||||
#define LABI_ADDR_IN_BOOTLOADER 0x700
|
||||
|
||||
#define LINUX_APP_BOOT_BLOCK_NAME "linux-app-boot"
|
||||
|
||||
#define LABI_SIGNATURE 0xAABBCCDD
|
||||
|
||||
/* from uboot-headers/octeon_mem_map.h */
|
||||
#define EXCEPTION_BASE_INCR (4 * 1024)
|
||||
/* Increment size for exception base addresses (4k minimum) */
|
||||
#define EXCEPTION_BASE_BASE 0
|
||||
#define BOOTLOADER_PRIV_DATA_BASE (EXCEPTION_BASE_BASE + 0x800)
|
||||
#define BOOTLOADER_BOOT_VECTOR (BOOTLOADER_PRIV_DATA_BASE)
|
||||
|
||||
#endif /* __OCTEON_BOOT_H__ */
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h> /* for memset */
|
||||
#include <linux/tty.h>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*
|
||||
* Copyright (C) 2004-2008 Cavium Networks
|
||||
*/
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/smp.h>
|
||||
|
@ -19,10 +20,16 @@
|
|||
|
||||
#include <asm/octeon/octeon.h>
|
||||
|
||||
#include "octeon_boot.h"
|
||||
|
||||
volatile unsigned long octeon_processor_boot = 0xff;
|
||||
volatile unsigned long octeon_processor_sp;
|
||||
volatile unsigned long octeon_processor_gp;
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static unsigned int InitTLBStart_addr;
|
||||
#endif
|
||||
|
||||
static irqreturn_t mailbox_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
const int coreid = cvmx_get_core_num();
|
||||
|
@ -67,8 +74,28 @@ static inline void octeon_send_ipi_mask(cpumask_t mask, unsigned int action)
|
|||
}
|
||||
|
||||
/**
|
||||
* Detect available CPUs, populate phys_cpu_present_map
|
||||
* Detect available CPUs, populate cpu_possible_map
|
||||
*/
|
||||
static void octeon_smp_hotplug_setup(void)
|
||||
{
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
uint32_t labi_signature;
|
||||
|
||||
labi_signature =
|
||||
cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
|
||||
LABI_ADDR_IN_BOOTLOADER +
|
||||
offsetof(struct linux_app_boot_info,
|
||||
labi_signature)));
|
||||
if (labi_signature != LABI_SIGNATURE)
|
||||
pr_err("The bootloader version on this board is incorrect\n");
|
||||
InitTLBStart_addr =
|
||||
cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
|
||||
LABI_ADDR_IN_BOOTLOADER +
|
||||
offsetof(struct linux_app_boot_info,
|
||||
InitTLBStart_addr)));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void octeon_smp_setup(void)
|
||||
{
|
||||
const int coreid = cvmx_get_core_num();
|
||||
|
@ -91,6 +118,9 @@ static void octeon_smp_setup(void)
|
|||
cpus++;
|
||||
}
|
||||
}
|
||||
cpu_present_map = cpu_possible_map;
|
||||
|
||||
octeon_smp_hotplug_setup();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,6 +158,17 @@ static void octeon_init_secondary(void)
|
|||
const int coreid = cvmx_get_core_num();
|
||||
union cvmx_ciu_intx_sum0 interrupt_enable;
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
unsigned int cur_exception_base;
|
||||
|
||||
cur_exception_base = cvmx_read64_uint32(
|
||||
CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
|
||||
LABI_ADDR_IN_BOOTLOADER +
|
||||
offsetof(struct linux_app_boot_info,
|
||||
cur_exception_base)));
|
||||
/* cur_exception_base is incremented in bootloader after setting */
|
||||
write_c0_ebase((unsigned int)(cur_exception_base - EXCEPTION_BASE_INCR));
|
||||
#endif
|
||||
octeon_check_cpu_bist();
|
||||
octeon_init_cvmcount();
|
||||
/*
|
||||
|
@ -199,6 +240,193 @@ static void octeon_cpus_done(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
|
||||
/* State of each CPU. */
|
||||
DEFINE_PER_CPU(int, cpu_state);
|
||||
|
||||
extern void fixup_irqs(void);
|
||||
|
||||
static DEFINE_SPINLOCK(smp_reserve_lock);
|
||||
|
||||
static int octeon_cpu_disable(void)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
|
||||
if (cpu == 0)
|
||||
return -EBUSY;
|
||||
|
||||
spin_lock(&smp_reserve_lock);
|
||||
|
||||
cpu_clear(cpu, cpu_online_map);
|
||||
cpu_clear(cpu, cpu_callin_map);
|
||||
local_irq_disable();
|
||||
fixup_irqs();
|
||||
local_irq_enable();
|
||||
|
||||
flush_cache_all();
|
||||
local_flush_tlb_all();
|
||||
|
||||
spin_unlock(&smp_reserve_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void octeon_cpu_die(unsigned int cpu)
|
||||
{
|
||||
int coreid = cpu_logical_map(cpu);
|
||||
uint32_t avail_coremask;
|
||||
struct cvmx_bootmem_named_block_desc *block_desc;
|
||||
|
||||
#ifdef CONFIG_CAVIUM_OCTEON_WATCHDOG
|
||||
/* Disable the watchdog */
|
||||
cvmx_ciu_wdogx_t ciu_wdog;
|
||||
ciu_wdog.u64 = cvmx_read_csr(CVMX_CIU_WDOGX(cpu));
|
||||
ciu_wdog.s.mode = 0;
|
||||
cvmx_write_csr(CVMX_CIU_WDOGX(cpu), ciu_wdog.u64);
|
||||
#endif
|
||||
|
||||
while (per_cpu(cpu_state, cpu) != CPU_DEAD)
|
||||
cpu_relax();
|
||||
|
||||
/*
|
||||
* This is a bit complicated strategics of getting/settig available
|
||||
* cores mask, copied from bootloader
|
||||
*/
|
||||
/* LINUX_APP_BOOT_BLOCK is initialized in bootoct binary */
|
||||
block_desc = cvmx_bootmem_find_named_block(LINUX_APP_BOOT_BLOCK_NAME);
|
||||
|
||||
if (!block_desc) {
|
||||
avail_coremask =
|
||||
cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
|
||||
LABI_ADDR_IN_BOOTLOADER +
|
||||
offsetof
|
||||
(struct linux_app_boot_info,
|
||||
avail_coremask)));
|
||||
} else { /* alternative, already initialized */
|
||||
avail_coremask =
|
||||
cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
|
||||
block_desc->base_addr +
|
||||
AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK));
|
||||
}
|
||||
|
||||
avail_coremask |= 1 << coreid;
|
||||
|
||||
/* Setting avail_coremask for bootoct binary */
|
||||
if (!block_desc) {
|
||||
cvmx_write64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
|
||||
LABI_ADDR_IN_BOOTLOADER +
|
||||
offsetof(struct linux_app_boot_info,
|
||||
avail_coremask)),
|
||||
avail_coremask);
|
||||
} else {
|
||||
cvmx_write64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
|
||||
block_desc->base_addr +
|
||||
AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK),
|
||||
avail_coremask);
|
||||
}
|
||||
|
||||
pr_info("Reset core %d. Available Coremask = %x \n", coreid,
|
||||
avail_coremask);
|
||||
cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid);
|
||||
cvmx_write_csr(CVMX_CIU_PP_RST, 0);
|
||||
}
|
||||
|
||||
void play_dead(void)
|
||||
{
|
||||
int coreid = cvmx_get_core_num();
|
||||
|
||||
idle_task_exit();
|
||||
octeon_processor_boot = 0xff;
|
||||
per_cpu(cpu_state, coreid) = CPU_DEAD;
|
||||
|
||||
while (1) /* core will be reset here */
|
||||
;
|
||||
}
|
||||
|
||||
extern void kernel_entry(unsigned long arg1, ...);
|
||||
|
||||
static void start_after_reset(void)
|
||||
{
|
||||
kernel_entry(0, 0, 0); /* set a2 = 0 for secondary core */
|
||||
}
|
||||
|
||||
int octeon_update_boot_vector(unsigned int cpu)
|
||||
{
|
||||
|
||||
int coreid = cpu_logical_map(cpu);
|
||||
unsigned int avail_coremask;
|
||||
struct cvmx_bootmem_named_block_desc *block_desc;
|
||||
struct boot_init_vector *boot_vect =
|
||||
(struct boot_init_vector *) cvmx_phys_to_ptr(0x0 +
|
||||
BOOTLOADER_BOOT_VECTOR);
|
||||
|
||||
block_desc = cvmx_bootmem_find_named_block(LINUX_APP_BOOT_BLOCK_NAME);
|
||||
|
||||
if (!block_desc) {
|
||||
avail_coremask =
|
||||
cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
|
||||
LABI_ADDR_IN_BOOTLOADER +
|
||||
offsetof(struct linux_app_boot_info,
|
||||
avail_coremask)));
|
||||
} else { /* alternative, already initialized */
|
||||
avail_coremask =
|
||||
cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
|
||||
block_desc->base_addr +
|
||||
AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK));
|
||||
}
|
||||
|
||||
if (!(avail_coremask & (1 << coreid))) {
|
||||
/* core not available, assume, that catched by simple-executive */
|
||||
cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid);
|
||||
cvmx_write_csr(CVMX_CIU_PP_RST, 0);
|
||||
}
|
||||
|
||||
boot_vect[coreid].app_start_func_addr =
|
||||
(uint32_t) (unsigned long) start_after_reset;
|
||||
boot_vect[coreid].code_addr = InitTLBStart_addr;
|
||||
|
||||
CVMX_SYNC;
|
||||
|
||||
cvmx_write_csr(CVMX_CIU_NMI, (1 << coreid) & avail_coremask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __cpuinit octeon_cpu_callback(struct notifier_block *nfb,
|
||||
unsigned long action, void *hcpu)
|
||||
{
|
||||
unsigned int cpu = (unsigned long)hcpu;
|
||||
|
||||
switch (action) {
|
||||
case CPU_UP_PREPARE:
|
||||
octeon_update_boot_vector(cpu);
|
||||
break;
|
||||
case CPU_ONLINE:
|
||||
pr_info("Cpu %d online\n", cpu);
|
||||
break;
|
||||
case CPU_DEAD:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block __cpuinitdata octeon_cpu_notifier = {
|
||||
.notifier_call = octeon_cpu_callback,
|
||||
};
|
||||
|
||||
static int __cpuinit register_cavium_notifier(void)
|
||||
{
|
||||
register_hotcpu_notifier(&octeon_cpu_notifier);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
late_initcall(register_cavium_notifier);
|
||||
|
||||
#endif /* CONFIG_HOTPLUG_CPU */
|
||||
|
||||
struct plat_smp_ops octeon_smp_ops = {
|
||||
.send_ipi_single = octeon_send_ipi_single,
|
||||
.send_ipi_mask = octeon_send_ipi_mask,
|
||||
|
@ -208,4 +436,8 @@ struct plat_smp_ops octeon_smp_ops = {
|
|||
.boot_secondary = octeon_boot_secondary,
|
||||
.smp_setup = octeon_smp_setup,
|
||||
.prepare_cpus = octeon_prepare_cpus,
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
.cpu_disable = octeon_cpu_disable,
|
||||
.cpu_die = octeon_cpu_die,
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef __ASM_BUG_H
|
||||
#define __ASM_BUG_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/sgidefs.h>
|
||||
|
||||
#ifdef CONFIG_BUG
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cpu-info.h>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define _ASM_IRQ_H
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/mipsmtregs.h>
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
|
|
@ -26,6 +26,10 @@ struct plat_smp_ops {
|
|||
void (*boot_secondary)(int cpu, struct task_struct *idle);
|
||||
void (*smp_setup)(void);
|
||||
void (*prepare_cpus)(unsigned int max_cpus);
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
int (*cpu_disable)(void);
|
||||
void (*cpu_die)(unsigned int cpu);
|
||||
#endif
|
||||
};
|
||||
|
||||
extern void register_smp_ops(struct plat_smp_ops *ops);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/threads.h>
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
|
@ -40,6 +41,7 @@ extern int __cpu_logical_map[NR_CPUS];
|
|||
/* Octeon - Tell another core to flush its icache */
|
||||
#define SMP_ICACHE_FLUSH 0x4
|
||||
|
||||
extern volatile cpumask_t cpu_callin_map;
|
||||
|
||||
extern void asmlinkage smp_bootstrap(void);
|
||||
|
||||
|
@ -55,6 +57,24 @@ static inline void smp_send_reschedule(int cpu)
|
|||
mp_ops->send_ipi_single(cpu, SMP_RESCHEDULE_YOURSELF);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static inline int __cpu_disable(void)
|
||||
{
|
||||
extern struct plat_smp_ops *mp_ops; /* private */
|
||||
|
||||
return mp_ops->cpu_disable();
|
||||
}
|
||||
|
||||
static inline void __cpu_die(unsigned int cpu)
|
||||
{
|
||||
extern struct plat_smp_ops *mp_ops; /* private */
|
||||
|
||||
mp_ops->cpu_die(cpu);
|
||||
}
|
||||
|
||||
extern void play_dead(void);
|
||||
#endif
|
||||
|
||||
extern asmlinkage void smp_call_function_interrupt(void);
|
||||
|
||||
extern void arch_send_call_function_single_ipi(int cpu);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <linux/smp.h>
|
||||
#include <linux/types.h>
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <asm/irq_cpu.h>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/clockchips.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/io.h>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/clockchips.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/smtc_ipi.h>
|
||||
#include <asm/time.h>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/clockchips.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/io.h>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/clockchips.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/smtc_ipi.h>
|
||||
#include <asm/time.h>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/stddef.h>
|
||||
|
||||
#include <asm/bugs.h>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <asm/delay.h>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/gic.h>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/kgdb.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <asm/inst.h>
|
||||
#include <asm/fpu.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
|
|
@ -50,10 +50,15 @@
|
|||
*/
|
||||
void __noreturn cpu_idle(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
/* CPU is going idle. */
|
||||
cpu = smp_processor_id();
|
||||
|
||||
/* endless idle loop with no priority at all */
|
||||
while (1) {
|
||||
tick_nohz_stop_sched_tick(1);
|
||||
while (!need_resched()) {
|
||||
while (!need_resched() && cpu_online(cpu)) {
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
extern void smtc_idle_loop_hook(void);
|
||||
|
||||
|
@ -62,6 +67,12 @@ void __noreturn cpu_idle(void)
|
|||
if (cpu_wait)
|
||||
(*cpu_wait)();
|
||||
}
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
if (!cpu_online(cpu) && !cpu_isset(cpu, cpu_callin_map) &&
|
||||
(system_state == SYSTEM_RUNNING ||
|
||||
system_state == SYSTEM_BOOTING))
|
||||
play_dead();
|
||||
#endif
|
||||
tick_nohz_restart_sched_tick();
|
||||
preempt_enable_no_resched();
|
||||
schedule();
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/compiler.h>
|
||||
|
|
|
@ -55,6 +55,18 @@ static void __init up_prepare_cpus(unsigned int max_cpus)
|
|||
{
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static int up_cpu_disable(void)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static void up_cpu_die(unsigned int cpu)
|
||||
{
|
||||
BUG();
|
||||
}
|
||||
#endif
|
||||
|
||||
struct plat_smp_ops up_smp_ops = {
|
||||
.send_ipi_single = up_send_ipi_single,
|
||||
.send_ipi_mask = up_send_ipi_mask,
|
||||
|
@ -64,4 +76,8 @@ struct plat_smp_ops up_smp_ops = {
|
|||
.boot_secondary = up_boot_secondary,
|
||||
.smp_setup = up_smp_setup,
|
||||
.prepare_cpus = up_prepare_cpus,
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
.cpu_disable = up_cpu_disable,
|
||||
.cpu_die = up_cpu_die,
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/threads.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -44,7 +45,7 @@
|
|||
#include <asm/mipsmtregs.h>
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
static volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */
|
||||
volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */
|
||||
int __cpu_number_map[NR_CPUS]; /* Map physical to logical */
|
||||
int __cpu_logical_map[NR_CPUS]; /* Map logical to physical */
|
||||
|
||||
|
@ -200,6 +201,8 @@ void __devinit smp_prepare_boot_cpu(void)
|
|||
* and keep control until "cpu_online(cpu)" is set. Note: cpu is
|
||||
* physical, not logical.
|
||||
*/
|
||||
static struct task_struct *cpu_idle_thread[NR_CPUS];
|
||||
|
||||
int __cpuinit __cpu_up(unsigned int cpu)
|
||||
{
|
||||
struct task_struct *idle;
|
||||
|
@ -209,9 +212,16 @@ int __cpuinit __cpu_up(unsigned int cpu)
|
|||
* The following code is purely to make sure
|
||||
* Linux can schedule processes on this slave.
|
||||
*/
|
||||
idle = fork_idle(cpu);
|
||||
if (IS_ERR(idle))
|
||||
panic(KERN_ERR "Fork failed for CPU %d", cpu);
|
||||
if (!cpu_idle_thread[cpu]) {
|
||||
idle = fork_idle(cpu);
|
||||
cpu_idle_thread[cpu] = idle;
|
||||
|
||||
if (IS_ERR(idle))
|
||||
panic(KERN_ERR "Fork failed for CPU %d", cpu);
|
||||
} else {
|
||||
idle = cpu_idle_thread[cpu];
|
||||
init_idle(idle, cpu);
|
||||
}
|
||||
|
||||
mp_ops->boot_secondary(cpu, idle);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/clockchips.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
|
|
|
@ -17,7 +17,10 @@ static int __init topology_init(void)
|
|||
#endif /* CONFIG_NUMA */
|
||||
|
||||
for_each_present_cpu(i) {
|
||||
ret = register_cpu(&per_cpu(cpu_devices, i), i);
|
||||
struct cpu *c = &per_cpu(cpu_devices, i);
|
||||
|
||||
c->hotpluggable = 1;
|
||||
ret = register_cpu(c, i);
|
||||
if (ret)
|
||||
printk(KERN_WARNING "topology_init: register_cpu %d "
|
||||
"failed (%d)\n", i, ret);
|
||||
|
|
|
@ -91,6 +91,7 @@ unsigned __cpuinit get_c0_compare_int(void)
|
|||
mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
|
||||
} else {
|
||||
#endif
|
||||
{
|
||||
if (cpu_has_vint)
|
||||
set_vi_handler(cp0_compare_irq, mips_timer_dispatch);
|
||||
mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/cpu.h>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitops.h>
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/cacheops.h>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/smp.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/hugetlb.h>
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/cpu.h>
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/smp.h>
|
||||
#include <asm/sn/arch.h>
|
||||
#include <asm/pci/bridge.h>
|
||||
#include <asm/paccess.h>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <linux/linkage.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/pmon.h>
|
||||
#include <asm/titan_dep.h>
|
||||
|
|
|
@ -43,15 +43,6 @@ LEAF(swsusp_arch_resume)
|
|||
bne t1, t3, 1b
|
||||
PTR_L t0, PBE_NEXT(t0)
|
||||
bnez t0, 0b
|
||||
/* flush caches to make sure context is in memory */
|
||||
PTR_L t0, __flush_cache_all
|
||||
jalr t0
|
||||
/* flush tlb entries */
|
||||
#ifdef CONFIG_SMP
|
||||
jal flush_tlb_all
|
||||
#else
|
||||
jal local_flush_tlb_all
|
||||
#endif
|
||||
PTR_LA t0, saved_regs
|
||||
PTR_L ra, PT_R31(t0)
|
||||
PTR_L sp, PT_R29(t0)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/cpumask.h>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/ioport.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/mm.h>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/smp.h>
|
||||
#include <asm/sn/types.h>
|
||||
#include <asm/sn/klconfig.h>
|
||||
#include <asm/sn/hub.h>
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
@ -51,12 +51,13 @@ static int cfe_console_setup(struct console *cons, char *str)
|
|||
setleds("u0cn");
|
||||
} else if (!strcmp(consdev, "uart1")) {
|
||||
setleds("u1cn");
|
||||
} else
|
||||
#endif
|
||||
#ifdef CONFIG_VGA_CONSOLE
|
||||
} else if (!strcmp(consdev, "pcconsole0")) {
|
||||
setleds("pccn");
|
||||
#endif
|
||||
if (!strcmp(consdev, "pcconsole0")) {
|
||||
setleds("pccn");
|
||||
} else
|
||||
#endif
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/clockchips.h>
|
||||
|
||||
|
|
|
@ -432,23 +432,27 @@ txx9dmac_descriptor_complete(struct txx9dmac_chan *dc,
|
|||
list_splice_init(&txd->tx_list, &dc->free_list);
|
||||
list_move(&desc->desc_node, &dc->free_list);
|
||||
|
||||
/*
|
||||
* We use dma_unmap_page() regardless of how the buffers were
|
||||
* mapped before they were submitted...
|
||||
*/
|
||||
if (!ds) {
|
||||
dma_addr_t dmaaddr;
|
||||
if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
|
||||
dmaaddr = is_dmac64(dc) ?
|
||||
desc->hwdesc.DAR : desc->hwdesc32.DAR;
|
||||
dma_unmap_page(chan2parent(&dc->chan), dmaaddr,
|
||||
desc->len, DMA_FROM_DEVICE);
|
||||
if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE)
|
||||
dma_unmap_single(chan2parent(&dc->chan),
|
||||
dmaaddr, desc->len, DMA_FROM_DEVICE);
|
||||
else
|
||||
dma_unmap_page(chan2parent(&dc->chan),
|
||||
dmaaddr, desc->len, DMA_FROM_DEVICE);
|
||||
}
|
||||
if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
|
||||
dmaaddr = is_dmac64(dc) ?
|
||||
desc->hwdesc.SAR : desc->hwdesc32.SAR;
|
||||
dma_unmap_page(chan2parent(&dc->chan), dmaaddr,
|
||||
desc->len, DMA_TO_DEVICE);
|
||||
if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE)
|
||||
dma_unmap_single(chan2parent(&dc->chan),
|
||||
dmaaddr, desc->len, DMA_TO_DEVICE);
|
||||
else
|
||||
dma_unmap_page(chan2parent(&dc->chan),
|
||||
dmaaddr, desc->len, DMA_TO_DEVICE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
obj-${CONFIG_OCTEON_ETHERNET} := octeon-ethernet.o
|
||||
|
||||
octeon-ethernet-objs := ethernet.o
|
||||
octeon-ethernet-objs += ethernet-common.o
|
||||
octeon-ethernet-objs += ethernet-mdio.o
|
||||
octeon-ethernet-objs += ethernet-mem.o
|
||||
octeon-ethernet-objs += ethernet-proc.o
|
||||
|
|
|
@ -1,328 +0,0 @@
|
|||
/**********************************************************************
|
||||
* Author: Cavium Networks
|
||||
*
|
||||
* Contact: support@caviumnetworks.com
|
||||
* This file is part of the OCTEON SDK
|
||||
*
|
||||
* Copyright (c) 2003-2007 Cavium Networks
|
||||
*
|
||||
* This file 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.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
|
||||
* NONINFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* or visit http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file may also be available under a different license from Cavium.
|
||||
* Contact Cavium Networks for more information
|
||||
**********************************************************************/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mii.h>
|
||||
#include <net/dst.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/octeon/octeon.h>
|
||||
|
||||
#include "ethernet-defines.h"
|
||||
#include "ethernet-tx.h"
|
||||
#include "ethernet-mdio.h"
|
||||
#include "ethernet-util.h"
|
||||
#include "octeon-ethernet.h"
|
||||
#include "ethernet-common.h"
|
||||
|
||||
#include "cvmx-pip.h"
|
||||
#include "cvmx-pko.h"
|
||||
#include "cvmx-fau.h"
|
||||
#include "cvmx-helper.h"
|
||||
|
||||
#include "cvmx-gmxx-defs.h"
|
||||
|
||||
/**
|
||||
* Get the low level ethernet statistics
|
||||
*
|
||||
* @dev: Device to get the statistics from
|
||||
* Returns Pointer to the statistics
|
||||
*/
|
||||
static struct net_device_stats *cvm_oct_common_get_stats(struct net_device *dev)
|
||||
{
|
||||
cvmx_pip_port_status_t rx_status;
|
||||
cvmx_pko_port_status_t tx_status;
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
|
||||
if (priv->port < CVMX_PIP_NUM_INPUT_PORTS) {
|
||||
if (octeon_is_simulation()) {
|
||||
/* The simulator doesn't support statistics */
|
||||
memset(&rx_status, 0, sizeof(rx_status));
|
||||
memset(&tx_status, 0, sizeof(tx_status));
|
||||
} else {
|
||||
cvmx_pip_get_port_status(priv->port, 1, &rx_status);
|
||||
cvmx_pko_get_port_status(priv->port, 1, &tx_status);
|
||||
}
|
||||
|
||||
priv->stats.rx_packets += rx_status.inb_packets;
|
||||
priv->stats.tx_packets += tx_status.packets;
|
||||
priv->stats.rx_bytes += rx_status.inb_octets;
|
||||
priv->stats.tx_bytes += tx_status.octets;
|
||||
priv->stats.multicast += rx_status.multicast_packets;
|
||||
priv->stats.rx_crc_errors += rx_status.inb_errors;
|
||||
priv->stats.rx_frame_errors += rx_status.fcs_align_err_packets;
|
||||
|
||||
/*
|
||||
* The drop counter must be incremented atomically
|
||||
* since the RX tasklet also increments it.
|
||||
*/
|
||||
#ifdef CONFIG_64BIT
|
||||
atomic64_add(rx_status.dropped_packets,
|
||||
(atomic64_t *)&priv->stats.rx_dropped);
|
||||
#else
|
||||
atomic_add(rx_status.dropped_packets,
|
||||
(atomic_t *)&priv->stats.rx_dropped);
|
||||
#endif
|
||||
}
|
||||
|
||||
return &priv->stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the multicast list. Currently unimplemented.
|
||||
*
|
||||
* @dev: Device to work on
|
||||
*/
|
||||
static void cvm_oct_common_set_multicast_list(struct net_device *dev)
|
||||
{
|
||||
union cvmx_gmxx_prtx_cfg gmx_cfg;
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
int interface = INTERFACE(priv->port);
|
||||
int index = INDEX(priv->port);
|
||||
|
||||
if ((interface < 2)
|
||||
&& (cvmx_helper_interface_get_mode(interface) !=
|
||||
CVMX_HELPER_INTERFACE_MODE_SPI)) {
|
||||
union cvmx_gmxx_rxx_adr_ctl control;
|
||||
control.u64 = 0;
|
||||
control.s.bcst = 1; /* Allow broadcast MAC addresses */
|
||||
|
||||
if (dev->mc_list || (dev->flags & IFF_ALLMULTI) ||
|
||||
(dev->flags & IFF_PROMISC))
|
||||
/* Force accept multicast packets */
|
||||
control.s.mcst = 2;
|
||||
else
|
||||
/* Force reject multicat packets */
|
||||
control.s.mcst = 1;
|
||||
|
||||
if (dev->flags & IFF_PROMISC)
|
||||
/*
|
||||
* Reject matches if promisc. Since CAM is
|
||||
* shut off, should accept everything.
|
||||
*/
|
||||
control.s.cam_mode = 0;
|
||||
else
|
||||
/* Filter packets based on the CAM */
|
||||
control.s.cam_mode = 1;
|
||||
|
||||
gmx_cfg.u64 =
|
||||
cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
|
||||
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
|
||||
gmx_cfg.u64 & ~1ull);
|
||||
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface),
|
||||
control.u64);
|
||||
if (dev->flags & IFF_PROMISC)
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN
|
||||
(index, interface), 0);
|
||||
else
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN
|
||||
(index, interface), 1);
|
||||
|
||||
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
|
||||
gmx_cfg.u64);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the hardware MAC address for a device
|
||||
*
|
||||
* @dev: Device to change the MAC address for
|
||||
* @addr: Address structure to change it too. MAC address is addr + 2.
|
||||
* Returns Zero on success
|
||||
*/
|
||||
static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
|
||||
{
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
union cvmx_gmxx_prtx_cfg gmx_cfg;
|
||||
int interface = INTERFACE(priv->port);
|
||||
int index = INDEX(priv->port);
|
||||
|
||||
memcpy(dev->dev_addr, addr + 2, 6);
|
||||
|
||||
if ((interface < 2)
|
||||
&& (cvmx_helper_interface_get_mode(interface) !=
|
||||
CVMX_HELPER_INTERFACE_MODE_SPI)) {
|
||||
int i;
|
||||
uint8_t *ptr = addr;
|
||||
uint64_t mac = 0;
|
||||
for (i = 0; i < 6; i++)
|
||||
mac = (mac << 8) | (uint64_t) (ptr[i + 2]);
|
||||
|
||||
gmx_cfg.u64 =
|
||||
cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
|
||||
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
|
||||
gmx_cfg.u64 & ~1ull);
|
||||
|
||||
cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface),
|
||||
ptr[2]);
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface),
|
||||
ptr[3]);
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface),
|
||||
ptr[4]);
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface),
|
||||
ptr[5]);
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface),
|
||||
ptr[6]);
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface),
|
||||
ptr[7]);
|
||||
cvm_oct_common_set_multicast_list(dev);
|
||||
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
|
||||
gmx_cfg.u64);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the link MTU. Unimplemented
|
||||
*
|
||||
* @dev: Device to change
|
||||
* @new_mtu: The new MTU
|
||||
*
|
||||
* Returns Zero on success
|
||||
*/
|
||||
static int cvm_oct_common_change_mtu(struct net_device *dev, int new_mtu)
|
||||
{
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
int interface = INTERFACE(priv->port);
|
||||
int index = INDEX(priv->port);
|
||||
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
|
||||
int vlan_bytes = 4;
|
||||
#else
|
||||
int vlan_bytes = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Limit the MTU to make sure the ethernet packets are between
|
||||
* 64 bytes and 65535 bytes.
|
||||
*/
|
||||
if ((new_mtu + 14 + 4 + vlan_bytes < 64)
|
||||
|| (new_mtu + 14 + 4 + vlan_bytes > 65392)) {
|
||||
pr_err("MTU must be between %d and %d.\n",
|
||||
64 - 14 - 4 - vlan_bytes, 65392 - 14 - 4 - vlan_bytes);
|
||||
return -EINVAL;
|
||||
}
|
||||
dev->mtu = new_mtu;
|
||||
|
||||
if ((interface < 2)
|
||||
&& (cvmx_helper_interface_get_mode(interface) !=
|
||||
CVMX_HELPER_INTERFACE_MODE_SPI)) {
|
||||
/* Add ethernet header and FCS, and VLAN if configured. */
|
||||
int max_packet = new_mtu + 14 + 4 + vlan_bytes;
|
||||
|
||||
if (OCTEON_IS_MODEL(OCTEON_CN3XXX)
|
||||
|| OCTEON_IS_MODEL(OCTEON_CN58XX)) {
|
||||
/* Signal errors on packets larger than the MTU */
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(index, interface),
|
||||
max_packet);
|
||||
} else {
|
||||
/*
|
||||
* Set the hardware to truncate packets larger
|
||||
* than the MTU and smaller the 64 bytes.
|
||||
*/
|
||||
union cvmx_pip_frm_len_chkx frm_len_chk;
|
||||
frm_len_chk.u64 = 0;
|
||||
frm_len_chk.s.minlen = 64;
|
||||
frm_len_chk.s.maxlen = max_packet;
|
||||
cvmx_write_csr(CVMX_PIP_FRM_LEN_CHKX(interface),
|
||||
frm_len_chk.u64);
|
||||
}
|
||||
/*
|
||||
* Set the hardware to truncate packets larger than
|
||||
* the MTU. The jabber register must be set to a
|
||||
* multiple of 8 bytes, so round up.
|
||||
*/
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_JABBER(index, interface),
|
||||
(max_packet + 7) & ~7u);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Per network device initialization
|
||||
*
|
||||
* @dev: Device to initialize
|
||||
* Returns Zero on success
|
||||
*/
|
||||
int cvm_oct_common_init(struct net_device *dev)
|
||||
{
|
||||
static int count;
|
||||
char mac[8] = { 0x00, 0x00,
|
||||
octeon_bootinfo->mac_addr_base[0],
|
||||
octeon_bootinfo->mac_addr_base[1],
|
||||
octeon_bootinfo->mac_addr_base[2],
|
||||
octeon_bootinfo->mac_addr_base[3],
|
||||
octeon_bootinfo->mac_addr_base[4],
|
||||
octeon_bootinfo->mac_addr_base[5] + count
|
||||
};
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
|
||||
/*
|
||||
* Force the interface to use the POW send if always_use_pow
|
||||
* was specified or it is in the pow send list.
|
||||
*/
|
||||
if ((pow_send_group != -1)
|
||||
&& (always_use_pow || strstr(pow_send_list, dev->name)))
|
||||
priv->queue = -1;
|
||||
|
||||
if (priv->queue != -1) {
|
||||
dev->hard_start_xmit = cvm_oct_xmit;
|
||||
if (USE_HW_TCPUDP_CHECKSUM)
|
||||
dev->features |= NETIF_F_IP_CSUM;
|
||||
} else
|
||||
dev->hard_start_xmit = cvm_oct_xmit_pow;
|
||||
count++;
|
||||
|
||||
dev->get_stats = cvm_oct_common_get_stats;
|
||||
dev->set_mac_address = cvm_oct_common_set_mac_address;
|
||||
dev->set_multicast_list = cvm_oct_common_set_multicast_list;
|
||||
dev->change_mtu = cvm_oct_common_change_mtu;
|
||||
dev->do_ioctl = cvm_oct_ioctl;
|
||||
/* We do our own locking, Linux doesn't need to */
|
||||
dev->features |= NETIF_F_LLTX;
|
||||
SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops);
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
dev->poll_controller = cvm_oct_poll_controller;
|
||||
#endif
|
||||
|
||||
cvm_oct_mdio_setup_device(dev);
|
||||
dev->set_mac_address(dev, mac);
|
||||
dev->change_mtu(dev, dev->mtu);
|
||||
|
||||
/*
|
||||
* Zero out stats for port so we won't mistakenly show
|
||||
* counters from the bootloader.
|
||||
*/
|
||||
memset(dev->get_stats(dev), 0, sizeof(struct net_device_stats));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cvm_oct_common_uninit(struct net_device *dev)
|
||||
{
|
||||
/* Currently nothing to do */
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*********************************************************************
|
||||
* Author: Cavium Networks
|
||||
*
|
||||
* Contact: support@caviumnetworks.com
|
||||
* This file is part of the OCTEON SDK
|
||||
*
|
||||
* Copyright (c) 2003-2007 Cavium Networks
|
||||
*
|
||||
* This file 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.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
|
||||
* NONINFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* or visit http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file may also be available under a different license from Cavium.
|
||||
* Contact Cavium Networks for more information
|
||||
*********************************************************************/
|
||||
|
||||
int cvm_oct_common_init(struct net_device *dev);
|
||||
void cvm_oct_common_uninit(struct net_device *dev);
|
|
@ -117,6 +117,8 @@
|
|||
|
||||
/* Maximum number of packets to process per interrupt. */
|
||||
#define MAX_RX_PACKETS 120
|
||||
/* Maximum number of SKBs to try to free per xmit packet. */
|
||||
#define MAX_SKB_TO_FREE 10
|
||||
#define MAX_OUT_QUEUE_DEPTH 1000
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
#include "ethernet-defines.h"
|
||||
#include "octeon-ethernet.h"
|
||||
#include "ethernet-common.h"
|
||||
#include "ethernet-util.h"
|
||||
|
||||
#include "cvmx-helper.h"
|
||||
|
@ -265,7 +264,7 @@ static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
|
|||
return return_status;
|
||||
}
|
||||
|
||||
static int cvm_oct_rgmii_open(struct net_device *dev)
|
||||
int cvm_oct_rgmii_open(struct net_device *dev)
|
||||
{
|
||||
union cvmx_gmxx_prtx_cfg gmx_cfg;
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
|
@ -286,7 +285,7 @@ static int cvm_oct_rgmii_open(struct net_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cvm_oct_rgmii_stop(struct net_device *dev)
|
||||
int cvm_oct_rgmii_stop(struct net_device *dev)
|
||||
{
|
||||
union cvmx_gmxx_prtx_cfg gmx_cfg;
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
|
@ -305,9 +304,7 @@ int cvm_oct_rgmii_init(struct net_device *dev)
|
|||
int r;
|
||||
|
||||
cvm_oct_common_init(dev);
|
||||
dev->open = cvm_oct_rgmii_open;
|
||||
dev->stop = cvm_oct_rgmii_stop;
|
||||
dev->stop(dev);
|
||||
dev->netdev_ops->ndo_stop(dev);
|
||||
|
||||
/*
|
||||
* Due to GMX errata in CN3XXX series chips, it is necessary
|
||||
|
|
|
@ -34,13 +34,12 @@
|
|||
#include "ethernet-defines.h"
|
||||
#include "octeon-ethernet.h"
|
||||
#include "ethernet-util.h"
|
||||
#include "ethernet-common.h"
|
||||
|
||||
#include "cvmx-helper.h"
|
||||
|
||||
#include "cvmx-gmxx-defs.h"
|
||||
|
||||
static int cvm_oct_sgmii_open(struct net_device *dev)
|
||||
int cvm_oct_sgmii_open(struct net_device *dev)
|
||||
{
|
||||
union cvmx_gmxx_prtx_cfg gmx_cfg;
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
|
@ -61,7 +60,7 @@ static int cvm_oct_sgmii_open(struct net_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cvm_oct_sgmii_stop(struct net_device *dev)
|
||||
int cvm_oct_sgmii_stop(struct net_device *dev)
|
||||
{
|
||||
union cvmx_gmxx_prtx_cfg gmx_cfg;
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
|
@ -113,9 +112,7 @@ int cvm_oct_sgmii_init(struct net_device *dev)
|
|||
{
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
cvm_oct_common_init(dev);
|
||||
dev->open = cvm_oct_sgmii_open;
|
||||
dev->stop = cvm_oct_sgmii_stop;
|
||||
dev->stop(dev);
|
||||
dev->netdev_ops->ndo_stop(dev);
|
||||
if (!octeon_is_simulation())
|
||||
priv->poll = cvm_oct_sgmii_poll;
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
#include "ethernet-defines.h"
|
||||
#include "octeon-ethernet.h"
|
||||
#include "ethernet-common.h"
|
||||
#include "ethernet-util.h"
|
||||
|
||||
#include "cvmx-spi.h"
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
|
||||
#include "ethernet-defines.h"
|
||||
#include "octeon-ethernet.h"
|
||||
#include "ethernet-tx.h"
|
||||
#include "ethernet-util.h"
|
||||
|
||||
#include "cvmx-wqe.h"
|
||||
|
@ -82,8 +83,10 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
uint64_t old_scratch2;
|
||||
int dropped;
|
||||
int qos;
|
||||
int queue_it_up;
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
int32_t in_use;
|
||||
int32_t skb_to_free;
|
||||
int32_t undo;
|
||||
int32_t buffers_to_free;
|
||||
#if REUSE_SKBUFFS_WITHOUT_FREE
|
||||
unsigned char *fpa_head;
|
||||
|
@ -120,15 +123,15 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
old_scratch2 = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8);
|
||||
|
||||
/*
|
||||
* Assume we're going to be able t osend this
|
||||
* packet. Fetch and increment the number of pending
|
||||
* packets for output.
|
||||
* Fetch and increment the number of packets to be
|
||||
* freed.
|
||||
*/
|
||||
cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH + 8,
|
||||
FAU_NUM_PACKET_BUFFERS_TO_FREE,
|
||||
0);
|
||||
cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH,
|
||||
priv->fau + qos * 4, 1);
|
||||
priv->fau + qos * 4,
|
||||
MAX_SKB_TO_FREE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -253,10 +256,10 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
|
||||
/*
|
||||
* The skbuff will be reused without ever being freed. We must
|
||||
* cleanup a bunch of Linux stuff.
|
||||
* cleanup a bunch of core things.
|
||||
*/
|
||||
dst_release(skb->dst);
|
||||
skb->dst = NULL;
|
||||
dst_release(skb_dst(skb));
|
||||
skb_dst_set(skb, NULL);
|
||||
#ifdef CONFIG_XFRM
|
||||
secpath_put(skb->sp);
|
||||
skb->sp = NULL;
|
||||
|
@ -286,15 +289,29 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
if (USE_ASYNC_IOBDMA) {
|
||||
/* Get the number of skbuffs in use by the hardware */
|
||||
CVMX_SYNCIOBDMA;
|
||||
in_use = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
|
||||
skb_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
|
||||
buffers_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8);
|
||||
} else {
|
||||
/* Get the number of skbuffs in use by the hardware */
|
||||
in_use = cvmx_fau_fetch_and_add32(priv->fau + qos * 4, 1);
|
||||
skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4,
|
||||
MAX_SKB_TO_FREE);
|
||||
buffers_to_free =
|
||||
cvmx_fau_fetch_and_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We try to claim MAX_SKB_TO_FREE buffers. If there were not
|
||||
* that many available, we have to un-claim (undo) any that
|
||||
* were in excess. If skb_to_free is positive we will free
|
||||
* that many buffers.
|
||||
*/
|
||||
undo = skb_to_free > 0 ?
|
||||
MAX_SKB_TO_FREE : skb_to_free + MAX_SKB_TO_FREE;
|
||||
if (undo > 0)
|
||||
cvmx_fau_atomic_add32(priv->fau+qos*4, -undo);
|
||||
skb_to_free = -skb_to_free > MAX_SKB_TO_FREE ?
|
||||
MAX_SKB_TO_FREE : -skb_to_free;
|
||||
|
||||
/*
|
||||
* If we're sending faster than the receive can free them then
|
||||
* don't do the HW free.
|
||||
|
@ -330,38 +347,31 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
cvmx_scratch_write64(CVMX_SCR_SCRATCH + 8, old_scratch2);
|
||||
}
|
||||
|
||||
queue_it_up = 0;
|
||||
if (unlikely(dropped)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
cvmx_fau_atomic_add32(priv->fau + qos * 4, -1);
|
||||
priv->stats.tx_dropped++;
|
||||
} else {
|
||||
if (USE_SKBUFFS_IN_HW) {
|
||||
/* Put this packet on the queue to be freed later */
|
||||
if (pko_command.s.dontfree)
|
||||
skb_queue_tail(&priv->tx_free_list[qos], skb);
|
||||
else {
|
||||
queue_it_up = 1;
|
||||
else
|
||||
cvmx_fau_atomic_add32
|
||||
(FAU_NUM_PACKET_BUFFERS_TO_FREE, -1);
|
||||
cvmx_fau_atomic_add32(priv->fau + qos * 4, -1);
|
||||
}
|
||||
} else {
|
||||
/* Put this packet on the queue to be freed later */
|
||||
skb_queue_tail(&priv->tx_free_list[qos], skb);
|
||||
queue_it_up = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free skbuffs not in use by the hardware, possibly two at a time */
|
||||
if (skb_queue_len(&priv->tx_free_list[qos]) > in_use) {
|
||||
if (queue_it_up) {
|
||||
spin_lock(&priv->tx_free_list[qos].lock);
|
||||
/*
|
||||
* Check again now that we have the lock. It might
|
||||
* have changed.
|
||||
*/
|
||||
if (skb_queue_len(&priv->tx_free_list[qos]) > in_use)
|
||||
dev_kfree_skb(__skb_dequeue(&priv->tx_free_list[qos]));
|
||||
if (skb_queue_len(&priv->tx_free_list[qos]) > in_use)
|
||||
dev_kfree_skb(__skb_dequeue(&priv->tx_free_list[qos]));
|
||||
__skb_queue_tail(&priv->tx_free_list[qos], skb);
|
||||
cvm_oct_free_tx_skbs(priv, skb_to_free, qos, 0);
|
||||
spin_unlock(&priv->tx_free_list[qos].lock);
|
||||
} else {
|
||||
cvm_oct_free_tx_skbs(priv, skb_to_free, qos, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -30,3 +30,28 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev);
|
|||
int cvm_oct_transmit_qos(struct net_device *dev, void *work_queue_entry,
|
||||
int do_free, int qos);
|
||||
void cvm_oct_tx_shutdown(struct net_device *dev);
|
||||
|
||||
/**
|
||||
* Free dead transmit skbs.
|
||||
*
|
||||
* @priv: The driver data
|
||||
* @skb_to_free: The number of SKBs to free (free none if negative).
|
||||
* @qos: The queue to free from.
|
||||
* @take_lock: If true, acquire the skb list lock.
|
||||
*/
|
||||
static inline void cvm_oct_free_tx_skbs(struct octeon_ethernet *priv,
|
||||
int skb_to_free,
|
||||
int qos, int take_lock)
|
||||
{
|
||||
/* Free skbuffs not in use by the hardware. */
|
||||
if (skb_to_free > 0) {
|
||||
if (take_lock)
|
||||
spin_lock(&priv->tx_free_list[qos].lock);
|
||||
while (skb_to_free > 0) {
|
||||
dev_kfree_skb(__skb_dequeue(&priv->tx_free_list[qos]));
|
||||
skb_to_free--;
|
||||
}
|
||||
if (take_lock)
|
||||
spin_unlock(&priv->tx_free_list[qos].lock);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,14 +33,13 @@
|
|||
|
||||
#include "ethernet-defines.h"
|
||||
#include "octeon-ethernet.h"
|
||||
#include "ethernet-common.h"
|
||||
#include "ethernet-util.h"
|
||||
|
||||
#include "cvmx-helper.h"
|
||||
|
||||
#include "cvmx-gmxx-defs.h"
|
||||
|
||||
static int cvm_oct_xaui_open(struct net_device *dev)
|
||||
int cvm_oct_xaui_open(struct net_device *dev)
|
||||
{
|
||||
union cvmx_gmxx_prtx_cfg gmx_cfg;
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
|
@ -60,7 +59,7 @@ static int cvm_oct_xaui_open(struct net_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cvm_oct_xaui_stop(struct net_device *dev)
|
||||
int cvm_oct_xaui_stop(struct net_device *dev)
|
||||
{
|
||||
union cvmx_gmxx_prtx_cfg gmx_cfg;
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
|
@ -112,9 +111,7 @@ int cvm_oct_xaui_init(struct net_device *dev)
|
|||
{
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
cvm_oct_common_init(dev);
|
||||
dev->open = cvm_oct_xaui_open;
|
||||
dev->stop = cvm_oct_xaui_stop;
|
||||
dev->stop(dev);
|
||||
dev->netdev_ops->ndo_stop(dev);
|
||||
if (!octeon_is_simulation())
|
||||
priv->poll = cvm_oct_xaui_poll;
|
||||
|
||||
|
|
|
@ -37,13 +37,14 @@
|
|||
#include <asm/octeon/octeon.h>
|
||||
|
||||
#include "ethernet-defines.h"
|
||||
#include "octeon-ethernet.h"
|
||||
#include "ethernet-mem.h"
|
||||
#include "ethernet-rx.h"
|
||||
#include "ethernet-tx.h"
|
||||
#include "ethernet-mdio.h"
|
||||
#include "ethernet-util.h"
|
||||
#include "ethernet-proc.h"
|
||||
#include "ethernet-common.h"
|
||||
#include "octeon-ethernet.h"
|
||||
|
||||
|
||||
#include "cvmx-pip.h"
|
||||
#include "cvmx-pko.h"
|
||||
|
@ -51,6 +52,7 @@
|
|||
#include "cvmx-ipd.h"
|
||||
#include "cvmx-helper.h"
|
||||
|
||||
#include "cvmx-gmxx-defs.h"
|
||||
#include "cvmx-smix-defs.h"
|
||||
|
||||
#if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) \
|
||||
|
@ -129,53 +131,55 @@ extern struct semaphore mdio_sem;
|
|||
*/
|
||||
static void cvm_do_timer(unsigned long arg)
|
||||
{
|
||||
int32_t skb_to_free, undo;
|
||||
int queues_per_port;
|
||||
int qos;
|
||||
struct octeon_ethernet *priv;
|
||||
static int port;
|
||||
if (port < CVMX_PIP_NUM_INPUT_PORTS) {
|
||||
if (cvm_oct_device[port]) {
|
||||
int queues_per_port;
|
||||
int qos;
|
||||
struct octeon_ethernet *priv =
|
||||
netdev_priv(cvm_oct_device[port]);
|
||||
if (priv->poll) {
|
||||
/* skip polling if we don't get the lock */
|
||||
if (!down_trylock(&mdio_sem)) {
|
||||
priv->poll(cvm_oct_device[port]);
|
||||
up(&mdio_sem);
|
||||
}
|
||||
}
|
||||
|
||||
queues_per_port = cvmx_pko_get_num_queues(port);
|
||||
/* Drain any pending packets in the free list */
|
||||
for (qos = 0; qos < queues_per_port; qos++) {
|
||||
if (skb_queue_len(&priv->tx_free_list[qos])) {
|
||||
spin_lock(&priv->tx_free_list[qos].
|
||||
lock);
|
||||
while (skb_queue_len
|
||||
(&priv->tx_free_list[qos]) >
|
||||
cvmx_fau_fetch_and_add32(priv->
|
||||
fau +
|
||||
qos * 4,
|
||||
0))
|
||||
dev_kfree_skb(__skb_dequeue
|
||||
(&priv->
|
||||
tx_free_list
|
||||
[qos]));
|
||||
spin_unlock(&priv->tx_free_list[qos].
|
||||
lock);
|
||||
}
|
||||
}
|
||||
cvm_oct_device[port]->get_stats(cvm_oct_device[port]);
|
||||
}
|
||||
port++;
|
||||
/* Poll the next port in a 50th of a second.
|
||||
This spreads the polling of ports out a little bit */
|
||||
mod_timer(&cvm_oct_poll_timer, jiffies + HZ / 50);
|
||||
} else {
|
||||
if (port >= CVMX_PIP_NUM_INPUT_PORTS) {
|
||||
/*
|
||||
* All ports have been polled. Start the next
|
||||
* iteration through the ports in one second.
|
||||
*/
|
||||
port = 0;
|
||||
/* All ports have been polled. Start the next iteration through
|
||||
the ports in one second */
|
||||
mod_timer(&cvm_oct_poll_timer, jiffies + HZ);
|
||||
return;
|
||||
}
|
||||
if (!cvm_oct_device[port])
|
||||
goto out;
|
||||
|
||||
priv = netdev_priv(cvm_oct_device[port]);
|
||||
if (priv->poll) {
|
||||
/* skip polling if we don't get the lock */
|
||||
if (!down_trylock(&mdio_sem)) {
|
||||
priv->poll(cvm_oct_device[port]);
|
||||
up(&mdio_sem);
|
||||
}
|
||||
}
|
||||
|
||||
queues_per_port = cvmx_pko_get_num_queues(port);
|
||||
/* Drain any pending packets in the free list */
|
||||
for (qos = 0; qos < queues_per_port; qos++) {
|
||||
if (skb_queue_len(&priv->tx_free_list[qos]) == 0)
|
||||
continue;
|
||||
skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4,
|
||||
MAX_SKB_TO_FREE);
|
||||
undo = skb_to_free > 0 ?
|
||||
MAX_SKB_TO_FREE : skb_to_free + MAX_SKB_TO_FREE;
|
||||
if (undo > 0)
|
||||
cvmx_fau_atomic_add32(priv->fau+qos*4, -undo);
|
||||
skb_to_free = -skb_to_free > MAX_SKB_TO_FREE ?
|
||||
MAX_SKB_TO_FREE : -skb_to_free;
|
||||
cvm_oct_free_tx_skbs(priv, skb_to_free, qos, 1);
|
||||
}
|
||||
cvm_oct_device[port]->netdev_ops->ndo_get_stats(cvm_oct_device[port]);
|
||||
|
||||
out:
|
||||
port++;
|
||||
/* Poll the next port in a 50th of a second.
|
||||
This spreads the polling of ports out a little bit */
|
||||
mod_timer(&cvm_oct_poll_timer, jiffies + HZ / 50);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -245,6 +249,362 @@ int cvm_oct_free_work(void *work_queue_entry)
|
|||
}
|
||||
EXPORT_SYMBOL(cvm_oct_free_work);
|
||||
|
||||
/**
|
||||
* Get the low level ethernet statistics
|
||||
*
|
||||
* @dev: Device to get the statistics from
|
||||
* Returns Pointer to the statistics
|
||||
*/
|
||||
static struct net_device_stats *cvm_oct_common_get_stats(struct net_device *dev)
|
||||
{
|
||||
cvmx_pip_port_status_t rx_status;
|
||||
cvmx_pko_port_status_t tx_status;
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
|
||||
if (priv->port < CVMX_PIP_NUM_INPUT_PORTS) {
|
||||
if (octeon_is_simulation()) {
|
||||
/* The simulator doesn't support statistics */
|
||||
memset(&rx_status, 0, sizeof(rx_status));
|
||||
memset(&tx_status, 0, sizeof(tx_status));
|
||||
} else {
|
||||
cvmx_pip_get_port_status(priv->port, 1, &rx_status);
|
||||
cvmx_pko_get_port_status(priv->port, 1, &tx_status);
|
||||
}
|
||||
|
||||
priv->stats.rx_packets += rx_status.inb_packets;
|
||||
priv->stats.tx_packets += tx_status.packets;
|
||||
priv->stats.rx_bytes += rx_status.inb_octets;
|
||||
priv->stats.tx_bytes += tx_status.octets;
|
||||
priv->stats.multicast += rx_status.multicast_packets;
|
||||
priv->stats.rx_crc_errors += rx_status.inb_errors;
|
||||
priv->stats.rx_frame_errors += rx_status.fcs_align_err_packets;
|
||||
|
||||
/*
|
||||
* The drop counter must be incremented atomically
|
||||
* since the RX tasklet also increments it.
|
||||
*/
|
||||
#ifdef CONFIG_64BIT
|
||||
atomic64_add(rx_status.dropped_packets,
|
||||
(atomic64_t *)&priv->stats.rx_dropped);
|
||||
#else
|
||||
atomic_add(rx_status.dropped_packets,
|
||||
(atomic_t *)&priv->stats.rx_dropped);
|
||||
#endif
|
||||
}
|
||||
|
||||
return &priv->stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the link MTU. Unimplemented
|
||||
*
|
||||
* @dev: Device to change
|
||||
* @new_mtu: The new MTU
|
||||
*
|
||||
* Returns Zero on success
|
||||
*/
|
||||
static int cvm_oct_common_change_mtu(struct net_device *dev, int new_mtu)
|
||||
{
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
int interface = INTERFACE(priv->port);
|
||||
int index = INDEX(priv->port);
|
||||
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
|
||||
int vlan_bytes = 4;
|
||||
#else
|
||||
int vlan_bytes = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Limit the MTU to make sure the ethernet packets are between
|
||||
* 64 bytes and 65535 bytes.
|
||||
*/
|
||||
if ((new_mtu + 14 + 4 + vlan_bytes < 64)
|
||||
|| (new_mtu + 14 + 4 + vlan_bytes > 65392)) {
|
||||
pr_err("MTU must be between %d and %d.\n",
|
||||
64 - 14 - 4 - vlan_bytes, 65392 - 14 - 4 - vlan_bytes);
|
||||
return -EINVAL;
|
||||
}
|
||||
dev->mtu = new_mtu;
|
||||
|
||||
if ((interface < 2)
|
||||
&& (cvmx_helper_interface_get_mode(interface) !=
|
||||
CVMX_HELPER_INTERFACE_MODE_SPI)) {
|
||||
/* Add ethernet header and FCS, and VLAN if configured. */
|
||||
int max_packet = new_mtu + 14 + 4 + vlan_bytes;
|
||||
|
||||
if (OCTEON_IS_MODEL(OCTEON_CN3XXX)
|
||||
|| OCTEON_IS_MODEL(OCTEON_CN58XX)) {
|
||||
/* Signal errors on packets larger than the MTU */
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(index, interface),
|
||||
max_packet);
|
||||
} else {
|
||||
/*
|
||||
* Set the hardware to truncate packets larger
|
||||
* than the MTU and smaller the 64 bytes.
|
||||
*/
|
||||
union cvmx_pip_frm_len_chkx frm_len_chk;
|
||||
frm_len_chk.u64 = 0;
|
||||
frm_len_chk.s.minlen = 64;
|
||||
frm_len_chk.s.maxlen = max_packet;
|
||||
cvmx_write_csr(CVMX_PIP_FRM_LEN_CHKX(interface),
|
||||
frm_len_chk.u64);
|
||||
}
|
||||
/*
|
||||
* Set the hardware to truncate packets larger than
|
||||
* the MTU. The jabber register must be set to a
|
||||
* multiple of 8 bytes, so round up.
|
||||
*/
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_JABBER(index, interface),
|
||||
(max_packet + 7) & ~7u);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the multicast list. Currently unimplemented.
|
||||
*
|
||||
* @dev: Device to work on
|
||||
*/
|
||||
static void cvm_oct_common_set_multicast_list(struct net_device *dev)
|
||||
{
|
||||
union cvmx_gmxx_prtx_cfg gmx_cfg;
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
int interface = INTERFACE(priv->port);
|
||||
int index = INDEX(priv->port);
|
||||
|
||||
if ((interface < 2)
|
||||
&& (cvmx_helper_interface_get_mode(interface) !=
|
||||
CVMX_HELPER_INTERFACE_MODE_SPI)) {
|
||||
union cvmx_gmxx_rxx_adr_ctl control;
|
||||
control.u64 = 0;
|
||||
control.s.bcst = 1; /* Allow broadcast MAC addresses */
|
||||
|
||||
if (dev->mc_list || (dev->flags & IFF_ALLMULTI) ||
|
||||
(dev->flags & IFF_PROMISC))
|
||||
/* Force accept multicast packets */
|
||||
control.s.mcst = 2;
|
||||
else
|
||||
/* Force reject multicat packets */
|
||||
control.s.mcst = 1;
|
||||
|
||||
if (dev->flags & IFF_PROMISC)
|
||||
/*
|
||||
* Reject matches if promisc. Since CAM is
|
||||
* shut off, should accept everything.
|
||||
*/
|
||||
control.s.cam_mode = 0;
|
||||
else
|
||||
/* Filter packets based on the CAM */
|
||||
control.s.cam_mode = 1;
|
||||
|
||||
gmx_cfg.u64 =
|
||||
cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
|
||||
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
|
||||
gmx_cfg.u64 & ~1ull);
|
||||
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface),
|
||||
control.u64);
|
||||
if (dev->flags & IFF_PROMISC)
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN
|
||||
(index, interface), 0);
|
||||
else
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN
|
||||
(index, interface), 1);
|
||||
|
||||
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
|
||||
gmx_cfg.u64);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the hardware MAC address for a device
|
||||
*
|
||||
* @dev: Device to change the MAC address for
|
||||
* @addr: Address structure to change it too. MAC address is addr + 2.
|
||||
* Returns Zero on success
|
||||
*/
|
||||
static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
|
||||
{
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
union cvmx_gmxx_prtx_cfg gmx_cfg;
|
||||
int interface = INTERFACE(priv->port);
|
||||
int index = INDEX(priv->port);
|
||||
|
||||
memcpy(dev->dev_addr, addr + 2, 6);
|
||||
|
||||
if ((interface < 2)
|
||||
&& (cvmx_helper_interface_get_mode(interface) !=
|
||||
CVMX_HELPER_INTERFACE_MODE_SPI)) {
|
||||
int i;
|
||||
uint8_t *ptr = addr;
|
||||
uint64_t mac = 0;
|
||||
for (i = 0; i < 6; i++)
|
||||
mac = (mac << 8) | (uint64_t) (ptr[i + 2]);
|
||||
|
||||
gmx_cfg.u64 =
|
||||
cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
|
||||
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
|
||||
gmx_cfg.u64 & ~1ull);
|
||||
|
||||
cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface),
|
||||
ptr[2]);
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface),
|
||||
ptr[3]);
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface),
|
||||
ptr[4]);
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface),
|
||||
ptr[5]);
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface),
|
||||
ptr[6]);
|
||||
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface),
|
||||
ptr[7]);
|
||||
cvm_oct_common_set_multicast_list(dev);
|
||||
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
|
||||
gmx_cfg.u64);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Per network device initialization
|
||||
*
|
||||
* @dev: Device to initialize
|
||||
* Returns Zero on success
|
||||
*/
|
||||
int cvm_oct_common_init(struct net_device *dev)
|
||||
{
|
||||
static int count;
|
||||
char mac[8] = { 0x00, 0x00,
|
||||
octeon_bootinfo->mac_addr_base[0],
|
||||
octeon_bootinfo->mac_addr_base[1],
|
||||
octeon_bootinfo->mac_addr_base[2],
|
||||
octeon_bootinfo->mac_addr_base[3],
|
||||
octeon_bootinfo->mac_addr_base[4],
|
||||
octeon_bootinfo->mac_addr_base[5] + count
|
||||
};
|
||||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
|
||||
/*
|
||||
* Force the interface to use the POW send if always_use_pow
|
||||
* was specified or it is in the pow send list.
|
||||
*/
|
||||
if ((pow_send_group != -1)
|
||||
&& (always_use_pow || strstr(pow_send_list, dev->name)))
|
||||
priv->queue = -1;
|
||||
|
||||
if (priv->queue != -1 && USE_HW_TCPUDP_CHECKSUM)
|
||||
dev->features |= NETIF_F_IP_CSUM;
|
||||
|
||||
count++;
|
||||
|
||||
/* We do our own locking, Linux doesn't need to */
|
||||
dev->features |= NETIF_F_LLTX;
|
||||
SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops);
|
||||
|
||||
cvm_oct_mdio_setup_device(dev);
|
||||
dev->netdev_ops->ndo_set_mac_address(dev, mac);
|
||||
dev->netdev_ops->ndo_change_mtu(dev, dev->mtu);
|
||||
|
||||
/*
|
||||
* Zero out stats for port so we won't mistakenly show
|
||||
* counters from the bootloader.
|
||||
*/
|
||||
memset(dev->netdev_ops->ndo_get_stats(dev), 0,
|
||||
sizeof(struct net_device_stats));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cvm_oct_common_uninit(struct net_device *dev)
|
||||
{
|
||||
/* Currently nothing to do */
|
||||
}
|
||||
|
||||
static const struct net_device_ops cvm_oct_npi_netdev_ops = {
|
||||
.ndo_init = cvm_oct_common_init,
|
||||
.ndo_uninit = cvm_oct_common_uninit,
|
||||
.ndo_start_xmit = cvm_oct_xmit,
|
||||
.ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
|
||||
.ndo_set_mac_address = cvm_oct_common_set_mac_address,
|
||||
.ndo_do_ioctl = cvm_oct_ioctl,
|
||||
.ndo_change_mtu = cvm_oct_common_change_mtu,
|
||||
.ndo_get_stats = cvm_oct_common_get_stats,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = cvm_oct_poll_controller,
|
||||
#endif
|
||||
};
|
||||
static const struct net_device_ops cvm_oct_xaui_netdev_ops = {
|
||||
.ndo_init = cvm_oct_xaui_init,
|
||||
.ndo_uninit = cvm_oct_xaui_uninit,
|
||||
.ndo_open = cvm_oct_xaui_open,
|
||||
.ndo_stop = cvm_oct_xaui_stop,
|
||||
.ndo_start_xmit = cvm_oct_xmit,
|
||||
.ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
|
||||
.ndo_set_mac_address = cvm_oct_common_set_mac_address,
|
||||
.ndo_do_ioctl = cvm_oct_ioctl,
|
||||
.ndo_change_mtu = cvm_oct_common_change_mtu,
|
||||
.ndo_get_stats = cvm_oct_common_get_stats,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = cvm_oct_poll_controller,
|
||||
#endif
|
||||
};
|
||||
static const struct net_device_ops cvm_oct_sgmii_netdev_ops = {
|
||||
.ndo_init = cvm_oct_sgmii_init,
|
||||
.ndo_uninit = cvm_oct_sgmii_uninit,
|
||||
.ndo_open = cvm_oct_sgmii_open,
|
||||
.ndo_stop = cvm_oct_sgmii_stop,
|
||||
.ndo_start_xmit = cvm_oct_xmit,
|
||||
.ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
|
||||
.ndo_set_mac_address = cvm_oct_common_set_mac_address,
|
||||
.ndo_do_ioctl = cvm_oct_ioctl,
|
||||
.ndo_change_mtu = cvm_oct_common_change_mtu,
|
||||
.ndo_get_stats = cvm_oct_common_get_stats,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = cvm_oct_poll_controller,
|
||||
#endif
|
||||
};
|
||||
static const struct net_device_ops cvm_oct_spi_netdev_ops = {
|
||||
.ndo_init = cvm_oct_spi_init,
|
||||
.ndo_uninit = cvm_oct_spi_uninit,
|
||||
.ndo_start_xmit = cvm_oct_xmit,
|
||||
.ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
|
||||
.ndo_set_mac_address = cvm_oct_common_set_mac_address,
|
||||
.ndo_do_ioctl = cvm_oct_ioctl,
|
||||
.ndo_change_mtu = cvm_oct_common_change_mtu,
|
||||
.ndo_get_stats = cvm_oct_common_get_stats,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = cvm_oct_poll_controller,
|
||||
#endif
|
||||
};
|
||||
static const struct net_device_ops cvm_oct_rgmii_netdev_ops = {
|
||||
.ndo_init = cvm_oct_rgmii_init,
|
||||
.ndo_uninit = cvm_oct_rgmii_uninit,
|
||||
.ndo_open = cvm_oct_rgmii_open,
|
||||
.ndo_stop = cvm_oct_rgmii_stop,
|
||||
.ndo_start_xmit = cvm_oct_xmit,
|
||||
.ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
|
||||
.ndo_set_mac_address = cvm_oct_common_set_mac_address,
|
||||
.ndo_do_ioctl = cvm_oct_ioctl,
|
||||
.ndo_change_mtu = cvm_oct_common_change_mtu,
|
||||
.ndo_get_stats = cvm_oct_common_get_stats,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = cvm_oct_poll_controller,
|
||||
#endif
|
||||
};
|
||||
static const struct net_device_ops cvm_oct_pow_netdev_ops = {
|
||||
.ndo_init = cvm_oct_common_init,
|
||||
.ndo_start_xmit = cvm_oct_xmit_pow,
|
||||
.ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
|
||||
.ndo_set_mac_address = cvm_oct_common_set_mac_address,
|
||||
.ndo_do_ioctl = cvm_oct_ioctl,
|
||||
.ndo_change_mtu = cvm_oct_common_change_mtu,
|
||||
.ndo_get_stats = cvm_oct_common_get_stats,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = cvm_oct_poll_controller,
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Module/ driver initialization. Creates the linux network
|
||||
* devices.
|
||||
|
@ -303,7 +663,7 @@ static int __init cvm_oct_init_module(void)
|
|||
struct octeon_ethernet *priv = netdev_priv(dev);
|
||||
memset(priv, 0, sizeof(struct octeon_ethernet));
|
||||
|
||||
dev->init = cvm_oct_common_init;
|
||||
dev->netdev_ops = &cvm_oct_pow_netdev_ops;
|
||||
priv->imode = CVMX_HELPER_INTERFACE_MODE_DISABLED;
|
||||
priv->port = CVMX_PIP_NUM_INPUT_PORTS;
|
||||
priv->queue = -1;
|
||||
|
@ -372,44 +732,38 @@ static int __init cvm_oct_init_module(void)
|
|||
break;
|
||||
|
||||
case CVMX_HELPER_INTERFACE_MODE_NPI:
|
||||
dev->init = cvm_oct_common_init;
|
||||
dev->uninit = cvm_oct_common_uninit;
|
||||
dev->netdev_ops = &cvm_oct_npi_netdev_ops;
|
||||
strcpy(dev->name, "npi%d");
|
||||
break;
|
||||
|
||||
case CVMX_HELPER_INTERFACE_MODE_XAUI:
|
||||
dev->init = cvm_oct_xaui_init;
|
||||
dev->uninit = cvm_oct_xaui_uninit;
|
||||
dev->netdev_ops = &cvm_oct_xaui_netdev_ops;
|
||||
strcpy(dev->name, "xaui%d");
|
||||
break;
|
||||
|
||||
case CVMX_HELPER_INTERFACE_MODE_LOOP:
|
||||
dev->init = cvm_oct_common_init;
|
||||
dev->uninit = cvm_oct_common_uninit;
|
||||
dev->netdev_ops = &cvm_oct_npi_netdev_ops;
|
||||
strcpy(dev->name, "loop%d");
|
||||
break;
|
||||
|
||||
case CVMX_HELPER_INTERFACE_MODE_SGMII:
|
||||
dev->init = cvm_oct_sgmii_init;
|
||||
dev->uninit = cvm_oct_sgmii_uninit;
|
||||
dev->netdev_ops = &cvm_oct_sgmii_netdev_ops;
|
||||
strcpy(dev->name, "eth%d");
|
||||
break;
|
||||
|
||||
case CVMX_HELPER_INTERFACE_MODE_SPI:
|
||||
dev->init = cvm_oct_spi_init;
|
||||
dev->uninit = cvm_oct_spi_uninit;
|
||||
dev->netdev_ops = &cvm_oct_spi_netdev_ops;
|
||||
strcpy(dev->name, "spi%d");
|
||||
break;
|
||||
|
||||
case CVMX_HELPER_INTERFACE_MODE_RGMII:
|
||||
case CVMX_HELPER_INTERFACE_MODE_GMII:
|
||||
dev->init = cvm_oct_rgmii_init;
|
||||
dev->uninit = cvm_oct_rgmii_uninit;
|
||||
dev->netdev_ops = &cvm_oct_rgmii_netdev_ops;
|
||||
strcpy(dev->name, "eth%d");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!dev->init) {
|
||||
if (!dev->netdev_ops) {
|
||||
kfree(dev);
|
||||
} else if (register_netdev(dev) < 0) {
|
||||
pr_err("Failed to register ethernet device "
|
||||
|
|
|
@ -111,12 +111,23 @@ static inline int cvm_oct_transmit(struct net_device *dev,
|
|||
|
||||
extern int cvm_oct_rgmii_init(struct net_device *dev);
|
||||
extern void cvm_oct_rgmii_uninit(struct net_device *dev);
|
||||
extern int cvm_oct_rgmii_open(struct net_device *dev);
|
||||
extern int cvm_oct_rgmii_stop(struct net_device *dev);
|
||||
|
||||
extern int cvm_oct_sgmii_init(struct net_device *dev);
|
||||
extern void cvm_oct_sgmii_uninit(struct net_device *dev);
|
||||
extern int cvm_oct_sgmii_open(struct net_device *dev);
|
||||
extern int cvm_oct_sgmii_stop(struct net_device *dev);
|
||||
|
||||
extern int cvm_oct_spi_init(struct net_device *dev);
|
||||
extern void cvm_oct_spi_uninit(struct net_device *dev);
|
||||
extern int cvm_oct_xaui_init(struct net_device *dev);
|
||||
extern void cvm_oct_xaui_uninit(struct net_device *dev);
|
||||
extern int cvm_oct_xaui_open(struct net_device *dev);
|
||||
extern int cvm_oct_xaui_stop(struct net_device *dev);
|
||||
|
||||
extern int cvm_oct_common_init(struct net_device *dev);
|
||||
extern void cvm_oct_common_uninit(struct net_device *dev);
|
||||
|
||||
extern int always_use_pow;
|
||||
extern int pow_send_group;
|
||||
|
|
Loading…
Reference in New Issue
Block a user