Commit 8d491953 authored by Alessandro Rubini's avatar Alessandro Rubini

Tom's sources, from svn:software/drivers (rev. 623)

This is a simple copy for files from the white-rabbit svn,
currently at revision 623. No local modification is there
at this commit. The author of the code is Tomasz Wlostowski,
even though I haven't marked him as --author (lazy me).
parent e55357b6
include ../../Makedefs
all:
cd wr_vic && ./build.sh && cd ..
cd wr_minic && ./build.sh && cd ..
cp wr_minic/*.ko wr_vic/*.ko bin
clean:
cd wr_vic && ./build.sh clean && cd ..
cd wr_minic && ./build.sh clean && cd ..
deploy: all
mkdir -p $(WR_INSTALL_ROOT)/lib
mkdir -p $(WR_INSTALL_ROOT)/lib/modules
cp bin/*.ko $(WR_INSTALL_ROOT)/lib/modules
run: all
scp bin/*.ko root@$(T):/wr/lib/modules
\ No newline at end of file
obj-m := wr_minic.o
KDIR := ../../../kernel
PWD := $(shell pwd)
EXTRA_CFLAGS := -I$(SUBDIRS)/../wr_vic
MAKE = make
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
\ No newline at end of file
This is a very simple, but working kernel driver for WhiteRabbit mini-NIC (hdl/modules/wrsw_mini_nic) with proper WR timestamping.
TODO:
- add calibration/DMTD ioctls()
- add support for more than 1 endpoint + miNIC (configurable platform_devices)
- add NAPI polling
- add support for sending multiple descriptors (TX ring buffer)
- cleanup, adapt to kernel coding rules
- add TX_TS interrupt handler for proper reception of TX timestamps
BUGS:
- sometimes drops a warning like this one:
# ping 192.168.100.1
PING 192.168.100.1 (192.168.100.1): 56 data bytes
------------[ cut here ]------------
WARNING: at kernel/softirq.c:143 local_bh_enable+0x44/0xac()
Modules linked in: wr_minic whiterabbit_vic
[<c00291f8>] (unwind_backtrace+0x0/0xf0) from [<c00390fc>] (warn_slowpath_common+0x4c/0x64)
[<c00390fc>] (warn_slowpath_common+0x4c/0x64) from [<c003912c>] (warn_slowpath_null+0x18/0x1c)
[<c003912c>] (warn_slowpath_null+0x18/0x1c) from [<c003e23c>] (local_bh_enable+0x44/0xac)
[<c003e23c>] (local_bh_enable+0x44/0xac) from [<c01982d0>] (neigh_lookup+0xb0/0xb8)
[<c01982d0>] (neigh_lookup+0xb0/0xb8) from [<c01ccd10>] (arp_process+0x514/0x680)
[<c01ccd10>] (arp_process+0x514/0x680) from [<c018ece8>] (__netif_receive_skb+0x244/0x26c)
[<c018ece8>] (__netif_receive_skb+0x244/0x26c) from [<bf01484c>] (minic_rx_frame+0x1f4/0x238 [wr_minic])
[<bf01484c>] (minic_rx_frame+0x1f4/0x238 [wr_minic]) from [<00000002>] (0x2)
---[ end trace b836ae4c93691b2b ]---
- fix compilation warning:
MODPOST 1 modules
WARNING: "wrmch_vic_request_irq" [/home/slayer/wrdev-new/software/drivers/wr_minic/wr-minic.ko] undefined!
WARNING: "wrmch_vic_free_irq" [/home/slayer/wrdev-new/software/drivers/wr_minic/wr-minic.ko] undefined!
\ No newline at end of file
#!/bin/sh
. ../../../settings
make CONFIG_DEBUG_SECTION_MISMATCH=y ARCH=arm CROSS_COMPILE=$CROSS_COMPILE_ARM -C ../../../kernel SUBDIRS=`pwd` modules $1
#cp wr_minic.ko ../bin
\ No newline at end of file
/*
Register definitions for slave core: WR Endpoint 1000base-X TBI PCS register block
* File : ../../../software/include/hw/endpoint_mdio.h
* Author : auto-generated by wbgen2 from pcs_regs.wb
* Created : Wed Nov 3 19:00:12 2010
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE pcs_regs.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_PCS_REGS_WB
#define __WBGEN2_REGDEFS_PCS_REGS_WB
#include <inttypes.h>
#if defined( __GNUC__)
#define PACKED __attribute__ ((packed))
#else
#error "Unsupported compiler?"
#endif
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: MDIO Control Register */
/* definitions for field: Reserved in reg: MDIO Control Register */
#define MDIO_MCR_RESV_MASK WBGEN2_GEN_MASK(0, 5)
#define MDIO_MCR_RESV_SHIFT 0
#define MDIO_MCR_RESV_W(value) WBGEN2_GEN_WRITE(value, 0, 5)
#define MDIO_MCR_RESV_R(reg) WBGEN2_GEN_READ(reg, 0, 5)
/* definitions for field: Unidirectional Enable in reg: MDIO Control Register */
#define MDIO_MCR_UNI_EN WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Speed Selection (MSB) in reg: MDIO Control Register */
#define MDIO_MCR_SPEED1000_MASK WBGEN2_GEN_MASK(6, 1)
#define MDIO_MCR_SPEED1000_SHIFT 6
#define MDIO_MCR_SPEED1000_W(value) WBGEN2_GEN_WRITE(value, 6, 1)
#define MDIO_MCR_SPEED1000_R(reg) WBGEN2_GEN_READ(reg, 6, 1)
/* definitions for field: Collision Test in reg: MDIO Control Register */
#define MDIO_MCR_CTST_MASK WBGEN2_GEN_MASK(7, 1)
#define MDIO_MCR_CTST_SHIFT 7
#define MDIO_MCR_CTST_W(value) WBGEN2_GEN_WRITE(value, 7, 1)
#define MDIO_MCR_CTST_R(reg) WBGEN2_GEN_READ(reg, 7, 1)
/* definitions for field: Duplex Mode in reg: MDIO Control Register */
#define MDIO_MCR_FULLDPLX_MASK WBGEN2_GEN_MASK(8, 1)
#define MDIO_MCR_FULLDPLX_SHIFT 8
#define MDIO_MCR_FULLDPLX_W(value) WBGEN2_GEN_WRITE(value, 8, 1)
#define MDIO_MCR_FULLDPLX_R(reg) WBGEN2_GEN_READ(reg, 8, 1)
/* definitions for field: Restart Auto-Negotiation in reg: MDIO Control Register */
#define MDIO_MCR_ANRESTART WBGEN2_GEN_MASK(9, 1)
/* definitions for field: Isolate in reg: MDIO Control Register */
#define MDIO_MCR_ISOLATE_MASK WBGEN2_GEN_MASK(10, 1)
#define MDIO_MCR_ISOLATE_SHIFT 10
#define MDIO_MCR_ISOLATE_W(value) WBGEN2_GEN_WRITE(value, 10, 1)
#define MDIO_MCR_ISOLATE_R(reg) WBGEN2_GEN_READ(reg, 10, 1)
/* definitions for field: Power Down in reg: MDIO Control Register */
#define MDIO_MCR_PDOWN WBGEN2_GEN_MASK(11, 1)
/* definitions for field: Auto-Negotiation Enable in reg: MDIO Control Register */
#define MDIO_MCR_ANENABLE WBGEN2_GEN_MASK(12, 1)
/* definitions for field: Speed Selection (LSB) in reg: MDIO Control Register */
#define MDIO_MCR_SPEED100_MASK WBGEN2_GEN_MASK(13, 1)
#define MDIO_MCR_SPEED100_SHIFT 13
#define MDIO_MCR_SPEED100_W(value) WBGEN2_GEN_WRITE(value, 13, 1)
#define MDIO_MCR_SPEED100_R(reg) WBGEN2_GEN_READ(reg, 13, 1)
/* definitions for field: Loopback in reg: MDIO Control Register */
#define MDIO_MCR_LOOPBACK WBGEN2_GEN_MASK(14, 1)
/* definitions for field: Reset in reg: MDIO Control Register */
#define MDIO_MCR_RESET WBGEN2_GEN_MASK(15, 1)
/* definitions for register: MDIO Status Register */
/* definitions for field: Extended Capability in reg: MDIO Status Register */
#define MDIO_MSR_ERCAP_MASK WBGEN2_GEN_MASK(0, 1)
#define MDIO_MSR_ERCAP_SHIFT 0
#define MDIO_MSR_ERCAP_W(value) WBGEN2_GEN_WRITE(value, 0, 1)
#define MDIO_MSR_ERCAP_R(reg) WBGEN2_GEN_READ(reg, 0, 1)
/* definitions for field: Jabber Detect in reg: MDIO Status Register */
#define MDIO_MSR_JCD_MASK WBGEN2_GEN_MASK(1, 1)
#define MDIO_MSR_JCD_SHIFT 1
#define MDIO_MSR_JCD_W(value) WBGEN2_GEN_WRITE(value, 1, 1)
#define MDIO_MSR_JCD_R(reg) WBGEN2_GEN_READ(reg, 1, 1)
/* definitions for field: Link Status in reg: MDIO Status Register */
#define MDIO_MSR_LSTATUS WBGEN2_GEN_MASK(2, 1)
/* definitions for field: Auto-Negotiation Ability in reg: MDIO Status Register */
#define MDIO_MSR_ANEGCAPABLE_MASK WBGEN2_GEN_MASK(3, 1)
#define MDIO_MSR_ANEGCAPABLE_SHIFT 3
#define MDIO_MSR_ANEGCAPABLE_W(value) WBGEN2_GEN_WRITE(value, 3, 1)
#define MDIO_MSR_ANEGCAPABLE_R(reg) WBGEN2_GEN_READ(reg, 3, 1)
/* definitions for field: Remote Fault in reg: MDIO Status Register */
#define MDIO_MSR_RFAULT WBGEN2_GEN_MASK(4, 1)
/* definitions for field: Auto-Negotiation Complete in reg: MDIO Status Register */
#define MDIO_MSR_ANEGCOMPLETE WBGEN2_GEN_MASK(5, 1)
/* definitions for field: MF Preamble Suppression in reg: MDIO Status Register */
#define MDIO_MSR_MFSUPPRESS_MASK WBGEN2_GEN_MASK(6, 1)
#define MDIO_MSR_MFSUPPRESS_SHIFT 6
#define MDIO_MSR_MFSUPPRESS_W(value) WBGEN2_GEN_WRITE(value, 6, 1)
#define MDIO_MSR_MFSUPPRESS_R(reg) WBGEN2_GEN_READ(reg, 6, 1)
/* definitions for field: Unidirectional Ability in reg: MDIO Status Register */
#define MDIO_MSR_UNIDIRABLE_MASK WBGEN2_GEN_MASK(7, 1)
#define MDIO_MSR_UNIDIRABLE_SHIFT 7
#define MDIO_MSR_UNIDIRABLE_W(value) WBGEN2_GEN_WRITE(value, 7, 1)
#define MDIO_MSR_UNIDIRABLE_R(reg) WBGEN2_GEN_READ(reg, 7, 1)
/* definitions for field: Extended Status Capable in reg: MDIO Status Register */
#define MDIO_MSR_ESTATEN_MASK WBGEN2_GEN_MASK(8, 1)
#define MDIO_MSR_ESTATEN_SHIFT 8
#define MDIO_MSR_ESTATEN_W(value) WBGEN2_GEN_WRITE(value, 8, 1)
#define MDIO_MSR_ESTATEN_R(reg) WBGEN2_GEN_READ(reg, 8, 1)
/* definitions for field: 100BASE-T2 Half Duplex in reg: MDIO Status Register */
#define MDIO_MSR_100HALF2_MASK WBGEN2_GEN_MASK(9, 1)
#define MDIO_MSR_100HALF2_SHIFT 9
#define MDIO_MSR_100HALF2_W(value) WBGEN2_GEN_WRITE(value, 9, 1)
#define MDIO_MSR_100HALF2_R(reg) WBGEN2_GEN_READ(reg, 9, 1)
/* definitions for field: 100BASE-T2 Full Duplex in reg: MDIO Status Register */
#define MDIO_MSR_100FULL2_MASK WBGEN2_GEN_MASK(10, 1)
#define MDIO_MSR_100FULL2_SHIFT 10
#define MDIO_MSR_100FULL2_W(value) WBGEN2_GEN_WRITE(value, 10, 1)
#define MDIO_MSR_100FULL2_R(reg) WBGEN2_GEN_READ(reg, 10, 1)
/* definitions for field: 10 Mbps Half Duplex in reg: MDIO Status Register */
#define MDIO_MSR_10HALF_MASK WBGEN2_GEN_MASK(11, 1)
#define MDIO_MSR_10HALF_SHIFT 11
#define MDIO_MSR_10HALF_W(value) WBGEN2_GEN_WRITE(value, 11, 1)
#define MDIO_MSR_10HALF_R(reg) WBGEN2_GEN_READ(reg, 11, 1)
/* definitions for field: 10 Mbps Full Duplex in reg: MDIO Status Register */
#define MDIO_MSR_10FULL_MASK WBGEN2_GEN_MASK(12, 1)
#define MDIO_MSR_10FULL_SHIFT 12
#define MDIO_MSR_10FULL_W(value) WBGEN2_GEN_WRITE(value, 12, 1)
#define MDIO_MSR_10FULL_R(reg) WBGEN2_GEN_READ(reg, 12, 1)
/* definitions for field: 100BASE-X Half Duplex in reg: MDIO Status Register */
#define MDIO_MSR_100HALF_MASK WBGEN2_GEN_MASK(13, 1)
#define MDIO_MSR_100HALF_SHIFT 13
#define MDIO_MSR_100HALF_W(value) WBGEN2_GEN_WRITE(value, 13, 1)
#define MDIO_MSR_100HALF_R(reg) WBGEN2_GEN_READ(reg, 13, 1)
/* definitions for field: 100BASE-X Full Duplex in reg: MDIO Status Register */
#define MDIO_MSR_100FULL_MASK WBGEN2_GEN_MASK(14, 1)
#define MDIO_MSR_100FULL_SHIFT 14
#define MDIO_MSR_100FULL_W(value) WBGEN2_GEN_WRITE(value, 14, 1)
#define MDIO_MSR_100FULL_R(reg) WBGEN2_GEN_READ(reg, 14, 1)
/* definitions for field: 100BASE-T4 in reg: MDIO Status Register */
#define MDIO_MSR_100BASE4_MASK WBGEN2_GEN_MASK(15, 1)
#define MDIO_MSR_100BASE4_SHIFT 15
#define MDIO_MSR_100BASE4_W(value) WBGEN2_GEN_WRITE(value, 15, 1)
#define MDIO_MSR_100BASE4_R(reg) WBGEN2_GEN_READ(reg, 15, 1)
/* definitions for register: MDIO PHY Identification Register 1 */
/* definitions for field: Organizationally Unique Identifier (bits 7-21) in reg: MDIO PHY Identification Register 1 */
#define MDIO_PHYSID1_OUI_MASK WBGEN2_GEN_MASK(0, 16)
#define MDIO_PHYSID1_OUI_SHIFT 0
#define MDIO_PHYSID1_OUI_W(value) WBGEN2_GEN_WRITE(value, 0, 16)
#define MDIO_PHYSID1_OUI_R(reg) WBGEN2_GEN_READ(reg, 0, 16)
/* definitions for register: MDIO PHY Identification Register 2 */
/* definitions for field: Revision Number in reg: MDIO PHY Identification Register 2 */
#define MDIO_PHYSID2_REV_NUM_MASK WBGEN2_GEN_MASK(0, 4)
#define MDIO_PHYSID2_REV_NUM_SHIFT 0
#define MDIO_PHYSID2_REV_NUM_W(value) WBGEN2_GEN_WRITE(value, 0, 4)
#define MDIO_PHYSID2_REV_NUM_R(reg) WBGEN2_GEN_READ(reg, 0, 4)
/* definitions for field: Manufacturer Model Number in reg: MDIO PHY Identification Register 2 */
#define MDIO_PHYSID2_MMNUM_MASK WBGEN2_GEN_MASK(4, 6)
#define MDIO_PHYSID2_MMNUM_SHIFT 4
#define MDIO_PHYSID2_MMNUM_W(value) WBGEN2_GEN_WRITE(value, 4, 6)
#define MDIO_PHYSID2_MMNUM_R(reg) WBGEN2_GEN_READ(reg, 4, 6)
/* definitions for field: Organizationally Unique Identifier (bits 0-5) in reg: MDIO PHY Identification Register 2 */
#define MDIO_PHYSID2_OUI_MASK WBGEN2_GEN_MASK(10, 6)
#define MDIO_PHYSID2_OUI_SHIFT 10
#define MDIO_PHYSID2_OUI_W(value) WBGEN2_GEN_WRITE(value, 10, 6)
#define MDIO_PHYSID2_OUI_R(reg) WBGEN2_GEN_READ(reg, 10, 6)
/* definitions for register: MDIO Auto-Negotiation Advertisement Register */
/* definitions for field: Reserved in reg: MDIO Auto-Negotiation Advertisement Register */
#define MDIO_ADVERTISE_RSVD3_MASK WBGEN2_GEN_MASK(0, 5)
#define MDIO_ADVERTISE_RSVD3_SHIFT 0
#define MDIO_ADVERTISE_RSVD3_W(value) WBGEN2_GEN_WRITE(value, 0, 5)
#define MDIO_ADVERTISE_RSVD3_R(reg) WBGEN2_GEN_READ(reg, 0, 5)
/* definitions for field: Full Duplex in reg: MDIO Auto-Negotiation Advertisement Register */
#define MDIO_ADVERTISE_FULL_MASK WBGEN2_GEN_MASK(5, 1)
#define MDIO_ADVERTISE_FULL_SHIFT 5
#define MDIO_ADVERTISE_FULL_W(value) WBGEN2_GEN_WRITE(value, 5, 1)
#define MDIO_ADVERTISE_FULL_R(reg) WBGEN2_GEN_READ(reg, 5, 1)
/* definitions for field: Half Duplex in reg: MDIO Auto-Negotiation Advertisement Register */
#define MDIO_ADVERTISE_HALF_MASK WBGEN2_GEN_MASK(6, 1)
#define MDIO_ADVERTISE_HALF_SHIFT 6
#define MDIO_ADVERTISE_HALF_W(value) WBGEN2_GEN_WRITE(value, 6, 1)
#define MDIO_ADVERTISE_HALF_R(reg) WBGEN2_GEN_READ(reg, 6, 1)
/* definitions for field: Pause in reg: MDIO Auto-Negotiation Advertisement Register */
#define MDIO_ADVERTISE_PAUSE_MASK WBGEN2_GEN_MASK(7, 2)
#define MDIO_ADVERTISE_PAUSE_SHIFT 7
#define MDIO_ADVERTISE_PAUSE_W(value) WBGEN2_GEN_WRITE(value, 7, 2)
#define MDIO_ADVERTISE_PAUSE_R(reg) WBGEN2_GEN_READ(reg, 7, 2)
/* definitions for field: Reserved in reg: MDIO Auto-Negotiation Advertisement Register */
#define MDIO_ADVERTISE_RSVD2_MASK WBGEN2_GEN_MASK(9, 3)
#define MDIO_ADVERTISE_RSVD2_SHIFT 9
#define MDIO_ADVERTISE_RSVD2_W(value) WBGEN2_GEN_WRITE(value, 9, 3)
#define MDIO_ADVERTISE_RSVD2_R(reg) WBGEN2_GEN_READ(reg, 9, 3)
/* definitions for field: Remote Fault in reg: MDIO Auto-Negotiation Advertisement Register */
#define MDIO_ADVERTISE_RFAULT_MASK WBGEN2_GEN_MASK(12, 2)
#define MDIO_ADVERTISE_RFAULT_SHIFT 12
#define MDIO_ADVERTISE_RFAULT_W(value) WBGEN2_GEN_WRITE(value, 12, 2)
#define MDIO_ADVERTISE_RFAULT_R(reg) WBGEN2_GEN_READ(reg, 12, 2)
/* definitions for field: Reserved in reg: MDIO Auto-Negotiation Advertisement Register */
#define MDIO_ADVERTISE_RSVD1_MASK WBGEN2_GEN_MASK(14, 1)
#define MDIO_ADVERTISE_RSVD1_SHIFT 14
#define MDIO_ADVERTISE_RSVD1_W(value) WBGEN2_GEN_WRITE(value, 14, 1)
#define MDIO_ADVERTISE_RSVD1_R(reg) WBGEN2_GEN_READ(reg, 14, 1)
/* definitions for field: Next Page in reg: MDIO Auto-Negotiation Advertisement Register */
#define MDIO_ADVERTISE_NPAGE_MASK WBGEN2_GEN_MASK(15, 1)
#define MDIO_ADVERTISE_NPAGE_SHIFT 15
#define MDIO_ADVERTISE_NPAGE_W(value) WBGEN2_GEN_WRITE(value, 15, 1)
#define MDIO_ADVERTISE_NPAGE_R(reg) WBGEN2_GEN_READ(reg, 15, 1)
/* definitions for register: MDIO Auto-Negotiation Link Partner Ability Register */
/* definitions for field: Reserved in reg: MDIO Auto-Negotiation Link Partner Ability Register */
#define MDIO_LPA_RSVD3_MASK WBGEN2_GEN_MASK(0, 5)
#define MDIO_LPA_RSVD3_SHIFT 0
#define MDIO_LPA_RSVD3_W(value) WBGEN2_GEN_WRITE(value, 0, 5)
#define MDIO_LPA_RSVD3_R(reg) WBGEN2_GEN_READ(reg, 0, 5)
/* definitions for field: Full Duplex in reg: MDIO Auto-Negotiation Link Partner Ability Register */
#define MDIO_LPA_FULL WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Half Duplex in reg: MDIO Auto-Negotiation Link Partner Ability Register */
#define MDIO_LPA_HALF WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Pause in reg: MDIO Auto-Negotiation Link Partner Ability Register */
#define MDIO_LPA_PAUSE_MASK WBGEN2_GEN_MASK(7, 2)
#define MDIO_LPA_PAUSE_SHIFT 7
#define MDIO_LPA_PAUSE_W(value) WBGEN2_GEN_WRITE(value, 7, 2)
#define MDIO_LPA_PAUSE_R(reg) WBGEN2_GEN_READ(reg, 7, 2)
/* definitions for field: Reserved in reg: MDIO Auto-Negotiation Link Partner Ability Register */
#define MDIO_LPA_RSVD2_MASK WBGEN2_GEN_MASK(9, 3)
#define MDIO_LPA_RSVD2_SHIFT 9
#define MDIO_LPA_RSVD2_W(value) WBGEN2_GEN_WRITE(value, 9, 3)
#define MDIO_LPA_RSVD2_R(reg) WBGEN2_GEN_READ(reg, 9, 3)
/* definitions for field: Remote Fault in reg: MDIO Auto-Negotiation Link Partner Ability Register */
#define MDIO_LPA_RFAULT_MASK WBGEN2_GEN_MASK(12, 2)
#define MDIO_LPA_RFAULT_SHIFT 12
#define MDIO_LPA_RFAULT_W(value) WBGEN2_GEN_WRITE(value, 12, 2)
#define MDIO_LPA_RFAULT_R(reg) WBGEN2_GEN_READ(reg, 12, 2)
/* definitions for field: Acknowledge in reg: MDIO Auto-Negotiation Link Partner Ability Register */
#define MDIO_LPA_LPACK WBGEN2_GEN_MASK(14, 1)
/* definitions for field: Next Page in reg: MDIO Auto-Negotiation Link Partner Ability Register */
#define MDIO_LPA_NPAGE WBGEN2_GEN_MASK(15, 1)
/* definitions for register: MDIO Auto-Negotiation Expansion Register */
/* definitions for field: Reserved in reg: MDIO Auto-Negotiation Expansion Register */
#define MDIO_EXPANSION_RSVD1_MASK WBGEN2_GEN_MASK(0, 1)
#define MDIO_EXPANSION_RSVD1_SHIFT 0
#define MDIO_EXPANSION_RSVD1_W(value) WBGEN2_GEN_WRITE(value, 0, 1)
#define MDIO_EXPANSION_RSVD1_R(reg) WBGEN2_GEN_READ(reg, 0, 1)
/* definitions for field: Page Received in reg: MDIO Auto-Negotiation Expansion Register */
#define MDIO_EXPANSION_LWCP_MASK WBGEN2_GEN_MASK(1, 1)
#define MDIO_EXPANSION_LWCP_SHIFT 1
#define MDIO_EXPANSION_LWCP_W(value) WBGEN2_GEN_WRITE(value, 1, 1)
#define MDIO_EXPANSION_LWCP_R(reg) WBGEN2_GEN_READ(reg, 1, 1)
/* definitions for field: Next Page Able in reg: MDIO Auto-Negotiation Expansion Register */
#define MDIO_EXPANSION_ENABLENPAGE_MASK WBGEN2_GEN_MASK(2, 1)
#define MDIO_EXPANSION_ENABLENPAGE_SHIFT 2
#define MDIO_EXPANSION_ENABLENPAGE_W(value) WBGEN2_GEN_WRITE(value, 2, 1)
#define MDIO_EXPANSION_ENABLENPAGE_R(reg) WBGEN2_GEN_READ(reg, 2, 1)
/* definitions for field: Reserved in reg: MDIO Auto-Negotiation Expansion Register */
#define MDIO_EXPANSION_RSVD2_MASK WBGEN2_GEN_MASK(3, 13)
#define MDIO_EXPANSION_RSVD2_SHIFT 3
#define MDIO_EXPANSION_RSVD2_W(value) WBGEN2_GEN_WRITE(value, 3, 13)
#define MDIO_EXPANSION_RSVD2_R(reg) WBGEN2_GEN_READ(reg, 3, 13)
/* definitions for register: MDIO Extended Status Register */
/* definitions for field: Reserved in reg: MDIO Extended Status Register */
#define MDIO_ESTATUS_RSVD1_MASK WBGEN2_GEN_MASK(0, 12)
#define MDIO_ESTATUS_RSVD1_SHIFT 0
#define MDIO_ESTATUS_RSVD1_W(value) WBGEN2_GEN_WRITE(value, 0, 12)
#define MDIO_ESTATUS_RSVD1_R(reg) WBGEN2_GEN_READ(reg, 0, 12)
/* definitions for field: 1000Base-T Half Duplex in reg: MDIO Extended Status Register */
#define MDIO_ESTATUS_1000_THALF_MASK WBGEN2_GEN_MASK(12, 1)
#define MDIO_ESTATUS_1000_THALF_SHIFT 12
#define MDIO_ESTATUS_1000_THALF_W(value) WBGEN2_GEN_WRITE(value, 12, 1)
#define MDIO_ESTATUS_1000_THALF_R(reg) WBGEN2_GEN_READ(reg, 12, 1)
/* definitions for field: 1000Base-T Full Duplex in reg: MDIO Extended Status Register */
#define MDIO_ESTATUS_1000_TFULL_MASK WBGEN2_GEN_MASK(13, 1)
#define MDIO_ESTATUS_1000_TFULL_SHIFT 13
#define MDIO_ESTATUS_1000_TFULL_W(value) WBGEN2_GEN_WRITE(value, 13, 1)
#define MDIO_ESTATUS_1000_TFULL_R(reg) WBGEN2_GEN_READ(reg, 13, 1)
/* definitions for field: 1000Base-X Half Duplex in reg: MDIO Extended Status Register */
#define MDIO_ESTATUS_1000_XHALF_MASK WBGEN2_GEN_MASK(14, 1)
#define MDIO_ESTATUS_1000_XHALF_SHIFT 14
#define MDIO_ESTATUS_1000_XHALF_W(value) WBGEN2_GEN_WRITE(value, 14, 1)
#define MDIO_ESTATUS_1000_XHALF_R(reg) WBGEN2_GEN_READ(reg, 14, 1)
/* definitions for field: 1000Base-X Full Duplex in reg: MDIO Extended Status Register */
#define MDIO_ESTATUS_1000_XFULL_MASK WBGEN2_GEN_MASK(15, 1)
#define MDIO_ESTATUS_1000_XFULL_SHIFT 15
#define MDIO_ESTATUS_1000_XFULL_W(value) WBGEN2_GEN_WRITE(value, 15, 1)
#define MDIO_ESTATUS_1000_XFULL_R(reg) WBGEN2_GEN_READ(reg, 15, 1)
/* definitions for register: WhiteRabbit-specific Configuration Register */
/* definitions for field: TX Calibration Pattern in reg: WhiteRabbit-specific Configuration Register */
#define MDIO_WR_SPEC_TX_CAL WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Calibration Pattern RX Status in reg: WhiteRabbit-specific Configuration Register */
#define MDIO_WR_SPEC_RX_CAL_STAT WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Reset calibration counter in reg: WhiteRabbit-specific Configuration Register */
#define MDIO_WR_SPEC_CAL_CRST WBGEN2_GEN_MASK(2, 1)
/* [0x0]: REG MDIO Control Register */
#define MDIO_REG_MCR 0x00000000
/* [0x4]: REG MDIO Status Register */
#define MDIO_REG_MSR 0x00000004
/* [0x8]: REG MDIO PHY Identification Register 1 */
#define MDIO_REG_PHYSID1 0x00000008
/* [0xc]: REG MDIO PHY Identification Register 2 */
#define MDIO_REG_PHYSID2 0x0000000c
/* [0x10]: REG MDIO Auto-Negotiation Advertisement Register */
#define MDIO_REG_ADVERTISE 0x00000010
/* [0x14]: REG MDIO Auto-Negotiation Link Partner Ability Register */
#define MDIO_REG_LPA 0x00000014
/* [0x18]: REG MDIO Auto-Negotiation Expansion Register */
#define MDIO_REG_EXPANSION 0x00000018
/* [0x3c]: REG MDIO Extended Status Register */
#define MDIO_REG_ESTATUS 0x0000003c
/* [0x40]: REG WhiteRabbit-specific Configuration Register */
#define MDIO_REG_WR_SPEC 0x00000040
#endif
/*
Register definitions for slave core: WR switch endpoint controller
* File : ../../../software/include/hw/endpoint_regs.h
* Author : auto-generated by wbgen2 from ep_wishbone_controller.wb
* Created : Wed Nov 3 19:00:12 2010
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE ep_wishbone_controller.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_EP_WISHBONE_CONTROLLER_WB
#define __WBGEN2_REGDEFS_EP_WISHBONE_CONTROLLER_WB
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: Endpoint Control Register */
/* definitions for field: Port identifier in reg: Endpoint Control Register */
#define EP_ECR_PORTID_MASK WBGEN2_GEN_MASK(0, 5)
#define EP_ECR_PORTID_SHIFT 0
#define EP_ECR_PORTID_W(value) WBGEN2_GEN_WRITE(value, 0, 5)
#define EP_ECR_PORTID_R(reg) WBGEN2_GEN_READ(reg, 0, 5)
/* definitions for field: Reset event counters in reg: Endpoint Control Register */
#define EP_ECR_RST_CNT WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Transmit framer enable in reg: Endpoint Control Register */
#define EP_ECR_TX_EN_FRA WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Receive deframer enable in reg: Endpoint Control Register */
#define EP_ECR_RX_EN_FRA WBGEN2_GEN_MASK(7, 1)
/* definitions for register: Timestamping Control Register */
/* definitions for field: Transmit timestamping enable in reg: Timestamping Control Register */
#define EP_TSCR_EN_TXTS WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Receive timestamping enable in reg: Timestamping Control Register */
#define EP_TSCR_EN_RXTS WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Timestamping counter synchronization start in reg: Timestamping Control Register */
#define EP_TSCR_CS_START WBGEN2_GEN_MASK(2, 1)
/* definitions for field: Timestamping counter synchronization done in reg: Timestamping Control Register */
#define EP_TSCR_CS_DONE WBGEN2_GEN_MASK(3, 1)
/* definitions for register: RX Deframer Control Register */
/* definitions for field: RX accept runts in reg: RX Deframer Control Register */
#define EP_RFCR_A_RUNT WBGEN2_GEN_MASK(0, 1)
/* definitions for field: RX accept giants in reg: RX Deframer Control Register */
#define EP_RFCR_A_GIANT WBGEN2_GEN_MASK(1, 1)
/* definitions for field: RX accept HP in reg: RX Deframer Control Register */
#define EP_RFCR_A_HP WBGEN2_GEN_MASK(2, 1)
/* definitions for field: RX accept fragments in reg: RX Deframer Control Register */
#define EP_RFCR_A_FRAG WBGEN2_GEN_MASK(3, 1)
/* definitions for field: RX 802.1q port mode in reg: RX Deframer Control Register */
#define EP_RFCR_QMODE_MASK WBGEN2_GEN_MASK(4, 2)
#define EP_RFCR_QMODE_SHIFT 4
#define EP_RFCR_QMODE_W(value) WBGEN2_GEN_WRITE(value, 4, 2)
#define EP_RFCR_QMODE_R(reg) WBGEN2_GEN_READ(reg, 4, 2)
/* definitions for field: Force 802.1q priority in reg: RX Deframer Control Register */
#define EP_RFCR_FIX_PRIO WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Port-assigned 802.1x priority in reg: RX Deframer Control Register */
#define EP_RFCR_PRIO_VAL_MASK WBGEN2_GEN_MASK(8, 3)
#define EP_RFCR_PRIO_VAL_SHIFT 8
#define EP_RFCR_PRIO_VAL_W(value) WBGEN2_GEN_WRITE(value, 8, 3)
#define EP_RFCR_PRIO_VAL_R(reg) WBGEN2_GEN_READ(reg, 8, 3)
/* definitions for field: Port-assigned VID in reg: RX Deframer Control Register */
#define EP_RFCR_VID_VAL_MASK WBGEN2_GEN_MASK(16, 12)
#define EP_RFCR_VID_VAL_SHIFT 16
#define EP_RFCR_VID_VAL_W(value) WBGEN2_GEN_WRITE(value, 16, 12)
#define EP_RFCR_VID_VAL_R(reg) WBGEN2_GEN_READ(reg, 16, 12)
/* definitions for register: Flow Control Register */
/* definitions for field: RX Pause enable in reg: Flow Control Register */
#define EP_FCR_RXPAUSE WBGEN2_GEN_MASK(0, 1)
/* definitions for field: TX Pause enable in reg: Flow Control Register */
#define EP_FCR_TXPAUSE WBGEN2_GEN_MASK(1, 1)
/* definitions for field: TX pause threshold in reg: Flow Control Register */
#define EP_FCR_TX_THR_MASK WBGEN2_GEN_MASK(8, 8)
#define EP_FCR_TX_THR_SHIFT 8
#define EP_FCR_TX_THR_W(value) WBGEN2_GEN_WRITE(value, 8, 8)
#define EP_FCR_TX_THR_R(reg) WBGEN2_GEN_READ(reg, 8, 8)
/* definitions for field: TX pause quanta in reg: Flow Control Register */
#define EP_FCR_TX_QUANTA_MASK WBGEN2_GEN_MASK(16, 16)
#define EP_FCR_TX_QUANTA_SHIFT 16
#define EP_FCR_TX_QUANTA_W(value) WBGEN2_GEN_WRITE(value, 16, 16)
#define EP_FCR_TX_QUANTA_R(reg) WBGEN2_GEN_READ(reg, 16, 16)
/* definitions for register: Endpoint MAC address high part register */
/* definitions for register: Endpoint MAC address low part register */
/* definitions for register: DMTD Control Register */
/* definitions for field: DMTD Phase measurement enable in reg: DMTD Control Register */
#define EP_DMCR_EN WBGEN2_GEN_MASK(0, 1)
/* definitions for field: DMTD averaging samples in reg: DMTD Control Register */
#define EP_DMCR_N_AVG_MASK WBGEN2_GEN_MASK(16, 12)
#define EP_DMCR_N_AVG_SHIFT 16
#define EP_DMCR_N_AVG_W(value) WBGEN2_GEN_WRITE(value, 16, 12)
#define EP_DMCR_N_AVG_R(reg) WBGEN2_GEN_READ(reg, 16, 12)
/* definitions for register: DMTD Status register */
/* definitions for field: DMTD Phase shift value in reg: DMTD Status register */
#define EP_DMSR_PS_VAL_MASK WBGEN2_GEN_MASK(0, 24)
#define EP_DMSR_PS_VAL_SHIFT 0
#define EP_DMSR_PS_VAL_W(value) WBGEN2_GEN_WRITE(value, 0, 24)
#define EP_DMSR_PS_VAL_R(reg) WBGEN2_GEN_READ(reg, 0, 24)
/* definitions for field: DMTD Phase shift value ready in reg: DMTD Status register */
#define EP_DMSR_PS_RDY WBGEN2_GEN_MASK(24, 1)
/* definitions for register: MDIO Control Register */
/* definitions for field: MDIO Register Value in reg: MDIO Control Register */
#define EP_MDIO_CR_DATA_MASK WBGEN2_GEN_MASK(0, 16)
#define EP_MDIO_CR_DATA_SHIFT 0
#define EP_MDIO_CR_DATA_W(value) WBGEN2_GEN_WRITE(value, 0, 16)
#define EP_MDIO_CR_DATA_R(reg) WBGEN2_GEN_READ(reg, 0, 16)
/* definitions for field: MDIO Register Address in reg: MDIO Control Register */
#define EP_MDIO_CR_ADDR_MASK WBGEN2_GEN_MASK(16, 8)
#define EP_MDIO_CR_ADDR_SHIFT 16
#define EP_MDIO_CR_ADDR_W(value) WBGEN2_GEN_WRITE(value, 16, 8)
#define EP_MDIO_CR_ADDR_R(reg) WBGEN2_GEN_READ(reg, 16, 8)
/* definitions for field: MDIO Read/Write select in reg: MDIO Control Register */
#define EP_MDIO_CR_RW WBGEN2_GEN_MASK(31, 1)
/* definitions for register: MDIO Status Register */
/* definitions for field: MDIO Read Value in reg: MDIO Status Register */
#define EP_MDIO_SR_RDATA_MASK WBGEN2_GEN_MASK(0, 16)
#define EP_MDIO_SR_RDATA_SHIFT 0
#define EP_MDIO_SR_RDATA_W(value) WBGEN2_GEN_WRITE(value, 0, 16)
#define EP_MDIO_SR_RDATA_R(reg) WBGEN2_GEN_READ(reg, 0, 16)
/* definitions for field: MDIO Ready in reg: MDIO Status Register */
#define EP_MDIO_SR_READY WBGEN2_GEN_MASK(31, 1)
/* definitions for RAM: Event counters memory */
#define EP_RMON_RAM_BYTES 0x00000080 /* size in bytes */
#define EP_RMON_RAM_WORDS 0x00000020 /* size in 32-bit words, 32-bit aligned */
/* [0x0]: REG Endpoint Control Register */
#define EP_REG_ECR 0x00000000
/* [0x4]: REG Timestamping Control Register */
#define EP_REG_TSCR 0x00000004
/* [0x8]: REG RX Deframer Control Register */
#define EP_REG_RFCR 0x00000008
/* [0xc]: REG Flow Control Register */
#define EP_REG_FCR 0x0000000c
/* [0x10]: REG Endpoint MAC address high part register */
#define EP_REG_MACH 0x00000010
/* [0x14]: REG Endpoint MAC address low part register */
#define EP_REG_MACL 0x00000014
/* [0x18]: REG DMTD Control Register */
#define EP_REG_DMCR 0x00000018
/* [0x1c]: REG DMTD Status register */
#define EP_REG_DMSR 0x0000001c
/* [0x20]: REG MDIO Control Register */
#define EP_REG_MDIO_CR 0x00000020
/* [0x24]: REG MDIO Status Register */
#define EP_REG_MDIO_SR 0x00000024
#define EP_REG_IDCODE 0x00000028
/* definitions for register: WhiteRabbit-specific Configuration Register */
/* definitions for field: TX Calibration Pattern in reg: WhiteRabbit-specific Configuration Register */
#define MDIO_WR_SPEC_TX_CAL WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Calibration Pattern RX Status in reg: WhiteRabbit-specific Configuration Register */
#define MDIO_WR_SPEC_RX_CAL_STAT WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Reset calibration counter in reg: WhiteRabbit-specific Configuration Register */
#define MDIO_WR_SPEC_CAL_CRST WBGEN2_GEN_MASK(2, 1)
/* [0x10]: REG WhiteRabbit-specific Configuration Register */
#define MDIO_REG_WR_SPEC 0x00000010
#endif
/*
Register definitions for slave core: Mini NIC for WhiteRabbit
* File : ../../../software/include/hw/minic_regs.h
* Author : auto-generated by wbgen2 from mini_nic.wb
* Created : Fri Jul 30 00:33:27 2010
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE mini_nic.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_MINI_NIC_WB
#define __WBGEN2_REGDEFS_MINI_NIC_WB
//#include <inttypes.h>
#if defined( __GNUC__)
#define PACKED __attribute__ ((packed))
#else
#error "Unsupported compiler?"
#endif
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: miNIC Control Register */
/* definitions for field: TX DMA start in reg: miNIC Control Register */
#define MINIC_MCR_TX_START WBGEN2_GEN_MASK(0, 1)
/* definitions for field: TX DMA idle in reg: miNIC Control Register */
#define MINIC_MCR_TX_IDLE WBGEN2_GEN_MASK(1, 1)
/* definitions for field: TX DMA error in reg: miNIC Control Register */
#define MINIC_MCR_TX_ERROR WBGEN2_GEN_MASK(2, 1)
/* definitions for field: RX DMA ready in reg: miNIC Control Register */
#define MINIC_MCR_RX_READY WBGEN2_GEN_MASK(8, 1)
/* definitions for field: RX DMA buffer full in reg: miNIC Control Register */
#define MINIC_MCR_RX_FULL WBGEN2_GEN_MASK(9, 1)
/* definitions for field: RX DMA enable in reg: miNIC Control Register */
#define MINIC_MCR_RX_EN WBGEN2_GEN_MASK(10, 1)
/* definitions for register: TX DMA Address */
/* definitions for register: RX DMA Address */
/* definitions for register: RX buffer size register */
/* definitions for register: Interrupt disable register */
/* definitions for field: TX DMA interrupt in reg: Interrupt disable register */
#define MINIC_EIC_IDR_TX WBGEN2_GEN_MASK(0, 1)
/* definitions for field: RX DMA interrupt in reg: Interrupt disable register */
#define MINIC_EIC_IDR_RX WBGEN2_GEN_MASK(1, 1)
/* definitions for field: TX timestamp available in reg: Interrupt disable register */
#define MINIC_EIC_IDR_TXTS WBGEN2_GEN_MASK(2, 1)
/* definitions for register: Interrupt enable register */
/* definitions for field: TX DMA interrupt in reg: Interrupt enable register */
#define MINIC_EIC_IER_TX WBGEN2_GEN_MASK(0, 1)
/* definitions for field: RX DMA interrupt in reg: Interrupt enable register */
#define MINIC_EIC_IER_RX WBGEN2_GEN_MASK(1, 1)
/* definitions for field: TX timestamp available in reg: Interrupt enable register */
#define MINIC_EIC_IER_TXTS WBGEN2_GEN_MASK(2, 1)
/* definitions for register: Interrupt mask register */
/* definitions for field: TX DMA interrupt in reg: Interrupt mask register */
#define MINIC_EIC_IMR_TX WBGEN2_GEN_MASK(0, 1)
/* definitions for field: RX DMA interrupt in reg: Interrupt mask register */
#define MINIC_EIC_IMR_RX WBGEN2_GEN_MASK(1, 1)
/* definitions for field: TX timestamp available in reg: Interrupt mask register */
#define MINIC_EIC_IMR_TXTS WBGEN2_GEN_MASK(2, 1)
/* definitions for register: Interrupt status register */
/* definitions for field: TX DMA interrupt in reg: Interrupt status register */
#define MINIC_EIC_ISR_TX WBGEN2_GEN_MASK(0, 1)
/* definitions for field: RX DMA interrupt in reg: Interrupt status register */
#define MINIC_EIC_ISR_RX WBGEN2_GEN_MASK(1, 1)
/* definitions for field: TX timestamp available in reg: Interrupt status register */
#define MINIC_EIC_ISR_TXTS WBGEN2_GEN_MASK(2, 1)
/* definitions for register: FIFO 'TX timestamp FIFO' data output register 0 */
/* definitions for field: Timestamp value in reg: FIFO 'TX timestamp FIFO' data output register 0 */
#define MINIC_TSFIFO_R0_TSVAL_MASK WBGEN2_GEN_MASK(0, 32)
#define MINIC_TSFIFO_R0_TSVAL_SHIFT 0
#define MINIC_TSFIFO_R0_TSVAL_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define MINIC_TSFIFO_R0_TSVAL_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: FIFO 'TX timestamp FIFO' data output register 1 */
/* definitions for field: Port ID in reg: FIFO 'TX timestamp FIFO' data output register 1 */
#define MINIC_TSFIFO_R1_PID_MASK WBGEN2_GEN_MASK(0, 5)
#define MINIC_TSFIFO_R1_PID_SHIFT 0
#define MINIC_TSFIFO_R1_PID_W(value) WBGEN2_GEN_WRITE(value, 0, 5)
#define MINIC_TSFIFO_R1_PID_R(reg) WBGEN2_GEN_READ(reg, 0, 5)
/* definitions for field: Frame ID in reg: FIFO 'TX timestamp FIFO' data output register 1 */
#define MINIC_TSFIFO_R1_FID_MASK WBGEN2_GEN_MASK(5, 16)
#define MINIC_TSFIFO_R1_FID_SHIFT 5
#define MINIC_TSFIFO_R1_FID_W(value) WBGEN2_GEN_WRITE(value, 5, 16)
#define MINIC_TSFIFO_R1_FID_R(reg) WBGEN2_GEN_READ(reg, 5, 16)
/* definitions for register: FIFO 'TX timestamp FIFO' control/status register */
/* definitions for field: FIFO empty flag in reg: FIFO 'TX timestamp FIFO' control/status register */
#define MINIC_TSFIFO_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* [0x0]: REG miNIC Control Register */
#define MINIC_REG_MCR 0x00000000
/* [0x4]: REG TX DMA Address */
#define MINIC_REG_TX_ADDR 0x00000004
/* [0x8]: REG RX DMA Address */
#define MINIC_REG_RX_ADDR 0x00000008
/* [0xc]: REG RX buffer size register */
#define MINIC_REG_RX_AVAIL 0x0000000c
/* [0x20]: REG Interrupt disable register */
#define MINIC_REG_EIC_IDR 0x00000020
/* [0x24]: REG Interrupt enable register */
#define MINIC_REG_EIC_IER 0x00000024
/* [0x28]: REG Interrupt mask register */
#define MINIC_REG_EIC_IMR 0x00000028
/* [0x2c]: REG Interrupt status register */
#define MINIC_REG_EIC_ISR 0x0000002c
/* [0x30]: REG FIFO 'TX timestamp FIFO' data output register 0 */
#define MINIC_REG_TSFIFO_R0 0x00000030
/* [0x34]: REG FIFO 'TX timestamp FIFO' data output register 1 */
#define MINIC_REG_TSFIFO_R1 0x00000034
/* [0x38]: REG FIFO 'TX timestamp FIFO' control/status register */
#define MINIC_REG_TSFIFO_CSR 0x00000038
#define MINIC_PBUF_SIZE_LOG2 (12)
#define MINIC_PBUF_SIZE (1<<(MINIC_PBUF_SIZE_LOG2+2))
#define MINIC_BASE_IO 0x0
#define MINIC_BASE_PBUF (2<<(MINIC_PBUF_SIZE_LOG2+2))
#define MINIC_BASE_ENDPOINT (1<<(MINIC_PBUF_SIZE_LOG2+2))
#define MINIC_BASE_GIGASPY (3<<(MINIC_PBUF_SIZE_LOG2+2))
#endif
/*
Register definitions for slave core: WR Switch PPS generator and RTC
* File : ../../../software/include/hw/pps_gen_regs.h
* Author : auto-generated by wbgen2 from wrsw_pps_gen.wb
* Created : Sat Sep 11 22:22:55 2010
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wrsw_pps_gen.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_WRSW_PPS_GEN_WB
#define __WBGEN2_REGDEFS_WRSW_PPS_GEN_WB
#if defined( __GNUC__)
#define PACKED __attribute__ ((packed))
#else
#error "Unsupported compiler?"
#endif
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: Control Register */
/* definitions for field: Reset counter in reg: Control Register */
#define PPSG_CR_CNT_RST WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Enable counter in reg: Control Register */
#define PPSG_CR_CNT_EN WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Adjust offset in reg: Control Register */
#define PPSG_CR_CNT_ADJ WBGEN2_GEN_MASK(2, 1)
/* definitions for field: Set time in reg: Control Register */
#define PPSG_CR_CNT_SET WBGEN2_GEN_MASK(3, 1)
/* definitions for field: PPS Pulse width in reg: Control Register */
#define PPSG_CR_PWIDTH_MASK WBGEN2_GEN_MASK(4, 28)
#define PPSG_CR_PWIDTH_SHIFT 4
#define PPSG_CR_PWIDTH_W(value) WBGEN2_GEN_WRITE(value, 4, 28)
#define PPSG_CR_PWIDTH_R(reg) WBGEN2_GEN_READ(reg, 4, 28)
/* definitions for register: Nanosecond counter register */
/* definitions for register: UTC Counter register (least-significant part) */
/* definitions for register: UTC Counter register (most-significant part) */
/* definitions for register: Nanosecond adjustment register */
/* definitions for register: UTC Adjustment register (least-significant part) */
/* definitions for register: UTC Adjustment register (most-significant part) */
/* [0x0]: REG Control Register */
#define PPSG_REG_CR 0x00000000
/* [0x4]: REG Nanosecond counter register */
#define PPSG_REG_CNTR_NSEC 0x00000004
/* [0x8]: REG UTC Counter register (least-significant part) */
#define PPSG_REG_CNTR_UTCLO 0x00000008
/* [0xc]: REG UTC Counter register (most-significant part) */
#define PPSG_REG_CNTR_UTCHI 0x0000000c
/* [0x10]: REG Nanosecond adjustment register */
#define PPSG_REG_ADJ_NSEC 0x00000010
/* [0x14]: REG UTC Adjustment register (least-significant part) */
#define PPSG_REG_ADJ_UTCLO 0x00000014
/* [0x18]: REG UTC Adjustment register (most-significant part) */
#define PPSG_REG_ADJ_UTCHI 0x00000018
#endif
/*
* Copyright (c) 2010 Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Copyright (c) 2009 Emilio G. Cota <cota@braap.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/platform_device.h>
#include <linux/etherdevice.h>
#include <linux/net_tstamp.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/swab.h>
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/if.h>
#include <asm/atomic.h>
#include "minic_regs.h"
#include "endpoint_regs.h"
#include "pps_gen_regs.h"
#include "wr_vic.h"
#define DMTD_AVG_SAMPLES 256
#define DMTD_MAX_PHASE 16384
#define F_COUNTER_BITS 4
#define F_COUNTER_MASK ((1<<F_COUNTER_BITS)-1)
#define LINK_POLL_INTERVAL (HZ/5)
#define DRV_NAME "wr_minic"
#define DRV_VERSION "0.5.1"
#define MINIC_NAPI_WEIGHT 10
#define MINIC_MTU 1540
#define MINIC_TX_MAX_TS 64
#define RX_DESC_VALID(d) ((d) & (1<<31) ? 1 : 0)
#define RX_DESC_ERROR(d) ((d) & (1<<30) ? 1 : 0)
#define RX_DESC_HAS_OOB(d) ((d) & (1<<29) ? 1 : 0)
#define RX_DESC_SIZE(d) (((d) & (1<<0) ? -1 : 0) + (d & 0xfffe))
#define TX_DESC_VALID (1<<31)
#define TX_DESC_WITH_OOB (1<<30)
#define TX_DESC_HAS_OWN_MAC (1<<28)
#define RX_OOB_SIZE 6
#define REFCLK_FREQ 125000000
// extracts the values of TS rising and falling edge counters from the descriptor header
#define EXPLODE_WR_TIMESTAMP(raw, rc, fc) \
rc = (raw) & 0xfffffff; \
fc = (raw >> 28) & 0xf;
/* UGLY HACK WARNING:
remove the PPS subsystem and put it in a separate driver */
struct tx_timestamp {
u16 fid;
u16 port;
struct skb_shared_hwtstamps ts_val;
int valid;
};
struct wr_minic {
void __iomem *base; // base address of the Minic+Packet RAM+Endpoint combo
void __iomem *minic_regs; // base address of the miNIC registers
void __iomem *ep_regs; // base address of the Endpoint registers
void __iomem *pbuf; // base address of the Packet RAM
void __iomem *ppsg; // base address of the PPS generator
spinlock_t lock;
int tx_hwtstamp_enable;
int rx_hwtstamp_enable;
u16 tx_hwtstamp_oob;
struct tx_timestamp tx_tstable[MINIC_TX_MAX_TS];
struct platform_device *pdev;
struct device *dev;
struct net_device *netdev;
struct net_device_stats stats;
struct napi_struct napi;
struct sk_buff *current_skb;
struct timer_list link_timer;
unsigned int rx_head, rx_avail, rx_base, rx_size;
unsigned int tx_head, tx_avail, tx_base, tx_size;
bool synced;
bool syncing_counters;
int iface_up;
u32 cur_rx_desc;
struct mii_if_info mii;
};
MODULE_DESCRIPTION("White Rabbit miNIC driver");
MODULE_AUTHOR("Tomasz Wlostowski <tomasz.wlostowsk@cern.ch>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:wr-minic");
#define minic_readl(m, offs) \
__raw_readl((m)->minic_regs + (offs))
#define minic_writel(m, offs, value) \
__raw_writel((value), (m)->minic_regs + (offs))
#define endpoint_readl(m, offs) \
__raw_readl((m)->ep_regs + (offs))
#define endpoint_writel(m, offs, value) \
__raw_writel((value), (m)->ep_regs + (offs))
#define ppsg_readl(m, offs) \
__raw_readl((m)->ppsg + (offs))
#define ppsg_writel(m, offs, value) \
__raw_writel((value), (m)->ppsg + (offs))
// reads an MDIO register
static int phy_read(struct net_device *dev, int phy_id, int location)
{
struct wr_minic *nic = netdev_priv(dev);
endpoint_writel(nic, EP_REG_MDIO_CR, EP_MDIO_CR_ADDR_W(location));
while( (endpoint_readl(nic, EP_REG_MDIO_SR) & EP_MDIO_SR_READY) == 0);
return EP_MDIO_SR_RDATA_R(endpoint_readl(nic, EP_REG_MDIO_SR));
}
static void phy_write(struct net_device *dev, int phy_id, int location, int value)
{
struct wr_minic *nic = netdev_priv(dev);
endpoint_writel(nic, EP_REG_MDIO_CR, EP_MDIO_CR_ADDR_W(location) | EP_MDIO_CR_DATA_W(value)| EP_MDIO_CR_RW);
while( (endpoint_readl(nic, EP_REG_MDIO_SR) & EP_MDIO_SR_READY) == 0);
}
static int minic_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct wr_minic *lp = netdev_priv(dev);
int ret;
spin_lock_irq(&lp->lock);
ret = mii_ethtool_gset(&lp->mii, cmd);
spin_unlock_irq(&lp->lock);
cmd->supported= SUPPORTED_FIBRE | SUPPORTED_Autoneg| SUPPORTED_1000baseKX_Full;
cmd->advertising = ADVERTISED_1000baseKX_Full | ADVERTISED_Autoneg;
cmd->port = PORT_FIBRE;
cmd->speed = SPEED_1000;
cmd->duplex = DUPLEX_FULL;
cmd->autoneg = AUTONEG_ENABLE;
return ret;
}
static int minic_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct wr_minic *lp = netdev_priv(dev);
int ret;
spin_lock_irq(&lp->lock);
ret = mii_ethtool_sset(&lp->mii, cmd);
spin_unlock_irq(&lp->lock);
return ret;
}
static int minic_nwayreset(struct net_device *dev)
{
struct wr_minic *lp = netdev_priv(dev);
int ret;
spin_lock_irq(&lp->lock);
ret = mii_nway_restart(&lp->mii);
spin_unlock_irq(&lp->lock);
return ret;
}
static void minic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
strlcpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info));
}
static const struct ethtool_ops minic_ethtool_ops = {
.get_settings = minic_get_settings,
.set_settings = minic_set_settings,
.get_drvinfo = minic_get_drvinfo,
.nway_reset = minic_nwayreset,
.get_link = ethtool_op_get_link,
};
// use in locked context, please
static void minic_ppsg_read_time(struct wr_minic *nic, u32 *cntr, u64 *utc)
{
uint32_t cyc_before, cyc_after;
uint32_t utc_lo, utc_hi;
for(;;)
{
cyc_before =ppsg_readl(nic, PPSG_REG_CNTR_NSEC) & 0xfffffff;
utc_lo = ppsg_readl(nic, PPSG_REG_CNTR_UTCLO) ;
utc_hi = ppsg_readl(nic, PPSG_REG_CNTR_UTCHI) & 0xff;
cyc_after = ppsg_readl(nic, PPSG_REG_CNTR_NSEC) & 0xfffffff;
// there was an UTC transition. (nanosecond counter overflow). read the value again.
if(cyc_after < REFCLK_FREQ/4 && cyc_before > (REFCLK_FREQ - REFCLK_FREQ/4))
continue;
else {
if(utc) *utc = (u64)utc_lo | (u64)utc_hi << 32;
if(cntr) *cntr = cyc_after;
return;
}
}
}
static inline u32 minic_ppsg_get_nsecs(struct wr_minic *nic)
{
return ppsg_readl(nic, PPSG_REG_CNTR_NSEC) & 0xfffffff;
}
static void minic_disable_irq(struct wr_minic *nic, u32 mask)
{
// dev_dbg(nic->dev, "wr_disable_irq() - mask %x\n", mask);
minic_writel(nic, MINIC_REG_EIC_IDR, mask);
}
static void minic_enable_irq(struct wr_minic *nic, u32 mask)
{
// dev_dbg(nic->dev, "wr_enable_irq() - mask %x\n", mask);
minic_writel(nic, MINIC_REG_EIC_IER, mask);
}
static void minic_clear_irq(struct wr_minic *nic, u32 mask)
{
minic_writel(nic, MINIC_REG_EIC_ISR, mask);
}
static struct net_device_stats *minic_get_stats(struct net_device *netdev)
{
struct wr_minic *nic = netdev_priv(netdev);
// wr_update_tx_stats(nic);
// wr_update_rx_stats(nic);
return &nic->stats;
}
static void minic_new_rx_buffer(struct wr_minic *nic)
{
nic->rx_head = nic->rx_base;
minic_writel(nic, MINIC_REG_MCR, 0);
minic_writel(nic, MINIC_REG_RX_ADDR, nic->rx_base);
minic_writel(nic, MINIC_REG_RX_AVAIL, (nic->rx_size - MINIC_MTU) >> 2);
minic_writel(nic, MINIC_REG_MCR, MINIC_MCR_RX_EN);
}
static void minic_new_tx_buffer(struct wr_minic *nic)
{
nic->tx_head = nic->tx_base;
nic->tx_avail = (nic->tx_size - MINIC_MTU) >> 2;
minic_writel(nic, MINIC_REG_TX_ADDR, nic->tx_base);
}
static int minic_rx_frame(struct wr_minic *nic)
{
struct net_device *netdev = nic->netdev;
struct sk_buff *skb;
u32 __iomem *rx_head;
u32 *tmp_ptr;
u32 payload_size, num_words;
u32 desc_hdr;
u32 rx_addr_cur;
u32 rx_oob;
u32 tmp_buf[(MINIC_MTU >> 2) + 8];
int i;
/* get the address of the latest RX descriptor */
rx_addr_cur = minic_readl(nic, MINIC_REG_RX_ADDR) & 0xffffff;
if(rx_addr_cur < nic->rx_head) /* nothing new in the buffer? */
return 1;
rx_head = nic->pbuf + nic->rx_head;
desc_hdr = __raw_readl(rx_head++); /* read the 32-bit descriptor header */
if(!RX_DESC_VALID(desc_hdr)) /* invalid descriptor? Weird, the RX_ADDR seems to be saying something different. Ignore the packet and purge the RX buffer. */
{
dev_info(nic->dev, "%s: weird, invalid RX descriptor (%x, head %x)", __func__, desc_hdr, (unsigned int) rx_head-1);
minic_new_rx_buffer(nic);
return 0;
}
// if(RX_DESC_HAS_OOB(desc_hdr))
payload_size = RX_DESC_SIZE(desc_hdr);
num_words = (payload_size + 3) >> 2;
/* valid packet */
if(!RX_DESC_ERROR(desc_hdr))
{
skb = netdev_alloc_skb(netdev, payload_size + 9);
if (unlikely(skb == NULL)) {
if (net_ratelimit())
dev_warn(nic->dev, "-ENOMEM - packet dropped\n");
return 0;
}
/* Make the IP header word-aligned (the ethernet header is 14 bytes) */
skb_reserve(skb, 2);
for(i=num_words, tmp_ptr = tmp_buf;i >=0 ; i--)
*tmp_ptr ++ = __raw_readl(rx_head++);
if(RX_DESC_HAS_OOB(desc_hdr)) // RX timestamping
{
struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb);
u32 counter_r, counter_f; // timestamp counter values
u32 counter_ppsg; // PPS generator nanosecond counter
u64 utc;
s32 cntr_diff;
payload_size -= RX_OOB_SIZE;
memcpy(&rx_oob, ((void *)tmp_buf) + payload_size+2, 4);
rx_oob = swab32(rx_oob);
EXPLODE_WR_TIMESTAMP(rx_oob, counter_r, counter_f);
minic_ppsg_read_time(nic, &counter_ppsg, &utc);
if(counter_r > (3*REFCLK_FREQ/4) && counter_ppsg < REFCLK_FREQ/4)
utc--;
// fixme: we need to pass the phase value somehow for RX timestamps. For the time being, we pass the R-F counter difference on the MSB of UTC (instead of sign value), so the PTP can detect the valid counter
hwts->hwtstamp.tv.sec = (s32)utc & 0x7fffffff ;
cntr_diff = (counter_r & F_COUNTER_MASK) - counter_f;
if(cntr_diff == 1 || cntr_diff == (-F_COUNTER_MASK))
hwts->hwtstamp.tv.sec |= 0x80000000; // indicated that the rising edge counter is one tick ahead
hwts->hwtstamp.tv.nsec = counter_r * 8;
}
memcpy(skb_put(skb, payload_size), tmp_buf, payload_size);
/* determine protocol id */
skb->protocol = eth_type_trans(skb, netdev);
/* @fixme ignore the checksum for the time being */
skb->ip_summed = CHECKSUM_UNNECESSARY;
/* update the rx buffer head to point to the next descriptor */
nic->rx_head += ( num_words + 1 ) << 2;
netdev->last_rx = jiffies;
nic->stats.rx_packets++;
nic->stats.rx_bytes += payload_size;
netif_receive_skb(skb);
} else { // RX_DESC_ERROR
nic->stats.rx_errors ++;
nic->rx_head += ( num_words + 1 ) << 2;
}
wmb();
return 0;
}
static int minic_poll_txts_fifo(struct wr_minic *nic, u16 oob_fid, struct skb_shared_hwtstamps *hwts)
{
int i;
u32 dmsr;
int dmtd_phase;
dmsr = endpoint_readl(nic, EP_REG_DMSR);
if(dmsr & EP_DMSR_PS_RDY)
dmtd_phase = EP_DMSR_PS_VAL_R(dmsr);
else
dmtd_phase = 0;
// sign-extend, fix the average if its out of range due to jitter
if(dmtd_phase & 0x800000) dmtd_phase |= 0xff000000;
// calculate the average
dmtd_phase /= DMTD_AVG_SAMPLES;
if(dmtd_phase > DMTD_MAX_PHASE) dmtd_phase -= DMTD_MAX_PHASE;
if(dmtd_phase < 0) dmtd_phase += DMTD_MAX_PHASE;
while(!(minic_readl(nic, MINIC_REG_TSFIFO_CSR) & MINIC_TSFIFO_CSR_EMPTY))
{
u32 tsval_raw = minic_readl(nic, MINIC_REG_TSFIFO_R0);
u32 fid = (minic_readl(nic, MINIC_REG_TSFIFO_R1) >> 5) & 0xffff;
u32 counter_r, counter_f; // timestamp counter values
u32 counter_ppsg; // PPS generator nanosecond counter
u64 utc;
struct skb_shared_hwtstamps tsval;
EXPLODE_WR_TIMESTAMP(tsval_raw, counter_r, counter_f);
// printk("About to read time\n");
minic_ppsg_read_time(nic, &counter_ppsg, &utc);
// printk("After read time\n");
// the timestamp was taken at the end of previous second
// of UTC time, and now we are at the beginning of the next second
if(counter_r > (3*REFCLK_FREQ/4) && counter_ppsg < REFCLK_FREQ/4)
utc--;
// fixme
tsval.hwtstamp.tv.sec = ((s32)utc & 0x7fffffff);
tsval.hwtstamp.tv.nsec = counter_r * 8;
for(i = 0; i<MINIC_TX_MAX_TS;i++)
if(!nic->tx_tstable[i].valid)
{
// printk("Addts: fid %d tsval %x\n", fid, tsval);
nic->tx_tstable[i].valid = 1;
nic->tx_tstable[i].ts_val = tsval;
nic->tx_tstable[i].fid = fid;
break;
};
}
// printk("queryts: fid %d\n", oob_fid);
for(i = 0; i<MINIC_TX_MAX_TS;i++)
if(nic->tx_tstable[i].valid && oob_fid == nic->tx_tstable[i].fid)
{
// printk("GotTS: fid %d\n", oob_fid);
if(hwts)
memcpy(hwts, &nic->tx_tstable[i].ts_val, sizeof(struct skb_shared_hwtstamps));
nic->tx_tstable[i].valid = 0;
return 0;
};
// printk("Missed timestamp...");
return -1;
}
static inline void minic_tx_handle_irq(struct wr_minic *nic)
{
struct net_device *netdev = nic->netdev;
struct skb_shared_hwtstamps hwts;
struct skb_shared_hwtstamps *hwoob = skb_hwtstamps(nic->current_skb);
union skb_shared_tx *shtx = skb_tx(nic->current_skb);
unsigned long flags;
u16 oob_tag;
spin_lock_irqsave(&nic->lock, flags);
// this will only work for the NIC directly connected to the endpoint. In case of a switch,
// the packet will reach the output port after being completely transmitted by the NIC (i.e. after the TX interrupt)
if(shtx->in_progress)
{
oob_tag = *(u16 *) hwoob;
if(!minic_poll_txts_fifo(nic, oob_tag, &hwts))
skb_tstamp_tx(nic->current_skb, &hwts);
}
dev_kfree_skb_irq(nic->current_skb);
if (netif_queue_stopped(nic->netdev))
netif_wake_queue(netdev);
spin_unlock_irqrestore(&nic->lock, flags);
minic_clear_irq(nic, MINIC_EIC_ISR_TX); // clear the TX interrupt
}
static inline void minic_rx_handle_irq(struct wr_minic *nic)
{
int buf_full;
buf_full = minic_readl(nic, MINIC_REG_MCR) & MINIC_MCR_RX_FULL ? 1 : 0;
while(!minic_rx_frame(nic));
if(buf_full)
minic_new_rx_buffer(nic);
minic_clear_irq(nic, MINIC_EIC_ISR_RX);
}
static void minic_interrupt(void *dev_id) // called by MCH VIC driver
{
struct net_device *netdev = dev_id;
struct wr_minic *nic = netdev_priv(netdev);
u32 isr;
isr = minic_readl(nic, MINIC_REG_EIC_ISR);
if (isr & MINIC_EIC_ISR_TX)
minic_tx_handle_irq(nic);
if (isr & MINIC_EIC_ISR_RX)
minic_rx_handle_irq(nic);
}
static int minic_hw_tx(struct wr_minic *nic, char *data, unsigned size, u16 tx_oob_val)
{
u32 __iomem *dst, *dptr;
u32 nwords;
u32 mcr;
int i;
u32 pkt_buf[(MINIC_MTU >> 2) + 4];
nwords = ((size + 1) >> 1) - 1;
memset(pkt_buf, 0x0, size + 16);
memcpy(pkt_buf + 1, data, size);
if(nwords < 30) nwords = 30; // min packet length = 60 bytes (CRC excluded)
if(tx_oob_val) // do the TX timestamping?
{
tx_oob_val = swab16(tx_oob_val);
memcpy((void*)pkt_buf + 4 + size, &tx_oob_val, sizeof(u16));
nwords++;
pkt_buf[0] = TX_DESC_WITH_OOB;
// printk("add oob\n");
} else
pkt_buf[0] = 0;
pkt_buf[0] |= TX_DESC_VALID | TX_DESC_HAS_OWN_MAC | nwords;
for(i=((nwords+1)>>1)+3, dptr = (u32*) pkt_buf, dst = nic->pbuf + nic->tx_head; i ; i--)
*dst ++ = *dptr++;
minic_enable_irq(nic, MINIC_EIC_IER_TX);
mcr = minic_readl(nic, MINIC_REG_MCR);
minic_writel(nic, MINIC_REG_MCR, mcr | MINIC_MCR_TX_START);
return 0;
}
static int minic_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct wr_minic *nic = netdev_priv(netdev);
union skb_shared_tx *shtx = skb_tx(skb);
u16 tx_oob = 0;
char *data;
unsigned len;
if (unlikely(skb->len > MINIC_MTU)) {
nic->stats.tx_errors++;
return -EMSGSIZE;
}
data = skb->data;
len = skb->len;
spin_lock_irq(&nic->lock);
nic->current_skb = skb;
netif_stop_queue(netdev); // queue stays stopped until the packet is transmitted.
if(nic -> tx_hwtstamp_enable && shtx->hardware)
{
struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb);
shtx->in_progress = 1;
// printk("DoHWTX\n");
*(u16 *) hwts = tx_oob = nic->tx_hwtstamp_oob;
nic->tx_hwtstamp_oob ++;
if(nic->tx_hwtstamp_oob == 60000)
nic->tx_hwtstamp_oob = 1;
} else
tx_oob = 0;
minic_new_tx_buffer(nic);
minic_hw_tx(nic, data, len, tx_oob);
nic->stats.tx_packets++;
nic->stats.tx_bytes += len;
netdev->trans_start = jiffies;
spin_unlock_irq(&nic->lock);
return 0;
}
static void minic_update_ts_config(struct wr_minic *nic)
{
endpoint_writel(nic, EP_REG_TSCR, (nic->tx_hwtstamp_enable ? EP_TSCR_EN_TXTS : 0)
| (nic->rx_hwtstamp_enable ? EP_TSCR_EN_RXTS : 0)
);
// printk("update_ts_config: TSCR %x\n", endpoint_readl(nic, EP_REG_TSCR));
}
static int minic_tstamp_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{
struct wr_minic *nic = netdev_priv(netdev);
struct hwtstamp_config config;
if (copy_from_user(&config, rq->ifr_data, sizeof(config)))
return -EFAULT;
// printk("hwtstamp_ioctl()\n" );
switch (config.tx_type) {
case HWTSTAMP_TX_ON:
// printk("%s: hw tx timestamping ON\n", __func__);
nic->tx_hwtstamp_enable = 1;
memset(nic->tx_tstable, 0, sizeof(nic->tx_tstable));
break;
case HWTSTAMP_TX_OFF:
// printk("%s: hw tx timestamping OFF\n", __func__);
nic->tx_hwtstamp_enable = 0;
break;
default:
return -ERANGE;
}
/*
* For the time being, make this really simple and stupid: either
* time-tag _all_ the incoming packets or none of them.
*/
switch (config.rx_filter) {
case HWTSTAMP_FILTER_NONE:
//dev_dbg(nic->dev, "%s - hw rx timestamping OFF\n", __func__);
nic->rx_hwtstamp_enable = 0;
break;
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
// printk( "%s - hw rx timestamping ON for PTP L2 events\n", __func__);
nic->rx_hwtstamp_enable = 1; // Only PTPv2 is supported for the time being...
config.rx_filter = HWTSTAMP_FILTER_ALL;
break;
default:
return -ERANGE;
}
minic_update_ts_config(nic);
return copy_to_user(rq->ifr_data, &config, sizeof(config)) ?
-EFAULT : 0;
}
#define PRIV_IOCGCALIBRATE (SIOCDEVPRIVATE+1)
#define PRIV_IOCGGETPHASE (SIOCDEVPRIVATE+2)
#define CAL_CMD_TX_ON 1
#define CAL_CMD_TX_OFF 2
#define CAL_CMD_RX_ON 3
#define CAL_CMD_RX_OFF 4
#define CAL_CMD_RX_CHECK 5
struct wrmch_calibration_req {
int cmd;
// int tx_rx;
int cal_present;
};
struct wrmch_phase_req {
int ready;
u32 phase;
};
static int phase_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{
struct wrmch_phase_req phase_req;
struct wr_minic *nic = netdev_priv(netdev);
u32 dmsr = endpoint_readl(nic, EP_REG_DMSR);
if(dmsr & EP_DMSR_PS_RDY)
{
s32 dmtd_phase = EP_DMSR_PS_VAL_R(dmsr);
// sign-extend, fix the average if its out of range due to jitter
if(dmtd_phase & 0x800000) dmtd_phase |= 0xff000000;
// calculate the average
dmtd_phase /= DMTD_AVG_SAMPLES;
if(dmtd_phase > DMTD_MAX_PHASE) dmtd_phase -= DMTD_MAX_PHASE;
if(dmtd_phase < 0) dmtd_phase += DMTD_MAX_PHASE;
phase_req.phase = dmtd_phase;
phase_req.ready = 1;
} else {
phase_req.phase = 0;
phase_req.ready = 0;
}
return copy_to_user(rq->ifr_data, &phase_req, sizeof(phase_req)) ?
-EFAULT : 0;
};
static int calibration_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{
struct wrmch_calibration_req cal_req;
struct wr_minic *nic = netdev_priv(netdev);
u32 tmp;
if (copy_from_user(&cal_req, rq->ifr_data, sizeof(cal_req)))
return -EFAULT;
switch(cal_req.cmd)
{
case CAL_CMD_TX_ON:
if(nic->iface_up)
{
tmp = phy_read(netdev, 0, MDIO_REG_WR_SPEC);
phy_write(netdev, 0, MDIO_REG_WR_SPEC, tmp | MDIO_WR_SPEC_TX_CAL);
} else return -EFAULT;
break;
case CAL_CMD_TX_OFF:
if(nic->iface_up)
{
tmp = phy_read(netdev, 0, MDIO_REG_WR_SPEC);
phy_write(netdev, 0, MDIO_REG_WR_SPEC, tmp & (~MDIO_WR_SPEC_TX_CAL));
} else return -EFAULT;
break;
case CAL_CMD_RX_ON:
if(nic->iface_up)
{
tmp = phy_read(netdev, 0, MDIO_REG_WR_SPEC);
phy_write(netdev, 0, MDIO_REG_WR_SPEC, tmp | MDIO_WR_SPEC_CAL_CRST);
} else return -EFAULT;
break;
case CAL_CMD_RX_OFF:
if(nic->iface_up)
{
// do nothing.....
} else return -EFAULT;
break;
case CAL_CMD_RX_CHECK:
if(nic->iface_up)
{
tmp = phy_read(netdev, 0, MDIO_REG_WR_SPEC);
cal_req.cal_present = tmp & MDIO_WR_SPEC_RX_CAL_STAT ? 1 : 0;
return copy_to_user(rq->ifr_data, &cal_req, sizeof(cal_req)) ?
-EFAULT : 0;
} else return -EFAULT;
break;
}
return 0;
}
static int minic_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{
struct wr_minic *nic = netdev_priv(netdev);
int res;
switch (cmd) {
case SIOCSHWTSTAMP:
return minic_tstamp_ioctl(netdev, rq, cmd);
case PRIV_IOCGCALIBRATE:
return calibration_ioctl(netdev, rq, cmd);
case PRIV_IOCGGETPHASE:
return phase_ioctl(netdev, rq, cmd);
default:
spin_lock_irq(&nic->lock);
res = generic_mii_ioctl(&nic->mii, if_mii(rq), cmd, NULL);
spin_unlock_irq(&nic->lock);
return res;
}
}
static void ep_enable(struct net_device *netdev)
{
struct wr_minic *nic = netdev_priv(netdev);
endpoint_writel(nic, EP_REG_DMCR, EP_DMCR_EN | EP_DMCR_N_AVG_W(DMTD_AVG_SAMPLES));
endpoint_writel(nic, EP_REG_ECR, EP_ECR_TX_EN_FRA | EP_ECR_RX_EN_FRA | EP_ECR_RST_CNT);
endpoint_writel(nic, EP_REG_RFCR, 3 << EP_RFCR_QMODE_SHIFT); // QMODE = UNQUALIFIED
endpoint_writel(nic, EP_REG_TSCR, 0); // disable the timestamping
endpoint_writel(nic, EP_REG_FCR, 0); // no flow control for the time being
phy_write(netdev, 0, MII_ADVERTISE, 0x01a0); // advertise TX+RX flow control, full duplex
phy_write(netdev, 0, MII_BMCR, 0); //phy_read(netdev, 0, MII_BMCR) | BMCR_ANENABLE | BMCR_ANRESTART);
}
static void ep_disable(struct net_device *netdev)
{
struct wr_minic *nic = netdev_priv(netdev);
endpoint_writel(nic, EP_REG_ECR, 0);
endpoint_writel(nic, EP_REG_TSCR, 0);
}
static void update_link_status(unsigned long dev_id)
{
struct net_device *netdev = (struct net_device *) dev_id;
struct wr_minic *nic = netdev_priv(netdev);
u32 ecr, bmsr, bmsr2, bmsr3, bmcr, lpa;
bmsr = phy_read(netdev, 0, MII_BMSR);
bmcr = phy_read(netdev, 0, MII_BMCR);
// printk(KERN_INFO "iface %s naddr %x bmsr %x\n", netdev->name, nic->mii.dev, bmsr);
if (!mii_link_ok(&nic->mii)) { /* no link */
if(netif_carrier_ok(netdev))
{
netif_carrier_off(netdev);
nic->iface_up = 0;
printk(KERN_INFO "%s: Link down.\n", netdev->name);
}
return;
}
if(netif_carrier_ok(netdev))
return;
if (bmcr & BMCR_ANENABLE) { /* AutoNegotiation is enabled */
if (!(bmsr & BMSR_ANEGCOMPLETE))
return; /* Do nothing - another interrupt generated when negotiation complete */
lpa = phy_read(netdev,0, MII_LPA);
netif_carrier_on(netdev);
nic->iface_up = 1;
// endpoint_writel(nic, EP_REG_FCR, EP_FCR_TXPAUSE |EP_FCR_RXPAUSE | EP_FCR_TX_THR_W(128) | EP_FCR_TX_QUANTA_W(200));
printk(KERN_INFO "%s: Link up, lpa 0x%04x.\n", netdev->name, lpa);
} else {
netif_carrier_on(netdev);
printk(KERN_INFO "%s: Link up.\n", netdev->name);
nic->iface_up = 1;
}
ecr = endpoint_readl(nic, EP_REG_ECR);
endpoint_writel(nic, EP_REG_ECR, ecr | EP_ECR_RST_CNT); // reset RMON counters
endpoint_writel(nic, EP_REG_ECR, ecr );
}
static void minic_check_link(unsigned long dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct wr_minic *lp = netdev_priv(dev);
update_link_status(dev_id);
mod_timer(&lp->link_timer, jiffies + LINK_POLL_INTERVAL);
}
static int minic_open(struct net_device *netdev)
{
struct wr_minic *nic = netdev_priv(netdev);
// printk("Bringing up: %s\n", netdev->name);
if (!is_valid_ether_addr(netdev->dev_addr))
return -EADDRNOTAVAIL;
minic_writel(nic, MINIC_REG_MCR, 0);
minic_disable_irq(nic, 0xffffffff);
ep_enable(netdev);
netif_carrier_off(netdev);
init_timer(&nic->link_timer);
nic->link_timer.data = (unsigned long)netdev;
nic->link_timer.function = minic_check_link;
mod_timer(&nic->link_timer, jiffies + LINK_POLL_INTERVAL);
nic->synced = false;
nic->syncing_counters = false;
nic->rx_base = MINIC_PBUF_SIZE >> 1;
nic->rx_size = MINIC_PBUF_SIZE >> 1;
nic->tx_base = 0;
nic->tx_size = MINIC_PBUF_SIZE >> 1;
nic->tx_hwtstamp_enable = 0;
nic->rx_hwtstamp_enable = 0;
nic->tx_hwtstamp_oob = 1;
minic_new_rx_buffer(nic);
minic_enable_irq(nic, MINIC_EIC_IER_RX); // enable RX irq
minic_writel(nic, MINIC_REG_MCR, MINIC_MCR_RX_EN); // enable RX
if (netif_queue_stopped(nic->netdev)) {
netif_wake_queue(netdev);
} else {
netif_start_queue(netdev);
}
nic->iface_up = 0;
return 0;
}
static int minic_close(struct net_device *netdev)
{
struct wr_minic *nic = netdev_priv(netdev);
// napi_disable(&nic->napi);
del_timer_sync(&nic->link_timer);
nic->iface_up = 0;
ep_disable(netdev);
if (!netif_queue_stopped(netdev))
netif_stop_queue(netdev);
minic_writel(nic, MINIC_REG_MCR, 0);
minic_writel(nic, MINIC_REG_EIC_IDR, 0xffffffff);
// dev_info(nic->dev, "wr_close() done\n");
return 0;
}
static void minic_update_mac(struct net_device *netdev)
{
struct wr_minic *nic = netdev_priv(netdev);
endpoint_writel(nic, EP_REG_MACL, (netdev->dev_addr[3] << 24) | (netdev->dev_addr[2] << 16) | (netdev->dev_addr[1] << 8) | (netdev->dev_addr[0]));
endpoint_writel(nic, EP_REG_MACH, (netdev->dev_addr[5] << 8) | (netdev->dev_addr[4]));
}
static int minic_set_mac_address(struct net_device *netdev, void* addr)
{
struct sockaddr *address = addr;
if (!is_valid_ether_addr(address->sa_data))
return -EADDRNOTAVAIL;
memcpy(netdev->dev_addr, address->sa_data, netdev->addr_len);
minic_update_mac(netdev);
// printk("%s: Setting MAC address to %pM\n", netdev->name, netdev->dev_addr);
return 0;
}
static const struct net_device_ops minic_netdev_ops = {
.ndo_open = minic_open,
.ndo_stop = minic_close,
.ndo_start_xmit = minic_start_xmit,
.ndo_validate_addr = eth_validate_addr,
.ndo_get_stats = minic_get_stats,
// .ndo_set_multicast_list = wr_set_multicast_list,
.ndo_set_mac_address = minic_set_mac_address,
// .ndo_change_mtu = wr_change_mtu,
.ndo_do_ioctl = minic_ioctl,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = NULL;//wr_netpoll;
#endif
};
static int __devinit minic_probe(struct platform_device *pdev)
{
struct net_device *netdev;
struct resource *base_minic, *base_ppsg;
struct wr_minic *nic;
int err;
base_minic = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!base_minic) {
dev_err(&pdev->dev, "no mmio resource defined\n");
err = -ENXIO;
goto err_out;
}
base_ppsg = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!base_ppsg) {
dev_err(&pdev->dev, "no mmio resource defined\n");
err = -ENXIO;
goto err_out;
}
netdev = alloc_etherdev(sizeof(struct wr_minic));
if (!netdev) {
dev_err(&pdev->dev, "etherdev alloc failed, aborting.\n");
err = -ENOMEM;
goto err_out;
}
// printk("base-addr 0x%x-0x%x\n", base->start, base->end);
SET_NETDEV_DEV(netdev, &pdev->dev);
/* initialise the nic structure */
nic = netdev_priv(netdev);
nic->pdev = pdev;
nic->netdev = netdev;
nic->dev = &pdev->dev;
nic->iface_up = 0;
spin_lock_init(&nic->lock);
nic->base = ioremap(base_minic->start, base_minic->end - base_minic->start + 1);
nic->ppsg = ioremap(base_ppsg->start, base_ppsg->end - base_ppsg->start + 1);
// dev_info(&pdev->dev, "io at 0x%x, pbuf at 0x%x\n", nic->minic_regs, nic->pbuf);
if (!nic->base || !nic->ppsg) {
// if (netif_msg_probe(nic))
dev_err(&pdev->dev, "failed to map minic address space\n");
err = -ENOMEM;
goto err_out_free_netdev;
}
nic->minic_regs = nic->base + MINIC_BASE_IO;
nic->ep_regs = nic->base + MINIC_BASE_ENDPOINT;
nic->pbuf = nic->base + MINIC_BASE_PBUF;
netdev->base_addr = (u32) nic->base;
strcpy(netdev->name, (char *)pdev->dev.platform_data);
if(endpoint_readl(nic, EP_REG_IDCODE) != 0xcafebabe)
{
printk(KERN_INFO "Looks like the port %s hasn't been synthesized...\n", netdev->name);
free_netdev(netdev);
iounmap(nic->base);
iounmap(nic->ppsg);
return 0 ;
}
memset(netdev->dev_addr, 0, 6);
// minic_get_mac_addr(nic);
netdev->irq = platform_get_irq(pdev, 0);
if (netdev->irq < 0) {
err = -ENXIO;
goto err_out_iounmap;
}
err = wrmch_vic_request_irq(netdev->irq, minic_interrupt, netdev);
if (err) {
// if (netif_msg_probe(nic)) {
dev_err(&netdev->dev, "request IRQ %d failed, err=%d\n",
netdev->irq, err);
// }
goto err_out_iounmap;
}
netdev->netdev_ops = &minic_netdev_ops;
netdev->ethtool_ops = &minic_ethtool_ops;
netdev->features |= 0;
/* setup NAPI */
memset(&nic->napi, 0, sizeof(nic->napi));
// netif_napi_add(netdev, &nic->napi, minic_poll, MINIC_NAPI_WEIGHT);
nic->mii.dev = netdev; /* Support for ethtool */
nic->mii.mdio_read = phy_read;
nic->mii.mdio_write = phy_write;
nic->mii.phy_id = 0;
nic->mii.phy_id_mask = 0x1f;
nic->mii.reg_num_mask = 0x1f;
nic->mii.force_media = 0;
nic->mii.advertising = ADVERTISE_1000XFULL;
nic->mii.full_duplex = 1;
err = register_netdev(netdev);
if (err) {
// if (netif_msg_probe(nic))
dev_err(&pdev->dev, "unable to register net device\n");
goto err_out_freeirq;
}
platform_set_drvdata(pdev, netdev);
/* WR NIC banner */
// if (netif_msg_probe(nic)) {
dev_info(&pdev->dev, "White Rabbit miNIC at 0x%08lx irq %d\n",
netdev->base_addr, netdev->irq);
// }
return 0;
err_out_freeirq:
free_irq(netdev->irq, &pdev->dev);
err_out_iounmap:
iounmap(nic->base);
err_out_free_netdev:
free_netdev(netdev);
err_out:
platform_set_drvdata(pdev, NULL);
return err;
}
static int __devexit minic_remove(struct platform_device *pdev)
{
struct net_device *netdev;
struct wr_minic *nic;
netdev = platform_get_drvdata(pdev);
if (!netdev)
return 0;
wrmch_vic_free_irq(netdev->irq, netdev);
nic = netdev_priv(netdev);
unregister_netdev(netdev);
iounmap(nic->base);
free_netdev(netdev);
platform_set_drvdata(pdev, NULL);
return 0;
}
#define minic_suspend NULL
#define minic_resume NULL
static struct platform_driver minic_driver = {
.remove = __exit_p(minic_remove),
.suspend = minic_suspend,
.resume = minic_resume,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
};
static int __devinit minic_init_module(void)
{
return platform_driver_probe(&minic_driver, minic_probe);
}
static void __devexit minic_cleanup_module(void)
{
platform_driver_unregister(&minic_driver);
}
module_init(minic_init_module);
module_exit(minic_cleanup_module);
obj-m := wr_vic.o
KDIR := ../../../kernel
PWD := $(shell pwd)
MAKE = make
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
White Rabbit MCH Vectored Interrupt Controller driver
------
This driver adds support for the Interrupt Controller in the main FPGA of White Rabbit MCH. The VIC multiplexes 32 source interrupts
into single interrupt CPU interrupt line (AT91SAM9263_ID_IRQ0).
exported functions:
---------------------
void wrmch_vic_free_irq(int irq, void *dev_id);
int wrmch_vic_request_irq(int irq, wrvic_irq_t handler, void *dev_id);
void wrmch_vic_enable_irq(int irq);
void wrmch_vic_disable_irq(int irq);
dev_id = private data of requesting device/driver.
\ No newline at end of file
#!/bin/sh
. ../../../settings
make CONFIG_DEBUG_SECTION_MISMATCH=y ARCH=arm CROSS_COMPILE=$CROSS_COMPILE_ARM -C ../../../kernel SUBDIRS=`pwd` modules $1
#cp wr_vic.ko ../bin
\ No newline at end of file
/*
* whiterabbit_vic.c
*
* Copyright (c) 2009 Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <asm/mach-types.h>
#include <asm/setup.h>
#include <asm/irq.h>
#include <asm/atomic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
#include "wr_vic.h"
#define DRV_MODULE_VERSION "0.1"
#define DRV_NAME "wr_vic"
#define PFX DRV_NAME ": "
/* [0x0]: REG VIC Control Register */
#define VIC_REG_CTL 0x00000000
/* [0x4]: REG Raw Interrupt Status Register */
#define VIC_REG_RISR 0x00000004
/* [0x8]: REG Interrupt Enable Register */
#define VIC_REG_IER 0x00000008
/* [0xc]: REG Interrupt Disable Register */
#define VIC_REG_IDR 0x0000000c
/* [0x10]: REG Interrupt Mask Register */
#define VIC_REG_IMR 0x00000010
/* [0x14]: REG Vector Address Register */
#define VIC_REG_VAR 0x00000014
/* [0x1c]: REG End Of Interrupt Acknowledge Register */
#define VIC_REG_EOIR 0x0000001c
#define VIC_CTL_ENABLE (1<<0)
#define VIC_CTL_POL (1<<1)
#define VIC_IVT_BASE 0x00000080
#define VIC_SPURIOUS_IRQ 0x12345678
#define vic_readl(vic, offs) \
__raw_readl((vic)->regs+ (offs))
#define vic_writel(vic, offs, value) \
__raw_writel((value), (vic)->regs + (offs))
struct wrmch_vic {
void __iomem *regs;
wrvic_irq_t handlers[WRMCH_VIC_MAX_IRQS];
void *dev_ids[WRMCH_VIC_MAX_IRQS];
};
static struct wrmch_vic *VIC;
static irqreturn_t wrmch_vic_interrupt(int irq, void *dev_id)
{
u32 reg_var;
wrvic_irq_t handler;
reg_var = vic_readl(VIC, VIC_REG_VAR); // determine the interrupt source
if (reg_var == VIC_SPURIOUS_IRQ)
printk(KERN_ERR PFX "spurious interrupt");
else
{
// printk("Got irq: var %d\n", reg_var);
handler = VIC->handlers[reg_var];
handler(VIC->dev_ids[reg_var]);
}
vic_writel(VIC, VIC_REG_EOIR, 0); // clear the interrupt pending flag
return IRQ_HANDLED;
}
int wrmch_vic_request_irq(int irq, wrvic_irq_t handler, void *dev_id)
{
if (irq < 0 || irq >= WRMCH_VIC_MAX_IRQS)
return -EINVAL;
if (VIC->handlers[irq])
return -EADDRINUSE;
VIC->handlers[irq] = handler;
VIC->dev_ids[irq] = dev_id;
vic_writel(VIC, VIC_IVT_BASE + (irq << 2), irq); //(u32)handler);
wrmch_vic_enable_irq(irq);
return 0;
}
void wrmch_vic_free_irq(int irq, void *dev_id)
{
if (irq < 0 || irq >= WRMCH_VIC_MAX_IRQS)
return;
if (VIC->dev_ids[irq] != dev_id)
return;
wrmch_vic_disable_irq(irq);
vic_writel(VIC, VIC_IVT_BASE + (irq << 2), VIC_SPURIOUS_IRQ);
VIC->handlers[irq] = NULL;
VIC->dev_ids[irq] = NULL;
}
void wrmch_vic_enable_irq(int irq)
{
if (irq < 0 || irq >= WRMCH_VIC_MAX_IRQS)
return;
vic_writel(VIC, VIC_REG_IER, (1<<irq));
// printk("vic_enable_irq: irq %d imr %x\n", irq, vic_readl(VIC, VIC_REG_IMR));
}
void wrmch_vic_disable_irq(int irq)
{
if (irq < 0 || irq >= WRMCH_VIC_MAX_IRQS)
return;
vic_writel(VIC, VIC_REG_IDR, (1<<irq));
// printk("vic_disable_irq: irq %d imr %x\n", irq, vic_readl(VIC, VIC_REG_IMR));
}
static int __devinit wrmch_vic_init_module(void)
{
int err, i;
VIC = kzalloc(sizeof(struct wrmch_vic), GFP_KERNEL);
VIC->regs = ioremap(FPGA_BASE_VIC, 0x1000);
vic_writel(VIC, VIC_REG_CTL, 0); // output is active LO
vic_writel(VIC, VIC_REG_IDR, 0xffffffff); // disable all interrupts
err = request_irq(AT91SAM9263_ID_IRQ0, wrmch_vic_interrupt,
IRQF_TRIGGER_LOW | IRQF_SHARED, "whiterabbit_vic",
VIC);
if (unlikely(err)) {
printk(KERN_ERR PFX "request IRQ for WR VIC failed");
return err;
}
/* clear the vector table */
for (i = 0; i < WRMCH_VIC_MAX_IRQS; i++)
vic_writel(VIC, VIC_IVT_BASE + (i<<2), VIC_SPURIOUS_IRQ);
vic_writel(VIC, VIC_REG_CTL, VIC_CTL_ENABLE); // enable the VIC
printk(KERN_INFO PFX "module initialized");
return 0;
}
static void __devexit wrmch_vic_cleanup_module(void)
{
free_irq(AT91SAM9263_ID_IRQ0, VIC);
if (VIC) {
if (VIC->regs) {
iounmap(VIC->regs);
VIC->regs = NULL;
}
kfree(VIC);
VIC = NULL;
}
printk(KERN_INFO PFX "module cleanup");
}
EXPORT_SYMBOL_GPL(wrmch_vic_request_irq);
EXPORT_SYMBOL_GPL(wrmch_vic_free_irq);
EXPORT_SYMBOL_GPL(wrmch_vic_enable_irq);
EXPORT_SYMBOL_GPL(wrmch_vic_disable_irq);
module_init(wrmch_vic_init_module);
module_exit(wrmch_vic_cleanup_module);
MODULE_AUTHOR("Tomasz Wlostowski");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("White Rabbit MCH Vectored Interrupt Controller driver");
MODULE_VERSION(DRV_MODULE_VERSION);
#ifndef __WHITERABBIT_VIC_H
#define __WHITERABBIT_VIC_H
#define FPGA_BASE_VIC 0x70030000
#define WRMCH_VIC_MAX_IRQS 32
typedef void (*wrvic_irq_t)(void *dev_id);
int wrmch_vic_request_irq(int irq, wrvic_irq_t handler, void *dev_id);
void wrmch_vic_free_irq(int irq, void *dev_id);
void wrmch_vic_enable_irq(int irq);
void wrmch_vic_disable_irq(int irq);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment