Commit 752ec733 authored by Alessandro Rubini's avatar Alessandro Rubini

Merge branch 'wr-nic-devel'

parents 24da69e3 ea1e3c65
This diff is collapsed.
......@@ -21,6 +21,12 @@ spec-$(CONFIG_GPIOLIB) += spec-gpio.o
wr-nic-y = wr-nic-core.o
wr-nic-y += wr-nic-eth.o
wr-nic-y += wr-nic-dio.o
wr-nic-y += wr_nic/device.o
wr-nic-y += wr_nic/endpoint.o
wr-nic-y += wr_nic/ethtool.o
wr-nic-y += wr_nic/nic-core.o
wr-nic-y += wr_nic/timestamp.o
wr-nic-$(CONFIG_GPIOLIB) += wr-nic-gpio.o
......
#ifndef __WR_NIC_H__
#define __WR_NIC_H__
#ifndef __SPEC_NIC_H__
#define __SPEC_NIC_H__
#include <linux/gpio.h>
/*
......@@ -28,20 +28,50 @@
* -- 0x200: DIO-GPIO
* -- 0x300: DIO-REGISTERS
* (plus, at 63000 there are the sdb records)
*
* However, we are extracting this information from SDB
*/
#define WRN_SDB_ADDR 0x63000
#define WRN_GPIO 0x62200 /* "standard" GPIO registers */
#define WRN_DIO 0x62300 /* time-aware gpio registers */
#define WRN_SDB 0x63000
#define SDB_CERN 0xce42LL
#define SDB_7SOL 0x75cbLL
#define WRN_SDB_RAM 0x66cfeb52
#define WRN_SDB_NIC 0x00000012
#define WRN_SDB_EP 0x650c2d4f
#define WRN_SDB_PPSG 0xde0d8ced
#define WRN_SDB_TS 0x00000014
#define WRN_SDB_VIC 0x00000013
#define WRN_SDB_GPIO 0x441c5143
#define WRN_SDB_WRDIO 0x00000001
#define WRN_SDB_SYSCON 0xff07fc47
#define WRN_GATEWARE_DEFAULT_NAME "fmc/wr_nic_dio.bin"
#define WRN_WRC_DEFAULT_NAME "fmc/wr_nic_dio-wrc.bin"
/* the various interrupt sources for the VIC */
#define WRN_VIC_MASK_NIC 0x0002
/* This is somehow generic, but I find no better place at this time */
#ifndef SET_HI32
# if BITS_PER_LONG > 32
# define SET_HI32(var, value) ((var) |= (value) << 32)
# define GET_HI32(var) ((var) >> 32)
# else
# define SET_HI32(var, value) ((var) |= 0)
# define GET_HI32(var) 0
# endif
#endif
struct wrn_drvdata {
struct gpio_chip *gc;
struct net_device *eth;
struct wrn_dev *wrn;
struct fmc_device *fmc;
/* We also need the various base addresses here for fmc_writel/readl */
__iomem void *gpio_baseaddr;
__iomem void *vic_base;
__iomem void *gpio_base;
__iomem void *wrdio_base;
__iomem void *ppsg_base;
};
/* wr-nic-eth.c */
......
# This Makefile is used to reproduce the headers from svn checkout.
# You need to have "wbgen2" in your command search path and the white-rabbit
# repos (wr-cores and wr-switch-hdl) Git checkout in $REPOS.
# Since this is only meant to be used by me (or Tom) no serious checking is done.
# List of input files in Git checkout
MODULES_WRS ?= $(REPOS)/wr-switch-hdl/modules
MODULES_WRC ?= $(REPOS)/wr-cores/modules
#SPECS = $(HW_REPO)/trunk/documentation/specifications
WB_ENDPOINT = $(MODULES_WRC)/wr_endpoint/ep_wishbone_controller.wb
WB_MDIO = $(MODULES_WRC)/wr_endpoint/pcs_regs.wb
WB_PPSG = $(MODULES_WRC)/wr_pps_gen/pps_gen_wb.wb
WB_TSTAMP = $(MODULES_WRS)/wrsw_txtsu/wrsw_txtsu.wb
WB_RTU = $(MODULES_WRS)/wrsw_rtu/rtu_wishbone_slave.wb
WB_NIC = $(MODULES_WRS)/wrsw_nic/wr_nic.wb
WB_SOFTPLL = $(MODULES_WRC)/wr_softpll_ng/spll_wb_slave.wb
HEADERS = endpoint-regs.h endpoint-mdio.h ppsg-regs.h tstamp-regs.h rtu-regs.h \
nic-regs.h softpll-regs.h
WBINPUT = $(HEADERS:.h=wb)
# No default, for people who types "make" everywhere (like me)
all:
@echo "This is for developer's use, see Makefile for details"
exit 1
# The headers rule regenerates headers from local wb files
headers: $(HEADERS)
%.h: %.wb
wbgen2 --cstyle=struct --co=$@ $<
sed -i 's,#include <inttypes.h>,#ifdef __KERNEL__\n#include <linux/types.h>\n#else\n#include <stdint.h>\n#endif\n,' $@
sed -i '/ Created *: .*20[0-9][0-9]$$/ d' $@
sed -i 's/-REGS_WB//' $@
# The wbinput rule just copies here stuff from svn.
# Do it silent so errors stand out
wbinput:
@cp $(WB_ENDPOINT) endpoint-regs.wb
@cp $(WB_MDIO) endpoint-mdio.wb
@cp $(WB_PPSG) ppsg-regs.wb
@cp $(WB_TSTAMP) tstamp-regs.wb
@cp $(WB_RTU) rtu-regs.wb
@cp $(WB_NIC) nic-regs.wb
@cp $(WB_SOFTPLL) softpll-regs.wb
@echo "Copied input files from subversions to local directory"
The headers have been derived from what is in svn:
documentation/specifications/hdlspec/memory_map/
In that directory you find the html generated from the wb files.
Here I import the relevant headers. The overall register
map is in ../nic/nic-hardware.h .
The .wb files whence the headers are generated come from different
plases in the white rabbit svn. To ease myself I wrote this in
the Makefile. You can "make wbinput" to get a fresh copy of them,
provided you have SVN set in your environment (point to the root
checkout, before "trunk" subdirectory). If unset or wrong, cp fails.
With "make headers" you can regenerate the headers from the wb input
files. Each generated file is postprocesses with sed to fix these
issues:
* generated files include <inttypes.h> as they use uint32_t. We want
<linux/types.h> instead, as no <inttypes.h> nor <stdint.h> is there
* generated files include the date of creation. This brings to noise
in the "git diff" or plain "diff", so I'd better have no date.
* creation of "#ifdef __THIS_HEADER__" fails on the dash, so I remove
the dash and trailing part with sed (as of writing, it has issues with
pathnames too, this is one the reasons why I copy the wb here first).
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
Register definitions for slave core: WR Switch PPS generator and RTC
* File : ppsg-regs.h
* Author : auto-generated by wbgen2 from ppsg-regs.wb
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE ppsg-regs.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_PPSG
#define __WBGEN2_REGDEFS_PPSG
#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <stdint.h>
#endif
#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) */
/* definitions for register: External sync control register */
/* definitions for field: Sync to external PPS input in reg: External sync control register */
#define PPSG_ESCR_SYNC WBGEN2_GEN_MASK(0, 1)
/* definitions for field: PPS output valid in reg: External sync control register */
#define PPSG_ESCR_PPS_VALID WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Timecode output(UTC+cycles) valid in reg: External sync control register */
#define PPSG_ESCR_TM_VALID WBGEN2_GEN_MASK(2, 1)
PACKED struct PPSG_WB {
/* [0x0]: REG Control Register */
uint32_t CR;
/* [0x4]: REG Nanosecond counter register */
uint32_t CNTR_NSEC;
/* [0x8]: REG UTC Counter register (least-significant part) */
uint32_t CNTR_UTCLO;
/* [0xc]: REG UTC Counter register (most-significant part) */
uint32_t CNTR_UTCHI;
/* [0x10]: REG Nanosecond adjustment register */
uint32_t ADJ_NSEC;
/* [0x14]: REG UTC Adjustment register (least-significant part) */
uint32_t ADJ_UTCLO;
/* [0x18]: REG UTC Adjustment register (most-significant part) */
uint32_t ADJ_UTCHI;
/* [0x1c]: REG External sync control register */
uint32_t ESCR;
};
#endif
-- -*- Mode: LUA; tab-width: 2 -*-
peripheral {
name = "WR Switch PPS generator and RTC";
description = "Unit generating PPS signals and acting as a UTC real-time clock";
hdl_entity = "pps_gen_wb";
prefix = "ppsg";
reg {
name = "Control Register";
prefix = "CR";
field {
name = "Reset counter";
description = "write 1: resets the counter\
write 0: no effect";
prefix = "CNT_RST";
type = MONOSTABLE;
clock = "refclk_i";
};
field {
name = "Enable counter";
description = "1: PPS counter is enabled";
prefix = "CNT_EN";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
clock = "refclk_i";
};
field {
name = "Adjust offset";
description = "write 1: Starts adjusting PPS/UTC offsets by adding the values taken from ADJ_NSEC, ADJ_UTCLO, ADJ_UTCHI registers to the current PPS counter value. These registers need to be programmed prior to update.\
write 0: no effect\
read 0: adjustment operation is done\
read 1: adjustment operation is in progress";
prefix = "CNT_ADJ";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
clock = "refclk_i";
};
field {
name = "Set time";
description = "write 1: Sets the UTC/PPS counter to values taken from ADJ_NSEC, ADJ_UTCLO, ADJ_UTCHI registers";
prefix = "CNT_SET";
type = MONOSTABLE;
clock = "refclk_i";
};
field {
name = "PPS Pulse width";
description = "Width of generated PPS pulses in 125 MHz refernce clock cycles";
prefix = "PWIDTH";
size = 28;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
clock= "refclk_i";
};
};
reg {
name = "Nanosecond counter register";
description = "Nanosecond part of current time, expressed as number of 125 MHz reference clock cycles";
prefix = "CNTR_NSEC";
field {
name = "Nanosecond counter";
type = SLV;
size = 28;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
clock = "refclk_i";
};
};
reg {
name = "UTC Counter register (least-significant part)";
description = "Lower 32 bits of current UTC time";
prefix = "CNTR_UTCLO";
field {
name = "UTC Counter";
type = SLV;
size = 32;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
clock = "refclk_i";
};
};
reg {
name = "UTC Counter register (most-significant part)";
description = "Highest 8 bits of current UTC time";
prefix = "CNTR_UTCHI";
field {
name = "UTC Counter";
type = SLV;
size = 8;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
clock = "refclk_i";
};
};
reg {
name = "Nanosecond adjustment register";
description = "Adjustment value for nanosecond counter";
prefix = "ADJ_NSEC";
field {
name = "Nanosecond adjustment";
type = PASS_THROUGH;
size = 28;
};
};
reg {
name = "UTC Adjustment register (least-significant part)";
description = "Lower 32 bits of adjustment value for UTC";
prefix = "ADJ_UTCLO";
field {
name = "UTC Counter adjustment";
type = PASS_THROUGH;
size = 32;
};
};
reg {
name = "UTC Adjustment register (most-significant part)";
description = "Highest 8 bits of adjustment value for UTC";
prefix = "ADJ_UTCHI";
field {
name = "UTC Counter adjustment";
type = PASS_THROUGH;
size = 8;
};
};
reg {
name = "External sync control register";
prefix = "ESCR";
field {
name = "Sync to external PPS input";
description = "write 1: Waits until a pulse on external PPS input arrives and re-synchronizes the PPS counter to it\
write 0: no effect\
read 1: external synchronization done\
read 0: external synchronization in progress";
type = BIT;
prefix = "SYNC";
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
clock = "refclk_i";
};
field {
name = "PPS output valid";
description = "write 1: PPS output provides reliable 1-PPS signal\
write 0: PPS output is invalid";
prefix = "PPS_VALID";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
clock = "refclk_i";
};
field {
name = "Timecode output(UTC+cycles) valid";
description = "write 1: Timecode output provides valid time\
write 0: Timecode output does not provide valid time";
prefix = "TM_VALID";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
clock = "refclk_i";
};
};
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
Register definitions for slave core: Shared TX Timestamping Unit (TXTSU)
* File : tstamp-regs.h
* Author : auto-generated by wbgen2 from tstamp-regs.wb
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE tstamp-regs.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_TSTAMP
#define __WBGEN2_REGDEFS_TSTAMP
#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <stdint.h>
#endif
#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: Interrupt disable register */
/* definitions for field: TXTSU fifo not-empty in reg: Interrupt disable register */
#define TXTSU_EIC_IDR_NEMPTY WBGEN2_GEN_MASK(0, 1)
/* definitions for register: Interrupt enable register */
/* definitions for field: TXTSU fifo not-empty in reg: Interrupt enable register */
#define TXTSU_EIC_IER_NEMPTY WBGEN2_GEN_MASK(0, 1)
/* definitions for register: Interrupt mask register */
/* definitions for field: TXTSU fifo not-empty in reg: Interrupt mask register */
#define TXTSU_EIC_IMR_NEMPTY WBGEN2_GEN_MASK(0, 1)
/* definitions for register: Interrupt status register */
/* definitions for field: TXTSU fifo not-empty in reg: Interrupt status register */
#define TXTSU_EIC_ISR_NEMPTY WBGEN2_GEN_MASK(0, 1)
/* definitions for register: FIFO 'Timestamp FIFO' data output register 0 */
/* definitions for field: Rising edge timestamp in reg: FIFO 'Timestamp FIFO' data output register 0 */
#define TXTSU_TSF_R0_VAL_R_MASK WBGEN2_GEN_MASK(0, 28)
#define TXTSU_TSF_R0_VAL_R_SHIFT 0
#define TXTSU_TSF_R0_VAL_R_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define TXTSU_TSF_R0_VAL_R_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for field: Falling edge timestamp in reg: FIFO 'Timestamp FIFO' data output register 0 */
#define TXTSU_TSF_R0_VAL_F_MASK WBGEN2_GEN_MASK(28, 4)
#define TXTSU_TSF_R0_VAL_F_SHIFT 28
#define TXTSU_TSF_R0_VAL_F_W(value) WBGEN2_GEN_WRITE(value, 28, 4)
#define TXTSU_TSF_R0_VAL_F_R(reg) WBGEN2_GEN_READ(reg, 28, 4)
/* definitions for register: FIFO 'Timestamp FIFO' data output register 1 */
/* definitions for field: Physical port ID in reg: FIFO 'Timestamp FIFO' data output register 1 */
#define TXTSU_TSF_R1_PID_MASK WBGEN2_GEN_MASK(0, 5)
#define TXTSU_TSF_R1_PID_SHIFT 0
#define TXTSU_TSF_R1_PID_W(value) WBGEN2_GEN_WRITE(value, 0, 5)
#define TXTSU_TSF_R1_PID_R(reg) WBGEN2_GEN_READ(reg, 0, 5)
/* definitions for field: Frame ID in reg: FIFO 'Timestamp FIFO' data output register 1 */
#define TXTSU_TSF_R1_FID_MASK WBGEN2_GEN_MASK(16, 16)
#define TXTSU_TSF_R1_FID_SHIFT 16
#define TXTSU_TSF_R1_FID_W(value) WBGEN2_GEN_WRITE(value, 16, 16)
#define TXTSU_TSF_R1_FID_R(reg) WBGEN2_GEN_READ(reg, 16, 16)
/* definitions for register: FIFO 'Timestamp FIFO' data output register 2 */
/* definitions for field: Timestamp (possibly) incorrect in reg: FIFO 'Timestamp FIFO' data output register 2 */
#define TXTSU_TSF_R2_INCORRECT WBGEN2_GEN_MASK(0, 1)
/* definitions for register: FIFO 'Timestamp FIFO' control/status register */
/* definitions for field: FIFO full flag in reg: FIFO 'Timestamp FIFO' control/status register */
#define TXTSU_TSF_CSR_FULL WBGEN2_GEN_MASK(16, 1)
/* definitions for field: FIFO empty flag in reg: FIFO 'Timestamp FIFO' control/status register */
#define TXTSU_TSF_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* definitions for field: FIFO counter in reg: FIFO 'Timestamp FIFO' control/status register */
#define TXTSU_TSF_CSR_USEDW_MASK WBGEN2_GEN_MASK(0, 8)
#define TXTSU_TSF_CSR_USEDW_SHIFT 0
#define TXTSU_TSF_CSR_USEDW_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define TXTSU_TSF_CSR_USEDW_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
PACKED struct TXTSU_WB {
/* [0x0]: REG Interrupt disable register */
uint32_t EIC_IDR;
/* [0x4]: REG Interrupt enable register */
uint32_t EIC_IER;
/* [0x8]: REG Interrupt mask register */
uint32_t EIC_IMR;
/* [0xc]: REG Interrupt status register */
uint32_t EIC_ISR;
/* [0x10]: REG FIFO 'Timestamp FIFO' data output register 0 */
uint32_t TSF_R0;
/* [0x14]: REG FIFO 'Timestamp FIFO' data output register 1 */
uint32_t TSF_R1;
/* [0x18]: REG FIFO 'Timestamp FIFO' data output register 2 */
uint32_t TSF_R2;
/* [0x1c]: REG FIFO 'Timestamp FIFO' control/status register */
uint32_t TSF_CSR;
};
#endif
-- -*- Mode: LUA; tab-width: 2 -*-
peripheral {
name = "Shared TX Timestamping Unit (TXTSU)";
prefix="txtsu";
hdl_entity="wrsw_txtsu_wb";
-- TXTSU shared FIFO
fifo_reg {
size = 256; -- or more. We'll see :)
direction = CORE_TO_BUS;
prefix = "tsf";
name = "Timestamp FIFO";
description = "This FIFO holds the TX packet timestamps gathered from all switch endpoints. Each entry contains a single timestamp value consisting of 2 numbers:\
- VAL_R - the timestamp taken at rising clock edge. This is the main timestamp value\
- VAL_F - few LSBs of timestamp taken at falling clock edge. It's used in conjunction with VAL_R to determine if the timestamp has been taken\
properly (there was no metastability/setup/hold violation)\
Entries also contain information required to identify the endpoint and frame for which the timestamp was taken:\
- FID - Frame identifier assigned by the NIC\
- PID - TXTSU port ID to which came the timestamp. Used to distinguish the timestamps for broadcast/multicast frames;\
- INCORRECT - timestamp may be incorrect, it has been generated during timebase adjustment";
flags_bus = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
flags_dev = {FIFO_FULL, FIFO_EMPTY};
field {
name = "Rising edge timestamp";
descritpion = "Timestamp value taken on rising clock edge (full word)";
prefix = "val_r";
type = SLV;
size = 28;
};
field {
name = "Falling edge timestamp";
description = "Timestamp value taken on falling clock edge (few LSBs)";
prefix = "val_f";
type = SLV;
size = 4;
};
field {
name ="Physical port ID";
description = "Identifier of the TXTSU port to which came the timestamp. There may be multiple timestamps sharing the same FID value for broadcast/multicast packets.";
prefix = "pid";
type = SLV;
size = 5;
align= 16;
};
field {
name = "Frame ID";
description = "OOB Frame Identifier. Used to associate the timestamp value with transmitted packet.";
prefix = "fid";
type = SLV;
size = 16;
align = 16;
};
field {
name = "Timestamp (possibly) incorrect";
description = "1: This timestamp may be incorrect (generated during PPS adjustment)\
0: Timestamp is correct.";
prefix = "incorrect";
type = BIT;
};
};
-- TXTSU interrupts
irq {
name = "TXTSU fifo not-empty";
description = "Interrupt active when TXTSU shared FIFO contains any timestamps.";
prefix = "nempty";
trigger = LEVEL_1;
};
};
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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