diff options
author | John Crispin <blogic@openwrt.org> | 2009-10-02 09:41:22 +0000 |
---|---|---|
committer | John Crispin <blogic@openwrt.org> | 2009-10-02 09:41:22 +0000 |
commit | c7d739f41d4263027ac577c6339c6449e15df28b (patch) | |
tree | 8caf0c94e441c5d63db606081de7ccf0748a04cf | |
parent | 995eaeb63c8d1df61e7d027201dc744fabd17380 (diff) | |
download | master-187ad058-c7d739f41d4263027ac577c6339c6449e15df28b.tar.gz master-187ad058-c7d739f41d4263027ac577c6339c6449e15df28b.tar.bz2 master-187ad058-c7d739f41d4263027ac577c6339c6449e15df28b.zip |
adds atm driver for ifxmips, code ported from wippies 2.6.16 gpl release. it compiles but throws ioctl -EINVAL during bring up of atm device, hence marked as broken
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@17819 3c298f89-4303-0410-b956-a3cf2f4a3e73
-rw-r--r-- | package/ifxmips-atm/Makefile | 49 | ||||
-rw-r--r-- | package/ifxmips-atm/src/Makefile | 4 | ||||
-rw-r--r-- | package/ifxmips-atm/src/common.h | 896 | ||||
-rw-r--r-- | package/ifxmips-atm/src/core.c | 800 | ||||
-rw-r--r-- | package/ifxmips-atm/src/ifx_ppe_fw.h | 426 | ||||
-rw-r--r-- | package/ifxmips-atm/src/irq.c | 506 | ||||
-rw-r--r-- | package/ifxmips-atm/src/ppe.c | 838 | ||||
-rw-r--r-- | package/ifxmips-atm/src/proc.c | 98 | ||||
-rw-r--r-- | package/ifxmips-atm/src/proc.h | 9 | ||||
-rw-r--r-- | package/ifxmips-atm/src/skb.c | 128 |
10 files changed, 3754 insertions, 0 deletions
diff --git a/package/ifxmips-atm/Makefile b/package/ifxmips-atm/Makefile new file mode 100644 index 0000000000..68b77b6c75 --- /dev/null +++ b/package/ifxmips-atm/Makefile @@ -0,0 +1,49 @@ +# Copyright (C) 2009 OpenWrt.org +# All rights reserved. +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +# blogic@openwrt.org +# + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=ifxmips-atm +PKG_RELEASE:=1 + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/ifxmips-atm + SUBMENU:=Network Devices + DEPENDS:=@BROKEN @TARGET_ifxmips +kmod-atm + TITLE:=ifxmips atm driver + FILES:=$(PKG_BUILD_DIR)/ifx-atm.$(LINUX_KMOD_SUFFIX) + AUTOLOAD:=$(call AutoLoad,50,ifx-atm) +endef + +define Kernel/Package/ifxmips-atm/description + This package provides the atm driver needed to make dsl work on ifxmips based boards +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Compile + $(MAKE) -C "$(LINUX_DIR)" \ + CROSS_COMPILE="$(TARGET_CROSS)" \ + ARCH="$(LINUX_KARCH)" \ + SUBDIRS="$(PKG_BUILD_DIR)" \ + modules +endef + +define KernelPackage/ifxmips-atm/install + $(INSTALL_DIR) $(1)/lib/modules/$(LINUX_VERSION) + $(CP) $(PKG_BUILD_DIR)/ifx-atm.ko $(1)/lib/modules/$(LINUX_VERSION) +endef + +$(eval $(call KernelPackage,ifxmips-atm)) + diff --git a/package/ifxmips-atm/src/Makefile b/package/ifxmips-atm/src/Makefile new file mode 100644 index 0000000000..23e0ea067e --- /dev/null +++ b/package/ifxmips-atm/src/Makefile @@ -0,0 +1,4 @@ +obj-m += ifx-atm.o +ifx-atm-objs := skb.o irq.o proc.o core.o ppe.o + +EXTRA_CFLAGS += -DENABLE_RX_QOS=1 diff --git a/package/ifxmips-atm/src/common.h b/package/ifxmips-atm/src/common.h new file mode 100644 index 0000000000..aad6a984e6 --- /dev/null +++ b/package/ifxmips-atm/src/common.h @@ -0,0 +1,896 @@ +#include <linux/atmdev.h> +#include <asm/ifxmips/ifxmips_irq.h> +#include <linux/irq.h> +#include <linux/sem.h> +#include <linux/coda.h> + +#define RX_DMA_CH_CBR 0 +#define RX_DMA_CH_VBR_RT 1 +#define RX_DMA_CH_VBR_NRT 2 +#define RX_DMA_CH_AVR 3 +#define RX_DMA_CH_UBR 4 +#define RX_DMA_CH_OAM 5 +#define RX_DMA_CH_TOTAL 6 + +#define WRX_DMA_CHANNEL_INTERRUPT_MODE 0x00 +#define WRX_DMA_CHANNEL_POLLING_MODE 0x01 +//#define WRX_DMA_CHANNEL_COUNTER_MODE 0x02 +#define WRX_DMA_CHANNEL_COUNTER_MODE WRX_DMA_CHANNEL_INTERRUPT_MODE +#define WRX_DMA_BUF_LEN_PER_DESCRIPTOR 0x00 +#define WRX_DMA_BUF_LEN_PER_CHANNEL 0x01 + +#define ATM_VBR_RT 6 +#define ATM_VBR_NRT ATM_VBR +#define ATM_UBR_PLUS 7 + +#define SET_BITS(x, msb, lsb, value) (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb))) + +#define GET_ATM_PRIV(dev) ((Atm_Priv *)dev->priv) + +#define CDM_CFG PPE_REG_ADDR(0x0100) + +#define CDM_CFG_RAM1 GET_BITS(*CDM_CFG, 3, 2) +#define CDM_CFG_RAM0 (*CDM_CFG & (1 << 1)) + +#define CDM_CFG_RAM1_SET(value) SET_BITS(0, 3, 2, value) +#define CDM_CFG_RAM0_SET(value) ((value) ? (1 << 1) : 0) + +/* + * EMA Registers + */ +#define EMA_CMDCFG PPE_REG_ADDR(0x0A00) +#define EMA_DATACFG PPE_REG_ADDR(0x0A01) +#define EMA_CMDCNT PPE_REG_ADDR(0x0A02) +#define EMA_DATACNT PPE_REG_ADDR(0x0A03) +#define EMA_ISR PPE_REG_ADDR(0x0A04) +#define EMA_IER PPE_REG_ADDR(0x0A05) +#define EMA_CFG PPE_REG_ADDR(0x0A06) +#define EMA_SUBID PPE_REG_ADDR(0x0A07) + + +/* + * QSB RAM Access Register + */ +#define QSB_RAMAC QSB_CONF_REG(0x000D) + +#define QSB_RAMAC_RW (*QSB_RAMAC & (1 << 31)) +#define QSB_RAMAC_TSEL GET_BITS(*QSB_RAMAC, 27, 24) +#define QSB_RAMAC_LH (*QSB_RAMAC & (1 << 16)) +#define QSB_RAMAC_TESEL GET_BITS(*QSB_RAMAC, 9, 0) + +#define QSB_RAMAC_RW_SET(value) ((value) ? (1 << 31) : 0) +#define QSB_RAMAC_TSEL_SET(value) SET_BITS(0, 27, 24, value) +#define QSB_RAMAC_LH_SET(value) ((value) ? (1 << 16) : 0) +#define QSB_RAMAC_TESEL_SET(value) SET_BITS(0, 9, 0, value) + +/* QSB */ +#define QSB_RAMAC_RW_READ 0 +#define QSB_RAMAC_RW_WRITE 1 + +#define QSB_RAMAC_TSEL_QPT 0x01 +#define QSB_RAMAC_TSEL_SCT 0x02 +#define QSB_RAMAC_TSEL_SPT 0x03 +#define QSB_RAMAC_TSEL_VBR 0x08 + +#define QSB_RAMAC_LH_LOW 0 +#define QSB_RAMAC_LH_HIGH 1 + +#define QSB_QPT_SET_MASK 0x0 +#define QSB_QVPT_SET_MASK 0x0 +#define QSB_SET_SCT_MASK 0x0 +#define QSB_SET_SPT_MASK 0x0 +#define QSB_SET_SPT_SBVALID_MASK 0x7FFFFFFF + +#define QSB_SPT_SBV_VALID (1 << 31) +#define QSB_SPT_PN_SET(value) (((value) & 0x01) ? (1 << 16) : 0) +#define QSB_SPT_INTRATE_SET(value) SET_BITS(0, 13, 0, value) + +/* + * QSB Internal Cell Delay Variation Register + */ +#define QSB_ICDV QSB_CONF_REG(0x0007) + +#define QSB_ICDV_TAU GET_BITS(*QSB_ICDV, 5, 0) + +#define QSB_ICDV_TAU_SET(value) SET_BITS(0, 5, 0, value) + +/* + * QSB Scheduler Burst Limit Register + */ +#define QSB_SBL QSB_CONF_REG(0x0009) + +#define QSB_SBL_SBL GET_BITS(*QSB_SBL, 3, 0) + +#define QSB_SBL_SBL_SET(value) SET_BITS(0, 3, 0, value) + +/* + * QSB Configuration Register + */ +#define QSB_CFG QSB_CONF_REG(0x000A) + +#define QSB_CFG_TSTEPC GET_BITS(*QSB_CFG, 1, 0) + +#define QSB_CFG_TSTEPC_SET(value) SET_BITS(0, 1, 0, value) + +/* + * QSB RAM Transfer Table Register + */ +#define QSB_RTM QSB_CONF_REG(0x000B) + +#define QSB_RTM_DM (*QSB_RTM) + +#define QSB_RTM_DM_SET(value) ((value) & 0xFFFFFFFF) + +/* + * QSB RAM Transfer Data Register + */ +#define QSB_RTD QSB_CONF_REG(0x000C) + +#define QSB_RTD_TTV (*QSB_RTD) + +#define QSB_RTD_TTV_SET(value) ((value) & 0xFFFFFFFF) + +/* + * PP32 Debug Control Register + */ +#define PP32_DBG_CTRL PP32_DEBUG_REG_ADDR(0x0000) + +#define DBG_CTRL_START_SET(value) ((value) ? (1 << 0) : 0) +#define DBG_CTRL_STOP_SET(value) ((value) ? (1 << 1) : 0) +#define DBG_CTRL_STEP_SET(value) ((value) ? (1 << 2) : 0) + +#define SB_RAM0_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x8000) << 2))) +#define UPDATE_VCC_STAT(conn, item, num) do { ppe_dev.connection[conn].item += num; } while (0) +/* + * EMA Settings + */ +#define EMA_CMD_BUF_LEN 0x0040 +#define EMA_CMD_BASE_ADDR (0x00001580 << 2) +#define EMA_DATA_BUF_LEN 0x0100 +#define EMA_DATA_BASE_ADDR (0x00001900 << 2) +#define EMA_WRITE_BURST 0x2 +#define EMA_READ_BURST 0x2 + + +#define CELL_SIZE ATM_AAL0_SDU +#define IDLE_CYCLE_NUMBER 30000 + +#define MBOX_IGU1_ISR PPE_REG_ADDR(0x0206) +#define MBOX_IGU3_ISRS PPE_REG_ADDR(0x0214) +#define MBOX_IGU1_ISRC PPE_REG_ADDR(0x0205) +#define MBOX_IGU3_ISR PPE_REG_ADDR(0x0216) +#define MBOX_IGU3_ISRS_SET(n) (1 << (n)) +#define MBOX_IGU3_ISR_ISR(n) (*MBOX_IGU3_ISR & (1 << (n))) +/* + * * Mailbox IGU1 Registers + * */ +#define MBOX_IGU1_ISRS PPE_REG_ADDR(0x0204) +#define MBOX_IGU1_IER PPE_REG_ADDR(0x0207) + +#define MBOX_IGU1_ISRS_SET(n) (1 << (n)) +#define MBOX_IGU1_ISRC_CLEAR(n) (1 << (n)) +#define MBOX_IGU1_ISR_ISR(n) (*MBOX_IGU1_ISR & (1 << (n))) +#define MBOX_IGU1_IER_EN(n) (*MBOX_IGU1_IER & (1 << (n))) +#define MBOX_IGU1_IER_EN_SET(n) (1 << (n)) + +/* + * * Mailbox IGU3 Registers + * */ +#define MBOX_IGU3_ISRC PPE_REG_ADDR(0x0215) +#define MBOX_IGU3_IER PPE_REG_ADDR(0x0217) + +#define MBOX_IGU3_ISRS_SET(n) (1 << (n)) +#define MBOX_IGU3_ISRC_CLEAR(n) (1 << (n)) +#define MBOX_IGU3_ISR_ISR(n) (*MBOX_IGU3_ISR & (1 << (n))) +#define MBOX_IGU3_IER_EN(n) (*MBOX_IGU3_IER & (1 << (n))) +#define MBOX_IGU3_IER_EN_SET(n) (1 << (n)) + + +// RX Frame Definitions +#define MAX_RX_PACKET_ALIGN_BYTES 3 +#define MAX_RX_PACKET_PADDING_BYTES 3 +#define RX_INBAND_TRAILER_LENGTH 8 +#define MAX_RX_FRAME_EXTRA_BYTES (RX_INBAND_TRAILER_LENGTH + MAX_RX_PACKET_ALIGN_BYTES + MAX_RX_PACKET_PADDING_BYTES) + +// TX Frame Definitions +#define MAX_TX_HEADER_ALIGN_BYTES 12 +#define MAX_TX_PACKET_ALIGN_BYTES 3 +#define MAX_TX_PACKET_PADDING_BYTES 3 +#define TX_INBAND_HEADER_LENGTH 8 +#define MAX_TX_FRAME_EXTRA_BYTES (TX_INBAND_HEADER_LENGTH + MAX_TX_HEADER_ALIGN_BYTES + MAX_TX_PACKET_ALIGN_BYTES + MAX_TX_PACKET_PADDING_BYTES) + + +// DWORD-Length of Memory Blocks +#define PP32_DEBUG_REG_DWLEN 0x0030 +#define PPM_INT_REG_DWLEN 0x0010 +#define PP32_INTERNAL_RES_DWLEN 0x00C0 +#define PPE_CLOCK_CONTROL_DWLEN 0x0F00 +#define CDM_CODE_MEMORY_RAM0_DWLEN 0x1000 +#define CDM_CODE_MEMORY_RAM1_DWLEN 0x0800 +#define PPE_REG_DWLEN 0x1000 +#define PP32_DATA_MEMORY_RAM1_DWLEN 0x0800 +#define PPM_INT_UNIT_DWLEN 0x0100 +#define PPM_TIMER0_DWLEN 0x0100 +#define PPM_TASK_IND_REG_DWLEN 0x0100 +#define PPS_BRK_DWLEN 0x0100 +#define PPM_TIMER1_DWLEN 0x0100 +#define SB_RAM0_DWLEN 0x0400 +#define SB_RAM1_DWLEN 0x0800 +#define SB_RAM2_DWLEN 0x0A00 +#define SB_RAM3_DWLEN 0x0400 +#define QSB_CONF_REG_DWLEN 0x0100 +/* + * QSB Queue Scheduling and Shaping Definitions + */ +#define QSB_WFQ_NONUBR_MAX 0x3f00 +#define QSB_WFQ_UBR_BYPASS 0x3fff +#define QSB_TP_TS_MAX 65472 +#define QSB_TAUS_MAX 64512 +#define QSB_GCR_MIN 18 + + + +// OAM Definitions +#define OAM_RX_QUEUE_NUMBER 1 +#define OAM_TX_QUEUE_NUMBER_PER_PORT 0 +#define OAM_RX_DMA_CHANNEL_NUMBER OAM_RX_QUEUE_NUMBER +#define OAM_HTU_ENTRY_NUMBER 3 +#define OAM_F4_SEG_HTU_ENTRY 0 +#define OAM_F4_TOT_HTU_ENTRY 1 +#define OAM_F5_HTU_ENTRY 2 +#define OAM_F4_CELL_ID 0 +#define OAM_F5_CELL_ID 15 + +// ATM Port, QSB Queue, DMA RX/TX Channel Parameters +#define ATM_PORT_NUMBER 2 +#define MAX_QUEUE_NUMBER 16 +#define QSB_QUEUE_NUMBER_BASE 1 +#define MAX_QUEUE_NUMBER_PER_PORT (MAX_QUEUE_NUMBER - QSB_QUEUE_NUMBER_BASE) +#define MAX_CONNECTION_NUMBER MAX_QUEUE_NUMBER +#define MAX_RX_DMA_CHANNEL_NUMBER 8 +#define MAX_TX_DMA_CHANNEL_NUMBER 16 +#define DMA_ALIGNMENT 4 + +#define DEFAULT_RX_HUNT_BITTH 4 + +/* + * FPI Configuration Bus Register and Memory Address Mapping + */ +#define DANUBE_PPE (KSEG1 + 0x1E180000) +#define PP32_DEBUG_REG_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x0000) << 2))) +#define PPM_INT_REG_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x0030) << 2))) +#define PP32_INTERNAL_RES_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x0040) << 2))) +#define PPE_CLOCK_CONTROL_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x0100) << 2))) +#define CDM_CODE_MEMORY_RAM0_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x1000) << 2))) +#define CDM_CODE_MEMORY_RAM1_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x2000) << 2))) +#define PPE_REG_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x4000) << 2))) +#define PP32_DATA_MEMORY_RAM1_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x5000) << 2))) +#define PPM_INT_UNIT_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x6000) << 2))) +#define PPM_TIMER0_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x6100) << 2))) +#define PPM_TASK_IND_REG_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x6200) << 2))) +#define PPS_BRK_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x6300) << 2))) +#define PPM_TIMER1_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x6400) << 2))) +#define SB_RAM0_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x8000) << 2))) +#define SB_RAM1_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x8400) << 2))) +#define SB_RAM2_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x8C00) << 2))) +#define SB_RAM3_ADDR(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0x9600) << 2))) +#define QSB_CONF_REG(x) ((volatile u32*)(DANUBE_PPE + (((x) + 0xC000) << 2))) + +/* + * Host-PPE Communication Data Address Mapping + */ +#define CFG_WRX_HTUTS PPM_INT_UNIT_ADDR(0x2400) /* WAN RX HTU Table Size, must be configured before enable PPE firmware. */ +#define CFG_WRX_QNUM PPM_INT_UNIT_ADDR(0x2401) /* WAN RX Queue Number */ +#define CFG_WRX_DCHNUM PPM_INT_UNIT_ADDR(0x2402) /* WAN RX DMA Channel Number, no more than 8, must be configured before enable PPE firmware. */ +#define CFG_WTX_DCHNUM PPM_INT_UNIT_ADDR(0x2403) /* WAN TX DMA Channel Number, no more than 16, must be configured before enable PPE firmware. */ +#define CFG_WRDES_DELAY PPM_INT_UNIT_ADDR(0x2404) /* WAN Descriptor Write Delay, must be configured before enable PPE firmware. */ +#define WRX_DMACH_ON PPM_INT_UNIT_ADDR(0x2405) /* WAN RX DMA Channel Enable, must be configured before enable PPE firmware. */ +#define WTX_DMACH_ON PPM_INT_UNIT_ADDR(0x2406) /* WAN TX DMA Channel Enable, must be configured before enable PPE firmware. */ +#define WRX_HUNT_BITTH PPM_INT_UNIT_ADDR(0x2407) /* WAN RX HUNT Threshold, must be between 2 to 8. */ +#define WRX_QUEUE_CONFIG(i) ((struct wrx_queue_config*)PPM_INT_UNIT_ADDR(0x2500 + (i) * 20)) +#define WRX_DMA_CHANNEL_CONFIG(i) ((struct wrx_dma_channel_config*)PPM_INT_UNIT_ADDR(0x2640 + (i) * 7)) +#define WTX_PORT_CONFIG(i) ((struct wtx_port_config*)PPM_INT_UNIT_ADDR(0x2440 + (i))) +#define WTX_QUEUE_CONFIG(i) ((struct wtx_queue_config*)PPM_INT_UNIT_ADDR(0x2710 + (i) * 27)) +#define WTX_DMA_CHANNEL_CONFIG(i) ((struct wtx_dma_channel_config*)PPM_INT_UNIT_ADDR(0x2711 + (i) * 27)) +#define WAN_MIB_TABLE ((struct wan_mib_table*)PPM_INT_UNIT_ADDR(0x2410)) +#define HTU_ENTRY(i) ((struct htu_entry*)PPM_INT_UNIT_ADDR(0x2000 + (i))) +#define HTU_MASK(i) ((struct htu_mask*)PPM_INT_UNIT_ADDR(0x2020 + (i))) +#define HTU_RESULT(i) ((struct htu_result*)PPM_INT_UNIT_ADDR(0x2040 + (i))) + +// DREG Idle Counters +#define DREG_AT_CELL0 PPE_REG_ADDR(0x0D24) +#define DREG_AT_CELL1 PPE_REG_ADDR(0x0D25) +#define DREG_AT_IDLE_CNT0 PPE_REG_ADDR(0x0D26) +#define DREG_AT_IDLE_CNT1 PPE_REG_ADDR(0x0D27) +#define DREG_AR_CELL0 PPE_REG_ADDR(0x0D68) +#define DREG_AR_CELL1 PPE_REG_ADDR(0x0D69) +#define DREG_AR_IDLE_CNT0 PPE_REG_ADDR(0x0D6A) +#define DREG_AR_IDLE_CNT1 PPE_REG_ADDR(0x0D6B) +#define DREG_AR_AIIDLE_CNT0 PPE_REG_ADDR(0x0D6C) +#define DREG_AR_AIIDLE_CNT1 PPE_REG_ADDR(0x0D6D) +#define DREG_AR_BE_CNT0 PPE_REG_ADDR(0x0D6E) +#define DREG_AR_BE_CNT1 PPE_REG_ADDR(0x0D6F) + + +/* + * 64-bit Data Type + */ +typedef struct { + unsigned int h: 32; + unsigned int l: 32; +} ppe_u64_t; + +/* + * PPE ATM Cell Header + */ +#if defined(__BIG_ENDIAN) + struct uni_cell_header { + unsigned int gfc :4; + unsigned int vpi :8; + unsigned int vci :16; + unsigned int pti :3; + unsigned int clp :1; + }; +#else + struct uni_cell_header { + unsigned int clp :1; + unsigned int pti :3; + unsigned int vci :16; + unsigned int vpi :8; + unsigned int gfc :4; + }; +#endif // defined(__BIG_ENDIAN) + +/* + * Inband Header and Trailer + */ +#if defined(__BIG_ENDIAN) + struct rx_inband_trailer { + /* 0 - 3h */ + unsigned int uu :8; + unsigned int cpi :8; + unsigned int stw_res1:4; + unsigned int stw_clp :1; + unsigned int stw_ec :1; + unsigned int stw_uu :1; + unsigned int stw_cpi :1; + unsigned int stw_ovz :1; + unsigned int stw_mfl :1; + unsigned int stw_usz :1; + unsigned int stw_crc :1; + unsigned int stw_il :1; + unsigned int stw_ra :1; + unsigned int stw_res2:2; + /* 4 - 7h */ + unsigned int gfc :4; + unsigned int vpi :8; + unsigned int vci :16; + unsigned int pti :3; + unsigned int clp :1; + }; + + struct tx_inband_header { + /* 0 - 3h */ + unsigned int gfc :4; + unsigned int vpi :8; + unsigned int vci :16; + unsigned int pti :3; + unsigned int clp :1; + /* 4 - 7h */ + unsigned int uu :8; + unsigned int cpi :8; + unsigned int pad :8; + unsigned int res1 :8; + }; +#else + struct rx_inband_trailer { + /* 0 - 3h */ + unsigned int stw_res2:2; + unsigned int stw_ra :1; + unsigned int stw_il :1; + unsigned int stw_crc :1; + unsigned int stw_usz :1; + unsigned int stw_mfl :1; + unsigned int stw_ovz :1; + unsigned int stw_cpi :1; + unsigned int stw_uu :1; + unsigned int stw_ec :1; + unsigned int stw_clp :1; + unsigned int stw_res1:4; + unsigned int cpi :8; + unsigned int uu :8; + /* 4 - 7h */ + unsigned int clp :1; + unsigned int pti :3; + unsigned int vci :16; + unsigned int vpi :8; + unsigned int gfc :4; + }; + + struct tx_inband_header { + /* 0 - 3h */ + unsigned int clp :1; + unsigned int pti :3; + unsigned int vci :16; + unsigned int vpi :8; + unsigned int gfc :4; + /* 4 - 7h */ + unsigned int res1 :8; + unsigned int pad :8; + unsigned int cpi :8; + unsigned int uu :8; + }; +#endif // defined(__BIG_ENDIAN) + +struct wan_mib_table { + unsigned int res1; + unsigned int wrx_drophtu_cell; + unsigned int wrx_dropdes_pdu; + unsigned int wrx_correct_pdu; + unsigned int wrx_err_pdu; + unsigned int wrx_dropdes_cell; + unsigned int wrx_correct_cell; + unsigned int wrx_err_cell; + unsigned int wrx_total_byte; + unsigned int wtx_total_pdu; + unsigned int wtx_total_cell; + unsigned int wtx_total_byte; +}; + +/* + * Internal Structure of Device + */ +struct port { + int connection_base; /* first connection ID (RX/TX queue ID) */ + unsigned int max_connections; /* maximum connection number */ + unsigned int connection_table; /* connection opened status, every bit */ + unsigned int tx_max_cell_rate; /* maximum cell rate */ + unsigned int tx_current_cell_rate; /* currently used cell rate */ +#if !defined(ENABLE_RX_QOS) || !ENABLE_RX_QOS + int rx_dma_channel_base; /* first RX DMA channel ID */ + unsigned int rx_dma_channel_assigned;/* totally RX DMA channels used */ +#endif // !defined(ENABLE_RX_QOS) || !ENABLE_RX_QOS + int oam_tx_queue; /* first TX queue ID of OAM cell */ + struct atm_dev *dev; + +}; + +struct connection { + struct atm_vcc *vcc; /* opened VCC */ + struct timespec access_time; /* time when last F4/F5 user cell arrives */ + unsigned int aal5_vcc_crc_err; /* number of packets with CRC error */ + unsigned int aal5_vcc_oversize_sdu; /* number of packets with oversize error */ + int rx_dma_channel; /* RX DMA channel ID assigned */ + int port; /* to which port the connection belongs */ + unsigned int rx_pdu; + unsigned int rx_err_pdu; + unsigned int rx_sw_drop_pdu; + unsigned int tx_pdu; + unsigned int tx_err_pdu; + unsigned int tx_hw_drop_pdu; + unsigned int tx_sw_drop_pdu; +}; + +struct ppe_dev { + struct connection connection[MAX_CONNECTION_NUMBER]; + struct port port[ATM_PORT_NUMBER]; + + struct aal5 { + unsigned char padding_byte; /* padding byte pattern of AAL5 packet */ + unsigned int rx_max_packet_size; /* max AAL5 packet length */ + unsigned int rx_min_packet_size; /* min AAL5 packet length */ + unsigned int rx_buffer_size; /* max memory allocated for a AAL5 packet */ + unsigned int tx_max_packet_size; /* max AAL5 packet length */ + unsigned int tx_min_packet_size; /* min AAL5 packet length */ + unsigned int tx_buffer_size; /* max memory allocated for a AAL5 packet */ + unsigned int rx_drop_error_packet; /* 1: drop error packet, 0: ignore errors */ + } aal5; + + struct qsb { + unsigned int tau; /* cell delay variation due to concurrency */ + unsigned int tstepc; /* shceduler burst length */ + unsigned int sbl; /* time step */ + } qsb; + + struct dma { + unsigned int rx_descriptor_number; /* number of RX descriptors */ + unsigned int tx_descriptor_number; /* number of TX descriptors */ + unsigned int rx_clp1_desc_threshold; /* threshold to drop cells with CLP1 */ + unsigned int write_descriptor_delay; /* delay on descriptor write path */ + unsigned int rx_total_channel_used; /* total RX channel used */ + void *rx_descriptor_addr; /* base address of memory allocated for */ + struct rx_descriptor + *rx_descriptor_base; /* base address of RX descriptors */ + int rx_desc_read_pos[MAX_RX_DMA_CHANNEL_NUMBER]; /* first RX descriptor */ + /* to be read */ +// struct sk_buff **rx_skb_pointers; /* base address of RX sk_buff pointers */ + +#if defined(ENABLE_RX_QOS) && ENABLE_RX_QOS + long rx_weight[MAX_RX_DMA_CHANNEL_NUMBER]; /* RX schedule weight */ + long rx_default_weight[MAX_RX_DMA_CHANNEL_NUMBER]; /* default weight */ +#endif + + unsigned int tx_total_channel_used; /* total TX channel used */ + void *tx_descriptor_addr; /* base address of memory allocated for */ + /* TX descriptors */ + struct tx_descriptor + *tx_descriptor_base; /* base address of TX descriptors */ + int tx_desc_alloc_pos[MAX_TX_DMA_CHANNEL_NUMBER]; /* first TX descriptor */ + /* could be allocated */ +// int tx_desc_alloc_num[MAX_TX_DMA_CHANNEL_NUMBER]; /* number of allocated */ +// /* TX descriptors */ + int tx_desc_alloc_flag[MAX_TX_DMA_CHANNEL_NUMBER]; /* at least one TX */ + /* descriptor is alloc */ +// int tx_desc_send_pos[MAX_TX_DMA_CHANNEL_NUMBER]; /* first TX descriptor */ +// /* to be send */ + int tx_desc_release_pos[MAX_TX_DMA_CHANNEL_NUMBER]; /* first TX descriptor */ + /* to be released */ + struct sk_buff **tx_skb_pointers; /* base address of TX sk_buff pointers */ + } dma; + + struct mib { + ppe_u64_t wrx_total_byte; /* bit-64 extention of MIB table member */ + ppe_u64_t wtx_total_byte; /* bit-64 extention of MIB talbe member */ + + unsigned int wrx_pdu; /* successfully received AAL5 packet */ + unsigned int wrx_drop_pdu; /* AAL5 packet dropped by driver on RX */ + unsigned int wtx_err_pdu; /* error AAL5 packet */ + unsigned int wtx_drop_pdu; /* AAL5 packet dropped by driver on TX */ + } mib; + struct wan_mib_table prev_mib; + + int oam_rx_queue; /* RX queue ID of OAM cell */ + int oam_rx_dma_channel; /* RX DMA channel ID of OAM cell */ + int max_connections; /* total connections available */ + + struct semaphore sem; /* lock used by open/close function */ +}; + +/* + * Host-PPE Communication Data Structure + */ +#if defined(__BIG_ENDIAN) + struct wrx_queue_config { + /* 0h */ + unsigned int res2 :27; + unsigned int dmach :4; + unsigned int errdp :1; + /* 1h */ + unsigned int oversize :16; + unsigned int undersize :16; + /* 2h */ + unsigned int res1 :16; + unsigned int mfs :16; + /* 3h */ + unsigned int uumask :8; + unsigned int cpimask :8; + unsigned int uuexp :8; + unsigned int cpiexp :8; + }; + + struct wtx_port_config { + unsigned int res1 :27; + unsigned int qid :4; + unsigned int qsben :1; + }; + + struct wtx_queue_config { + unsigned int res1 :25; + unsigned int sbid :1; + unsigned int res2 :3; + unsigned int type :2; + unsigned int qsben :1; + }; + + struct wrx_dma_channel_config { + /* 0h */ + unsigned int res1 :1; + unsigned int mode :2; + unsigned int rlcfg :1; + unsigned int desba :28; + /* 1h */ + unsigned int chrl :16; + unsigned int clp1th :16; + /* 2h */ + unsigned int deslen :16; + unsigned int vlddes :16; + }; + + struct wtx_dma_channel_config { + /* 0h */ + unsigned int res2 :1; + unsigned int mode :2; + unsigned int res3 :1; + unsigned int desba :28; + /* 1h */ + unsigned int res1 :32; + /* 2h */ + unsigned int deslen :16; + unsigned int vlddes :16; + }; + + struct htu_entry { + unsigned int res1 :2; + unsigned int pid :2; + unsigned int vpi :8; + unsigned int vci :16; + unsigned int pti :3; + unsigned int vld :1; + }; + + struct htu_mask { + unsigned int set :2; + unsigned int pid_mask :2; + unsigned int vpi_mask :8; + unsigned int vci_mask :16; + unsigned int pti_mask :3; + unsigned int clear :1; + }; + + struct htu_result { + unsigned int res1 :12; + unsigned int cellid :4; + unsigned int res2 :5; + unsigned int type :1; + unsigned int ven :1; + unsigned int res3 :5; + unsigned int qid :4; + }; + + struct rx_descriptor { + /* 0 - 3h */ + unsigned int own :1; + unsigned int c :1; + unsigned int sop :1; + unsigned int eop :1; + unsigned int res1 :3; + unsigned int byteoff :2; + unsigned int res2 :2; + unsigned int id :4; + unsigned int err :1; + unsigned int datalen :16; + /* 4 - 7h */ + unsigned int res3 :4; + unsigned int dataptr :28; + }; + + struct tx_descriptor { + /* 0 - 3h */ + unsigned int own :1; + unsigned int c :1; + unsigned int sop :1; + unsigned int eop :1; + unsigned int byteoff :5; + unsigned int res1 :5; + unsigned int iscell :1; + unsigned int clp :1; + unsigned int datalen :16; + /* 4 - 7h */ + unsigned int res2 :4; + unsigned int dataptr :28; + }; +#else + struct wrx_queue_config { + /* 0h */ + unsigned int errdp :1; + unsigned int dmach :4; + unsigned int res2 :27; + /* 1h */ + unsigned int undersize :16; + unsigned int oversize :16; + /* 2h */ + unsigned int mfs :16; + unsigned int res1 :16; + /* 3h */ + unsigned int cpiexp :8; + unsigned int uuexp :8; + unsigned int cpimask :8; + unsigned int uumask :8; + }; + + struct wtx_port_config { + unsigned int qsben :1; + unsigned int qid :4; + unsigned int res1 :27; + }; + + struct wtx_queue_config { + unsigned int qsben :1; + unsigned int type :2; + unsigned int res2 :3; + unsigned int sbid :1; + unsigned int res1 :25; + }; + + struct wrx_dma_channel_config + { + /* 0h */ + unsigned int desba :28; + unsigned int rlcfg :1; + unsigned int mode :2; + unsigned int res1 :1; + /* 1h */ + unsigned int clp1th :16; + unsigned int chrl :16; + /* 2h */ + unsigned int vlddes :16; + unsigned int deslen :16; + }; + + struct wtx_dma_channel_config { + /* 0h */ + unsigned int desba :28; + unsigned int res3 :1; + unsigned int mode :2; + unsigned int res2 :1; + /* 1h */ + unsigned int res1 :32; + /* 2h */ + unsigned int vlddes :16; + unsigned int deslen :16; + }; + + struct rx_descriptor { + /* 4 - 7h */ + unsigned int dataptr :28; + unsigned int res3 :4; + /* 0 - 3h */ + unsigned int datalen :16; + unsigned int err :1; + unsigned int id :4; + unsigned int res2 :2; + unsigned int byteoff :2; + unsigned int res1 :3; + unsigned int eop :1; + unsigned int sop :1; + unsigned int c :1; + unsigned int own :1; + }; + + struct tx_descriptor { + /* 4 - 7h */ + unsigned int dataptr :28; + unsigned int res2 :4; + /* 0 - 3h */ + unsigned int datalen :16; + unsigned int clp :1; + unsigned int iscell :1; + unsigned int res1 :5; + unsigned int byteoff :5; + unsigned int eop :1; + unsigned int sop :1; + unsigned int c :1; + unsigned int own :1; + }; +#endif // defined(__BIG_ENDIAN) + +/* + * QSB Queue Parameter Table Entry and Queue VBR Parameter Table Entry + */ +#if defined(__BIG_ENDIAN) + union qsb_queue_parameter_table { + struct { + unsigned int res1 :1; + unsigned int vbr :1; + unsigned int wfqf :14; + unsigned int tp :16; + } bit; + unsigned int dword; + }; + + union qsb_queue_vbr_parameter_table { + struct { + unsigned int taus :16; + unsigned int ts :16; + } bit; + unsigned int dword; + }; +#else + union qsb_queue_parameter_table { + struct { + unsigned int tp :16; + unsigned int wfqf :14; + unsigned int vbr :1; + unsigned int res1 :1; + } bit; + unsigned int dword; + }; + + union qsb_queue_vbr_parameter_table { + struct { + unsigned int ts :16; + unsigned int taus :16; + } bit; + unsigned int dword; + }; +#endif // defined(__BIG_ENDIAN) + + +typedef enum +{ + IAD_ATM_CBR = 6, /* IAD_ATM_PRI_HIGH, */ + IAD_ATM_VBR_RT = 4, /* IAD_ATM_PRI_MED_HIGH, VBR, Real-Time */ + IAD_ATM_VBR_NRT = 2, /* IAD_ATM_PRI_MED_LOW, VBR, Non-Real-Time */ + IAD_ATM_UBR = 0, /* IAD_ATM_PRI_LOW */ +} iad_atmServiceCategory; + +typedef unsigned int iad_atmDiffServCategory; + +typedef struct +{ + int cellRate; + int round; /* IAD_ATM_RATE_CEILING, IAD_ATM_RATE_FLOOR */ +} iad_atmCellRateDesc; + +typedef struct +{ + unsigned int phyID; /* IAD_ATM_PHY0, IAD_ATM_PHY1 */ + unsigned int txQHnd; /* Tx HW Q */ + union _pri + { + int priority; /* TS Q: 4 priorities: IAD_ATM_PRI_HIGH, IAD_ATM_PRI_MED_HIGH, IAD_ATM_PRI_MED_LOW, IAD_ATM_PRI_LOW + non-TS Q: 8 priorities: IAD_ATM_PRI_LEVEL_7, IAD_ATM_PRI_LEVEL_6,..., IAD_ATM_PRI_LEVEL_0 */ + iad_atmServiceCategory qosClass; /* IAD_ATM_CBR, IAD_ATM_VBR_RT, IAD_ATM_VBR_NRT, IAD_ATM_UBR */ + iad_atmDiffServCategory diffServClass; /* IP_QOS */ + } srvCat; /* service category */ + iad_atmCellRateDesc pcr; /* Peak Cell Rate */ + iad_atmCellRateDesc scr; /* Sustained Cell Rate. */ + iad_atmCellRateDesc mcr; /* Minimum Cell Rate, not used */ + int mbs; /* maximum bursting size in cells */ + int isPrioritize; /* TRUE: This flow is of the higher priority than the flows of the same QOS category.(Use MCR to boost priority) */ +} iad_atmTrfPar; /* Tx Traffic Parameters */ + +typedef struct +{ + unsigned int txGrpId; + unsigned int flowId; + iad_atmTrfPar trfPar; +} Atm_Ictl_Flow_Set; + +typedef struct +{ + unsigned int txGrpId; + unsigned int vpi; + unsigned int vci; + + unsigned int encaps; + unsigned int proto; + +} Atm_Ictl_Open_Vcc; + +typedef struct +{ + struct atm_vcc vcc; + unsigned int valid; + unsigned int on; + unsigned int vccIndex; /* 0~7 */ + unsigned int itf; + struct net_device_stats stats; +} Atm_Priv; + + +extern struct ppe_dev ppe_dev; + + +int pp32_start(void); +void pp32_stop(void); +void init_rx_tables(void); +void init_tx_tables(void); +struct sk_buff* alloc_skb_rx(void); +struct sk_buff* alloc_skb_tx(unsigned int); +void resize_skb_rx(struct sk_buff *, unsigned int, int); +struct sk_buff* atm_alloc_tx(struct atm_vcc *, unsigned int); +void atm_free_tx_skb_vcc(struct sk_buff *); +int alloc_tx_connection(int); +int ppe_open(struct atm_vcc *vcc); +void ppe_close(struct atm_vcc *vcc); +int ppe_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg); +int ppe_send(struct atm_vcc *vcc, struct sk_buff *skb); +int ppe_send_oam(struct atm_vcc *vcc, void *cell, int flags); +int ppe_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags); +irqreturn_t mailbox_irq_handler(int, void *); +int find_vcc(struct atm_vcc *vcc); +int find_vpi(unsigned int vpi); +int find_vpivci(unsigned int vpi, unsigned int vci); +void mailbox_signal(unsigned int channel, int is_tx); + diff --git a/package/ifxmips-atm/src/core.c b/package/ifxmips-atm/src/core.c new file mode 100644 index 0000000000..95b05f3dbd --- /dev/null +++ b/package/ifxmips-atm/src/core.c @@ -0,0 +1,800 @@ +#include <asm/mach-ifxmips/cgu.h> +#include <linux/module.h> +#include <linux/atmdev.h> +#include <linux/irq.h> + +#include "common.h" +#include "proc.h" + +// our main struct +struct ppe_dev ppe_dev; + +static int port_max_connection[2] = {7, 7}; /* Maximum number of connections for ports (0-14) */ +static int port_cell_rate_up[2] = {3200, 3200}; /* Maximum TX cell rate for ports */ +static int qsb_tau = 1; +static int qsb_srvm = 0x0f; +static int qsb_tstep = 4; +static int write_descriptor_delay = 0x20; +static int aal5_fill_pattern = 0x007E; +static int aal5r_max_packet_size = 0x0700; +static int aal5r_min_packet_size = 0x0000; +static int aal5s_max_packet_size = 0x0700; +static int aal5s_min_packet_size = 0x0000; +static int aal5r_drop_error_packet = 1; +static int dma_rx_descriptor_length = 48; +static int dma_tx_descriptor_length = 64; +static int dma_rx_clp1_descriptor_threshold = 38; + +//module_param(port_max_connection, "2-2i"); +//module_param(port_cell_rate_up, "2-2i"); +module_param(qsb_tau, int, 0); +module_param(qsb_srvm, int, 0); +module_param(qsb_tstep, int, 0); +module_param(write_descriptor_delay, int, 0); +module_param(aal5_fill_pattern, int, 0); +module_param(aal5r_max_packet_size, int, 0); +module_param(aal5r_min_packet_size, int, 0); +module_param(aal5s_max_packet_size, int, 0); +module_param(aal5s_min_packet_size, int, 0); +module_param(aal5r_drop_error_packet, int, 0); +module_param(dma_rx_descriptor_length, int, 0); +module_param(dma_tx_descriptor_length, int, 0); +module_param(dma_rx_clp1_descriptor_threshold, int, 0); + +MODULE_PARM_DESC(port_cell_rate_up, "ATM port upstream rate in cells/s"); +MODULE_PARM_DESC(port_max_connection, "Maximum atm connection for port (0-1)"); +MODULE_PARM_DESC(qsb_tau, "Cell delay variation. Value must be > 0"); +MODULE_PARM_DESC(qsb_srvm, "Maximum burst size"); +MODULE_PARM_DESC(qsb_tstep, "n*32 cycles per sbs cycles n=1,2,4"); +MODULE_PARM_DESC(write_descriptor_delay, "PPE core clock cycles between descriptor write and effectiveness in external RAM"); +MODULE_PARM_DESC(a5_fill_pattern, "Filling pattern (PAD) for AAL5 frames"); +MODULE_PARM_DESC(aal5r_max_packet_size, "Max packet size in byte for downstream AAL5 frames"); +MODULE_PARM_DESC(aal5r_min_packet_size, "Min packet size in byte for downstream AAL5 frames"); +MODULE_PARM_DESC(aal5s_max_packet_size, "Max packet size in byte for upstream AAL5 frames"); +MODULE_PARM_DESC(aal5s_min_packet_size, "Min packet size in byte for upstream AAL5 frames"); +MODULE_PARM_DESC(aal5r_drop_error_packet, "Non-zero value to drop error packet for downstream"); +MODULE_PARM_DESC(dma_rx_descriptor_length, "Number of descriptor assigned to DMA RX channel (>16)"); +MODULE_PARM_DESC(dma_tx_descriptor_length, "Number of descriptor assigned to DMA TX channel (>16)"); +MODULE_PARM_DESC(dma_rx_clp1_descriptor_threshold, "Descriptor threshold for cells with cell loss priority 1"); + +void init_rx_tables(void) +{ + int i, j; + struct wrx_queue_config wrx_queue_config = {0}; + struct wrx_dma_channel_config wrx_dma_channel_config = {0}; + struct htu_entry htu_entry = {0}; + struct htu_result htu_result = {0}; + + struct htu_mask htu_mask = { set: 0x03, + pid_mask: 0x00, + vpi_mask: 0x00, + vci_mask: 0x00, + pti_mask: 0x00, + clear: 0x00}; + + /* + * General Registers + */ + *CFG_WRX_HTUTS = ppe_dev.max_connections + OAM_HTU_ENTRY_NUMBER; + *CFG_WRX_QNUM = ppe_dev.max_connections + OAM_RX_QUEUE_NUMBER + QSB_QUEUE_NUMBER_BASE; + *CFG_WRX_DCHNUM = ppe_dev.dma.rx_total_channel_used; + *WRX_DMACH_ON = (1 << ppe_dev.dma.rx_total_channel_used) - 1; + *WRX_HUNT_BITTH = DEFAULT_RX_HUNT_BITTH; + + /* + * WRX Queue Configuration Table + */ + wrx_queue_config.uumask = 0; + wrx_queue_config.cpimask = 0; + wrx_queue_config.uuexp = 0; + wrx_queue_config.cpiexp = 0; + wrx_queue_config.mfs = ppe_dev.aal5.rx_max_packet_size; // rx_buffer_size + wrx_queue_config.oversize = ppe_dev.aal5.rx_max_packet_size; + wrx_queue_config.undersize = ppe_dev.aal5.rx_min_packet_size; + wrx_queue_config.errdp = ppe_dev.aal5.rx_drop_error_packet; + for ( i = 0; i < QSB_QUEUE_NUMBER_BASE; i++ ) + *WRX_QUEUE_CONFIG(i) = wrx_queue_config; + for ( j = 0; j < ppe_dev.max_connections; j++ ) + { +#if !defined(ENABLE_RX_QOS) || !ENABLE_RX_QOS + /* If RX QoS is disabled, the DMA channel must be fixed. */ + wrx_queue_config.dmach = ppe_dev.connection[i].rx_dma_channel; +#endif // !defined(ENABLE_RX_QOS) || !ENABLE_RX_QOS + *WRX_QUEUE_CONFIG(i++) = wrx_queue_config; + } + /* OAM RX Queue */ + for ( j = 0; j < OAM_RX_DMA_CHANNEL_NUMBER; j++ ) + { +#if defined(ENABLE_RX_QOS) && ENABLE_RX_QOS + wrx_queue_config.dmach = RX_DMA_CH_OAM; +#else + wrx_queue_config.dmach = ppe_dev.oam_rx_dma_channel + j; +#endif // defined(ENABLE_RX_QOS) && ENABLE_RX_QOS + *WRX_QUEUE_CONFIG(i++) = wrx_queue_config; + } + + wrx_dma_channel_config.deslen = ppe_dev.dma.rx_descriptor_number; + wrx_dma_channel_config.chrl = 0; + wrx_dma_channel_config.clp1th = ppe_dev.dma.rx_clp1_desc_threshold; + wrx_dma_channel_config.mode = WRX_DMA_CHANNEL_COUNTER_MODE; + wrx_dma_channel_config.rlcfg = WRX_DMA_BUF_LEN_PER_DESCRIPTOR; + for ( i = 0; i < ppe_dev.dma.rx_total_channel_used; i++ ) + { + wrx_dma_channel_config.desba = (((u32)ppe_dev.dma.rx_descriptor_base >> 2) & 0x0FFFFFFF) + ppe_dev.dma.rx_descriptor_number * i * (sizeof(struct rx_descriptor) >> 2); + *WRX_DMA_CHANNEL_CONFIG(i) = wrx_dma_channel_config; + } + + /* + * HTU Tables + */ + for ( i = 0; i < ppe_dev.max_connections; i++ ) + { + htu_result.qid = (unsigned int)i; + + *HTU_ENTRY(i + OAM_HTU_ENTRY_NUMBER) = htu_entry; + *HTU_MASK(i + OAM_HTU_ENTRY_NUMBER) = htu_mask; + *HTU_RESULT(i + OAM_HTU_ENTRY_NUMBER) = htu_result; + } + /* OAM HTU Entry */ + htu_entry.vci = 0x03; + htu_mask.pid_mask = 0x03; + htu_mask.vpi_mask = 0xFF; + htu_mask.vci_mask = 0x0000; + htu_mask.pti_mask = 0x07; + htu_result.cellid = ppe_dev.oam_rx_queue; + htu_result.type = 1; + htu_result.ven = 1; + htu_result.qid = ppe_dev.oam_rx_queue; + *HTU_RESULT(OAM_F4_SEG_HTU_ENTRY) = htu_result; + *HTU_MASK(OAM_F4_SEG_HTU_ENTRY) = htu_mask; + *HTU_ENTRY(OAM_F4_SEG_HTU_ENTRY) = htu_entry; + htu_entry.vci = 0x04; + htu_result.cellid = ppe_dev.oam_rx_queue; + htu_result.type = 1; + htu_result.ven = 1; + htu_result.qid = ppe_dev.oam_rx_queue; + *HTU_RESULT(OAM_F4_TOT_HTU_ENTRY) = htu_result; + *HTU_MASK(OAM_F4_TOT_HTU_ENTRY) = htu_mask; + *HTU_ENTRY(OAM_F4_TOT_HTU_ENTRY) = htu_entry; + htu_entry.vci = 0x00; + htu_entry.pti = 0x04; + htu_mask.vci_mask = 0xFFFF; + htu_mask.pti_mask = 0x01; + htu_result.cellid = ppe_dev.oam_rx_queue; + htu_result.type = 1; + htu_result.ven = 1; + htu_result.qid = ppe_dev.oam_rx_queue; + *HTU_RESULT(OAM_F5_HTU_ENTRY) = htu_result; + *HTU_MASK(OAM_F5_HTU_ENTRY) = htu_mask; + *HTU_ENTRY(OAM_F5_HTU_ENTRY) = htu_entry; +} + +void init_tx_tables(void) +{ + int i, j; + struct wtx_queue_config wtx_queue_config = {0}; + struct wtx_dma_channel_config wtx_dma_channel_config = {0}; + + struct wtx_port_config wtx_port_config = { res1: 0, + qid: 0, + qsben: 1}; + + /* + * General Registers + */ + *CFG_WTX_DCHNUM = ppe_dev.dma.tx_total_channel_used + QSB_QUEUE_NUMBER_BASE; + *WTX_DMACH_ON = ((1 << (ppe_dev.dma.tx_total_channel_used + QSB_QUEUE_NUMBER_BASE)) - 1) ^ ((1 << QSB_QUEUE_NUMBER_BASE) - 1); + *CFG_WRDES_DELAY = ppe_dev.dma.write_descriptor_delay; + + /* + * WTX Port Configuration Table + */ +#if !defined(DISABLE_QSB) || !DISABLE_QSB + for ( i = 0; i < ATM_PORT_NUMBER; i++ ) + *WTX_PORT_CONFIG(i) = wtx_port_config; +#else + wtx_port_config.qsben = 0; + for ( i = 0; i < ATM_PORT_NUMBER; i++ ) + { + wtx_port_config.qid = ppe_dev.port[i].connection_base; + *WTX_PORT_CONFIG(i) = wtx_port_config; + +printk("port %d: qid = %d, qsb disabled\n", i, wtx_port_config.qid); + } +#endif + + /* + * WTX Queue Configuration Table + */ + wtx_queue_config.res1 = 0; + wtx_queue_config.res2 = 0; +// wtx_queue_config.type = 0x03; + wtx_queue_config.type = 0x0; +#if !defined(DISABLE_QSB) || !DISABLE_QSB + wtx_queue_config.qsben = 1; +#else + wtx_queue_config.qsben = 0; +#endif + wtx_queue_config.sbid = 0; + for ( i = 0; i < QSB_QUEUE_NUMBER_BASE; i++ ) + *WTX_QUEUE_CONFIG(i) = wtx_queue_config; + for ( j = 0; j < ppe_dev.max_connections; j++ ) + { + wtx_queue_config.sbid = ppe_dev.connection[i].port & 0x01; /* assign QSB to TX queue */ + *WTX_QUEUE_CONFIG(i) = wtx_queue_config; + i++; + } + /* OAM TX Queue */ +// wtx_queue_config.type = 0x01; + wtx_queue_config.type = 0x00; + for ( i = 0; i < ATM_PORT_NUMBER; i++ ) + { + wtx_queue_config.sbid = i & 0x01; + for ( j = 0; j < OAM_TX_QUEUE_NUMBER_PER_PORT; j++ ) + *WTX_QUEUE_CONFIG(ppe_dev.port[i].oam_tx_queue + j) = wtx_queue_config; + } + + wtx_dma_channel_config.mode = WRX_DMA_CHANNEL_COUNTER_MODE; + wtx_dma_channel_config.deslen = 0; + wtx_dma_channel_config.desba = 0; + for ( i = 0; i < QSB_QUEUE_NUMBER_BASE; i++ ) + *WTX_DMA_CHANNEL_CONFIG(i) = wtx_dma_channel_config; + /* normal connection and OAM channel */ + wtx_dma_channel_config.deslen = ppe_dev.dma.tx_descriptor_number; + for ( j = 0; j < ppe_dev.dma.tx_total_channel_used; j++ ) + { + wtx_dma_channel_config.desba = (((u32)ppe_dev.dma.tx_descriptor_base >> 2) & 0x0FFFFFFF) + ppe_dev.dma.tx_descriptor_number * j * (sizeof(struct tx_descriptor) >> 2); + *WTX_DMA_CHANNEL_CONFIG(i++) = wtx_dma_channel_config; + } +} + +static inline void qsb_global_set(void) +{ + int i, j; + u32 qsb_clk = cgu_get_fpi_bus_clock(2); + u32 tmp1, tmp2, tmp3; + union qsb_queue_parameter_table qsb_queue_parameter_table = {{0}}; + union qsb_queue_vbr_parameter_table qsb_queue_vbr_parameter_table = {{0}}; + int qsb_qid; + + *QSB_ICDV = QSB_ICDV_TAU_SET(ppe_dev.qsb.tau); + *QSB_SBL = QSB_SBL_SBL_SET(ppe_dev.qsb.sbl); + *QSB_CFG = QSB_CFG_TSTEPC_SET(ppe_dev.qsb.tstepc >> 1); + + /* + * set SCT and SPT per port + */ + for ( i = 0; i < ATM_PORT_NUMBER; i++ ) + if ( ppe_dev.port[i].max_connections != 0 && ppe_dev.port[i].tx_max_cell_rate != 0 ) + { + tmp1 = ((qsb_clk * ppe_dev.qsb.tstepc) >> 1) / ppe_dev.port[i].tx_max_cell_rate; + tmp2 = tmp1 >> 6; /* integer value of Tsb */ + tmp3 = (tmp1 & ((1 << 6) - 1)) + 1; /* fractional part of Tsb */ + /* carry over to integer part (?) */ + if ( tmp3 == (1 << 6) ) + { + tmp3 = 0; + tmp2++; + } + if ( tmp2 == 0 ) + tmp2 = tmp3 = 1; + /* 1. set mask */ + /* 2. write value to data transfer register */ + /* 3. start the tranfer */ + /* SCT (FracRate) */ + *QSB_RTM = QSB_RTM_DM_SET(QSB_SET_SCT_MASK); + *QSB_RTD = QSB_RTD_TTV_SET(tmp3); + *QSB_RAMAC = QSB_RAMAC_RW_SET(QSB_RAMAC_RW_WRITE) | QSB_RAMAC_TSEL_SET(QSB_RAMAC_TSEL_SCT) | QSB_RAMAC_LH_SET(QSB_RAMAC_LH_LOW) | QSB_RAMAC_TESEL_SET(i & 0x01); + /* SPT (SBV + PN + IntRage) */ + *QSB_RTM = QSB_RTM_DM_SET(QSB_SET_SPT_MASK); + *QSB_RTD = QSB_RTD_TTV_SET(QSB_SPT_SBV_VALID | QSB_SPT_PN_SET(i & 0x01) | QSB_SPT_INTRATE_SET(tmp2)); + *QSB_RAMAC = QSB_RAMAC_RW_SET(QSB_RAMAC_RW_WRITE) | QSB_RAMAC_TSEL_SET(QSB_RAMAC_TSEL_SPT) | QSB_RAMAC_LH_SET(QSB_RAMAC_LH_LOW) | QSB_RAMAC_TESEL_SET(i & 0x01); + } + + /* + * set OAM TX queue + */ + for ( i = 0; i < ATM_PORT_NUMBER; i++ ) + if ( ppe_dev.port[i].max_connections != 0 ) + { + tmp1 = ((qsb_clk * ppe_dev.qsb.tstepc) >> 1) / ppe_dev.port[i].tx_max_cell_rate; + tmp2 = tmp1 >> 6; /* integer value of Tsb */ + tmp3 = (tmp1 & ((1 << 6) - 1)) + 1; /* fractional part of Tsb */ + /* carry over to integer part (?) */ + if ( tmp3 == (1 << 6) ) + { + tmp3 = 0; + tmp2++; + } + if ( tmp2 == 0 ) + tmp2 = tmp3 = 1; + /* 1. set mask */ + /* 2. write value to data transfer register */ + /* 3. start the tranfer */ + /* SCT (FracRate) */ + *QSB_RTM = QSB_RTM_DM_SET(QSB_SET_SCT_MASK); + *QSB_RTD = QSB_RTD_TTV_SET(tmp3); + *QSB_RAMAC = QSB_RAMAC_RW_SET(QSB_RAMAC_RW_WRITE) | QSB_RAMAC_TSEL_SET(QSB_RAMAC_TSEL_SCT) | QSB_RAMAC_LH_SET(QSB_RAMAC_LH_LOW) | QSB_RAMAC_TESEL_SET(i & 0x01); + + /* SPT (SBV + PN + IntRage) */ + *QSB_RTM = QSB_RTM_DM_SET(QSB_SET_SPT_MASK); + *QSB_RTD = QSB_RTD_TTV_SET(QSB_SPT_SBV_VALID | QSB_SPT_PN_SET(i & 0x01) | QSB_SPT_INTRATE_SET(tmp2)); + *QSB_RAMAC = QSB_RAMAC_RW_SET(QSB_RAMAC_RW_WRITE) | QSB_RAMAC_TSEL_SET(QSB_RAMAC_TSEL_SPT) | QSB_RAMAC_LH_SET(QSB_RAMAC_LH_LOW) | QSB_RAMAC_TESEL_SET(i & 0x01); + } + + /* + * * set OAM TX queue + * */ + for ( i = 0; i < ATM_PORT_NUMBER; i++ ) + if ( ppe_dev.port[i].max_connections != 0 ) + for ( j = 0; j < OAM_TX_QUEUE_NUMBER_PER_PORT; j++ ) + { + qsb_qid = ppe_dev.port[i].oam_tx_queue + j; + + /* disable PCR limiter */ + qsb_queue_parameter_table.bit.tp = 0; + /* set WFQ as real time queue */ + qsb_queue_parameter_table.bit.wfqf = 0; + /* disable leaky bucket shaper */ + qsb_queue_vbr_parameter_table.bit.taus = 0; + qsb_queue_vbr_parameter_table.bit.ts = 0; + + /* Queue Parameter Table (QPT) */ + *QSB_RTM = QSB_RTM_DM_SET(QSB_QPT_SET_MASK); + *QSB_RTD = QSB_RTD_TTV_SET(qsb_queue_parameter_table.dword); + *QSB_RAMAC = QSB_RAMAC_RW_SET(QSB_RAMAC_RW_WRITE) | QSB_RAMAC_TSEL_SET(QSB_RAMAC_TSEL_QPT) | QSB_RAMAC_LH_SET(QSB_RAMAC_LH_LOW) | QSB_RAMAC_TESEL_SET(qsb_qid); + /* Queue VBR Paramter Table (QVPT) */ + *QSB_RTM = QSB_RTM_DM_SET(QSB_QVPT_SET_MASK); + *QSB_RTD = QSB_RTD_TTV_SET(qsb_queue_vbr_parameter_table.dword); + *QSB_RAMAC = QSB_RAMAC_RW_SET(QSB_RAMAC_RW_WRITE) | QSB_RAMAC_TSEL_SET(QSB_RAMAC_TSEL_VBR) | QSB_RAMAC_LH_SET(QSB_RAMAC_LH_LOW) | QSB_RAMAC_TESEL_SET(qsb_qid); + } +} + +static inline void clear_ppe_dev(void) +{ + int i; + + for (i = 0; i < ppe_dev.dma.tx_total_channel_used; i++ ) + { + int conn = i + QSB_QUEUE_NUMBER_BASE; + int desc_base; + struct sk_buff *skb; + + while(ppe_dev.dma.tx_desc_release_pos[conn] != ppe_dev.dma.tx_desc_alloc_pos[conn]) + { + desc_base = ppe_dev.dma.tx_descriptor_number * (conn - QSB_QUEUE_NUMBER_BASE) + ppe_dev.dma.tx_desc_release_pos[conn]; + if(!ppe_dev.dma.tx_descriptor_base[desc_base].own) + { + skb = ppe_dev.dma.tx_skb_pointers[desc_base]; + atm_free_tx_skb_vcc(skb); + + // pretend PP32 hold owner bit, so that won't be released more than once, so allocation process don't check this bit + ppe_dev.dma.tx_descriptor_base[desc_base].own = 1; + } + if (++ppe_dev.dma.tx_desc_release_pos[conn] == ppe_dev.dma.tx_descriptor_number) + ppe_dev.dma.tx_desc_release_pos[conn] = 0; + } + } + + for (i = ppe_dev.dma.rx_total_channel_used * ppe_dev.dma.rx_descriptor_number - 1; i >= 0; i--) + dev_kfree_skb_any(*(struct sk_buff **)(((ppe_dev.dma.rx_descriptor_base[i].dataptr << 2) | KSEG0) - 4)); + + kfree(ppe_dev.dma.tx_skb_pointers); + kfree(ppe_dev.dma.tx_descriptor_addr); + kfree(ppe_dev.dma.rx_descriptor_addr); +} + +static inline int init_ppe_dev(void) +{ + int i, j; + int rx_desc, tx_desc; + int conn; + int oam_tx_queue; +#if !defined(ENABLE_RX_QOS) || !ENABLE_RX_QOS + int rx_dma_channel_base; + int rx_dma_channel_assigned; +#endif // !defined(ENABLE_RX_QOS) || !ENABLE_RX_QOS + + struct rx_descriptor rx_descriptor = { own: 1, + c: 0, + sop: 1, + eop: 1, + res1: 0, + byteoff:0, + res2: 0, + id: 0, + err: 0, + datalen:0, + res3: 0, + dataptr:0}; + + struct tx_descriptor tx_descriptor = { own: 1, // pretend it's hold by PP32 + c: 0, + sop: 1, + eop: 1, + byteoff:0, + res1: 0, + iscell: 0, + clp: 0, + datalen:0, + res2: 0, + dataptr:0}; + + memset(&ppe_dev, 0, sizeof(ppe_dev)); + + /* + * Setup AAL5 members, buffer size must be larger than max packet size plus overhead. + */ + ppe_dev.aal5.padding_byte = (u8)aal5_fill_pattern; + ppe_dev.aal5.rx_max_packet_size = (u32)aal5r_max_packet_size; + ppe_dev.aal5.rx_min_packet_size = (u32)aal5r_min_packet_size; + ppe_dev.aal5.rx_buffer_size = ((u32)(aal5r_max_packet_size > CELL_SIZE ? aal5r_max_packet_size + MAX_RX_FRAME_EXTRA_BYTES : CELL_SIZE + MAX_RX_FRAME_EXTRA_BYTES) + DMA_ALIGNMENT - 1) & ~(DMA_ALIGNMENT - 1); + ppe_dev.aal5.tx_max_packet_size = (u32)aal5s_max_packet_size; + ppe_dev.aal5.tx_min_packet_size = (u32)aal5s_min_packet_size; + ppe_dev.aal5.tx_buffer_size = ((u32)(aal5s_max_packet_size > CELL_SIZE ? aal5s_max_packet_size + MAX_TX_FRAME_EXTRA_BYTES : CELL_SIZE + MAX_TX_FRAME_EXTRA_BYTES) + DMA_ALIGNMENT - 1) & ~(DMA_ALIGNMENT - 1); + ppe_dev.aal5.rx_drop_error_packet = aal5r_drop_error_packet ? 1 : 0; + + /* + * Setup QSB members, please refer to Amazon spec 15.4 to get the value calculation formula. + */ + ppe_dev.qsb.tau = (u32)qsb_tau; + ppe_dev.qsb.tstepc = (u32)qsb_tstep; + ppe_dev.qsb.sbl = (u32)qsb_srvm; + + /* + * Setup port, connection, other members. + */ + conn = 0; + for ( i = 0; i < ATM_PORT_NUMBER; i++ ) + { + /* first connection ID of port */ + ppe_dev.port[i].connection_base = conn + QSB_QUEUE_NUMBER_BASE; + /* max number of connections of port */ + ppe_dev.port[i].max_connections = (u32)port_max_connection[i]; + /* max cell rate the port has */ + ppe_dev.port[i].tx_max_cell_rate = (u32)port_cell_rate_up[i]; + + /* link connection ID to port ID */ + for ( j = port_max_connection[i] - 1; j >= 0; j-- ) + ppe_dev.connection[conn++ + QSB_QUEUE_NUMBER_BASE].port = i; + } + /* total connection numbers of all ports */ + ppe_dev.max_connections = conn; + /* OAM RX queue ID, which is the first available connection ID after */ + /* connections assigned to ports. */ + ppe_dev.oam_rx_queue = conn + QSB_QUEUE_NUMBER_BASE; + +#if defined(ENABLE_RX_QOS) && ENABLE_RX_QOS + oam_tx_queue = conn; + for ( i = 0; i < ATM_PORT_NUMBER; i++ ) + if ( port_max_connection[i] != 0 ) + { + ppe_dev.port[i].oam_tx_queue = oam_tx_queue + QSB_QUEUE_NUMBER_BASE; + + for ( j = 0; j < OAM_TX_QUEUE_NUMBER_PER_PORT; j++ ) + /* Since connection ID is one to one mapped to RX/TX queue ID, the connection */ + /* structure must be reserved for OAM RX/TX queues, and member "port" is set */ + /* according to port to which OAM TX queue is connected. */ + ppe_dev.connection[oam_tx_queue++ + QSB_QUEUE_NUMBER_BASE].port = i; + } + /* DMA RX channel assigned to OAM RX queue */ + ppe_dev.oam_rx_dma_channel = RX_DMA_CH_OAM; + /* DMA RX channel will be assigned dynamically when VCC is open. */ +#else // defined(ENABLE_RX_QOS) && ENABLE_RX_QOS + rx_dma_channel_base = 0; + oam_tx_queue = conn; + for ( i = 0; i < ATM_PORT_NUMBER; i++ ) + if ( port_max_connection[i] != 0 ) + { + /* Calculate the number of DMA RX channels could be assigned to port. */ + rx_dma_channel_assigned = i == ATM_PORT_NUMBER - 1 + ? (MAX_RX_DMA_CHANNEL_NUMBER - OAM_RX_DMA_CHANNEL_NUMBER) - rx_dma_channel_base + : (ppe_dev.port[i].max_connections * (MAX_RX_DMA_CHANNEL_NUMBER - OAM_RX_DMA_CHANNEL_NUMBER) + ppe_dev.max_connections / 2) / ppe_dev.max_connections; + /* Amend the number, which could be zero. */ + if ( rx_dma_channel_assigned == 0 ) + rx_dma_channel_assigned = 1; + /* Calculate the first DMA RX channel ID could be assigned to port. */ + if ( rx_dma_channel_base + rx_dma_channel_assigned > MAX_RX_DMA_CHANNEL_NUMBER - OAM_RX_DMA_CHANNEL_NUMBER ) + rx_dma_channel_base = MAX_RX_DMA_CHANNEL_NUMBER - OAM_RX_DMA_CHANNEL_NUMBER - rx_dma_channel_assigned; + + /* first DMA RX channel ID */ + ppe_dev.port[i].rx_dma_channel_base = rx_dma_channel_base; + /* number of DMA RX channels assigned to this port */ + ppe_dev.port[i].rx_dma_channel_assigned = rx_dma_channel_assigned; + /* OAM TX queue ID, which must be assigned after connections assigned to ports */ + ppe_dev.port[i].oam_tx_queue = oam_tx_queue + QSB_QUEUE_NUMBER_BASE; + + rx_dma_channel_base += rx_dma_channel_assigned; + + for ( j = 0; j < OAM_TX_QUEUE_NUMBER_PER_PORT; j++ ) + /* Since connection ID is one to one mapped to RX/TX queue ID, the connection */ + /* structure must be reserved for OAM RX/TX queues, and member "port" is set */ + /* according to port to which OAM TX queue is connected. */ + ppe_dev.connection[oam_tx_queue++ + QSB_QUEUE_NUMBER_BASE].port = i; + } + /* DMA RX channel assigned to OAM RX queue */ + ppe_dev.oam_rx_dma_channel = rx_dma_channel_base; + + for ( i = 0; i < ATM_PORT_NUMBER; i++ ) + for ( j = 0; j < port_max_connection[i]; j++ ) + /* Assign DMA RX channel to RX queues. One channel could be assigned to more than one queue. */ + ppe_dev.connection[ppe_dev.port[i].connection_base + j].rx_dma_channel = ppe_dev.port[i].rx_dma_channel_base + j % ppe_dev.port[i].rx_dma_channel_assigned; +#endif // defined(ENABLE_RX_QOS) && ENABLE_RX_QOS + + /* initialize semaphore used by open and close */ + sema_init(&ppe_dev.sem, 1); + /* descriptor number of RX DMA channel */ + ppe_dev.dma.rx_descriptor_number = dma_rx_descriptor_length; + /* descriptor number of TX DMA channel */ + ppe_dev.dma.tx_descriptor_number = dma_tx_descriptor_length; + /* If used descriptors are more than this value, cell with CLP1 is dropped. */ + ppe_dev.dma.rx_clp1_desc_threshold = dma_rx_clp1_descriptor_threshold; + + /* delay on descriptor write path */ + ppe_dev.dma.write_descriptor_delay = write_descriptor_delay; + + /* total DMA RX channel used */ +#if defined(ENABLE_RX_QOS) && ENABLE_RX_QOS + ppe_dev.dma.rx_total_channel_used = RX_DMA_CH_TOTAL; +#else + ppe_dev.dma.rx_total_channel_used = rx_dma_channel_base + OAM_RX_DMA_CHANNEL_NUMBER; +#endif // defined(ENABLE_RX_QOS) && ENABLE_RX_QOS + /* total DMA TX channel used (exclude channel reserved by QSB) */ + ppe_dev.dma.tx_total_channel_used = oam_tx_queue; + + /* allocate memory for RX descriptors */ + ppe_dev.dma.rx_descriptor_addr = kmalloc(ppe_dev.dma.rx_total_channel_used * ppe_dev.dma.rx_descriptor_number * sizeof(struct rx_descriptor) + 4, GFP_KERNEL | GFP_DMA); + if ( !ppe_dev.dma.rx_descriptor_addr ) + goto RX_DESCRIPTOR_BASE_ALLOCATE_FAIL; + /* do alignment (DWORD) */ + ppe_dev.dma.rx_descriptor_base = (struct rx_descriptor *)(((u32)ppe_dev.dma.rx_descriptor_addr + 0x03) & ~0x03); + ppe_dev.dma.rx_descriptor_base = (struct rx_descriptor *)((u32)ppe_dev.dma.rx_descriptor_base | KSEG1); // no cache + + /* allocate memory for TX descriptors */ + ppe_dev.dma.tx_descriptor_addr = kmalloc(ppe_dev.dma.tx_total_channel_used * ppe_dev.dma.tx_descriptor_number * sizeof(struct tx_descriptor) + 4, GFP_KERNEL | GFP_DMA); + if ( !ppe_dev.dma.tx_descriptor_addr ) + goto TX_DESCRIPTOR_BASE_ALLOCATE_FAIL; + /* do alignment (DWORD) */ + ppe_dev.dma.tx_descriptor_base = (struct tx_descriptor *)(((u32)ppe_dev.dma.tx_descriptor_addr + 0x03) & ~0x03); + ppe_dev.dma.tx_descriptor_base = (struct tx_descriptor *)((u32)ppe_dev.dma.tx_descriptor_base | KSEG1); // no cache + /* allocate pointers to TX sk_buff */ + ppe_dev.dma.tx_skb_pointers = kmalloc(ppe_dev.dma.tx_total_channel_used * ppe_dev.dma.tx_descriptor_number * sizeof(struct sk_buff *), GFP_KERNEL); + if ( !ppe_dev.dma.tx_skb_pointers ) + goto TX_SKB_POINTER_ALLOCATE_FAIL; + memset(ppe_dev.dma.tx_skb_pointers, 0, ppe_dev.dma.tx_total_channel_used * ppe_dev.dma.tx_descriptor_number * sizeof(struct sk_buff *)); + + /* Allocate RX sk_buff and fill up RX descriptors. */ + rx_descriptor.datalen = ppe_dev.aal5.rx_buffer_size; + for ( rx_desc = ppe_dev.dma.rx_total_channel_used * ppe_dev.dma.rx_descriptor_number - 1; rx_desc >= 0; rx_desc-- ) + { + struct sk_buff *skb; + skb = alloc_skb_rx(); + if ( skb == NULL ) + panic("sk buffer is used up\n"); + rx_descriptor.dataptr = (u32)skb->data >> 2; + ppe_dev.dma.rx_descriptor_base[rx_desc] = rx_descriptor; + + } + + /* Fill up TX descriptors. */ + tx_descriptor.datalen = ppe_dev.aal5.tx_buffer_size; + for ( tx_desc = ppe_dev.dma.tx_total_channel_used * ppe_dev.dma.tx_descriptor_number - 1; tx_desc >= 0; tx_desc-- ) + ppe_dev.dma.tx_descriptor_base[tx_desc] = tx_descriptor; + + return 0; + +TX_SKB_POINTER_ALLOCATE_FAIL: + kfree(ppe_dev.dma.tx_descriptor_addr); +TX_DESCRIPTOR_BASE_ALLOCATE_FAIL: + kfree(ppe_dev.dma.rx_descriptor_addr); +RX_DESCRIPTOR_BASE_ALLOCATE_FAIL: + return -ENOMEM; +} + + +static inline void clear_share_buffer(void) +{ + volatile u32 *p = SB_RAM0_ADDR(0); + unsigned int i; + + /* write all zeros only */ + for ( i = 0; i < SB_RAM0_DWLEN + SB_RAM1_DWLEN + SB_RAM2_DWLEN + SB_RAM3_DWLEN; i++ ) + *p++ = 0; +} + + +static inline void check_parameters(void) +{ + int i; + int enabled_port_number; + int unassigned_queue_number; + int assigned_queue_number; + + enabled_port_number = 0; + for ( i = 0; i < ATM_PORT_NUMBER; i++ ) + if ( port_max_connection[i] < 1 ) + port_max_connection[i] = 0; + else + enabled_port_number++; + /* If the max connection number of a port is not 0, the port is enabled */ + /* and at lease two connection ID must be reserved for this port. One of */ + /* them is used as OAM TX path. */ + unassigned_queue_number = MAX_QUEUE_NUMBER - QSB_QUEUE_NUMBER_BASE; + for ( i = 0; i < ATM_PORT_NUMBER; i++ ) + if ( port_max_connection[i] > 0 ) + { + enabled_port_number--; + assigned_queue_number = unassigned_queue_number - enabled_port_number * (1 + OAM_TX_QUEUE_NUMBER_PER_PORT) - OAM_TX_QUEUE_NUMBER_PER_PORT; + if ( assigned_queue_number > MAX_QUEUE_NUMBER_PER_PORT - OAM_TX_QUEUE_NUMBER_PER_PORT ) + assigned_queue_number = MAX_QUEUE_NUMBER_PER_PORT - OAM_TX_QUEUE_NUMBER_PER_PORT; + if ( port_max_connection[i] > assigned_queue_number ) + { + port_max_connection[i] = assigned_queue_number; + unassigned_queue_number -= assigned_queue_number; + } + else + unassigned_queue_number -= port_max_connection[i]; + } + + /* Please refer to Amazon spec 15.4 for setting these values. */ + if ( qsb_tau < 1 ) + qsb_tau = 1; + if ( qsb_tstep < 1 ) + qsb_tstep = 1; + else if ( qsb_tstep > 4 ) + qsb_tstep = 4; + else if ( qsb_tstep == 3 ) + qsb_tstep = 2; + + /* There is a delay between PPE write descriptor and descriptor is */ + /* really stored in memory. Host also has this delay when writing */ + /* descriptor. So PPE will use this value to determine if the write */ + /* operation makes effect. */ + if ( write_descriptor_delay < 0 ) + write_descriptor_delay = 0; + + if ( aal5_fill_pattern < 0 ) + aal5_fill_pattern = 0; + else + aal5_fill_pattern &= 0xFF; + + /* Because of the limitation of length field in descriptors, the packet */ + /* size could not be larger than 64K minus overhead size. */ + if ( aal5r_max_packet_size < 0 ) + aal5r_max_packet_size = 0; + else if ( aal5r_max_packet_size >= 65536 - MAX_RX_FRAME_EXTRA_BYTES ) + aal5r_max_packet_size = 65536 - MAX_RX_FRAME_EXTRA_BYTES; + if ( aal5r_min_packet_size < 0 ) + aal5r_min_packet_size = 0; + else if ( aal5r_min_packet_size > aal5r_max_packet_size ) + aal5r_min_packet_size = aal5r_max_packet_size; + if ( aal5s_max_packet_size < 0 ) + aal5s_max_packet_size = 0; + else if ( aal5s_max_packet_size >= 65536 - MAX_TX_FRAME_EXTRA_BYTES ) + aal5s_max_packet_size = 65536 - MAX_TX_FRAME_EXTRA_BYTES; + if ( aal5s_min_packet_size < 0 ) + aal5s_min_packet_size = 0; + else if ( aal5s_min_packet_size > aal5s_max_packet_size ) + aal5s_min_packet_size = aal5s_max_packet_size; + + if ( dma_rx_descriptor_length < 2 ) + dma_rx_descriptor_length = 2; + if ( dma_tx_descriptor_length < 2 ) + dma_tx_descriptor_length = 2; + if ( dma_rx_clp1_descriptor_threshold < 0 ) + dma_rx_clp1_descriptor_threshold = 0; + else if ( dma_rx_clp1_descriptor_threshold > dma_rx_descriptor_length ) + dma_rx_clp1_descriptor_threshold = dma_rx_descriptor_length; +} + +static struct atmdev_ops ppe_atm_ops = { + owner: THIS_MODULE, + open: ppe_open, + close: ppe_close, + ioctl: ppe_ioctl, + send: ppe_send, + send_oam: ppe_send_oam, + change_qos: ppe_change_qos, +}; + +int __init danube_ppe_init(void) +{ + int ret; + int port_num; + + check_parameters(); + + ret = init_ppe_dev(); + if ( ret ) + goto INIT_PPE_DEV_FAIL; + + clear_share_buffer(); + init_rx_tables(); + init_tx_tables(); +printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + + for ( port_num = 0; port_num < ATM_PORT_NUMBER; port_num++ ) + if ( ppe_dev.port[port_num].max_connections != 0 ) + { + printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + ppe_dev.port[port_num].dev = atm_dev_register("danube_atm", &ppe_atm_ops, -1, 0UL); + if ( !ppe_dev.port[port_num].dev ) + { + printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + ret = -EIO; + goto ATM_DEV_REGISTER_FAIL; + } + else + { + printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + ppe_dev.port[port_num].dev->ci_range.vpi_bits = 8; + ppe_dev.port[port_num].dev->ci_range.vci_bits = 16; + ppe_dev.port[port_num].dev->link_rate = ppe_dev.port[port_num].tx_max_cell_rate; + ppe_dev.port[port_num].dev->dev_data = (void*)port_num; + } + } + /* register interrupt handler */ + ret = request_irq(IFXMIPS_PPE_MBOX_INT, mailbox_irq_handler, IRQF_DISABLED, "ppe_mailbox_isr", NULL); + if ( ret ) + { + if ( ret == -EBUSY ) + printk("ppe: IRQ may be occupied by ETH2 driver, please reconfig to disable it.\n"); + goto REQUEST_IRQ_IFXMIPS_PPE_MBOX_INT_FAIL; + } + disable_irq(IFXMIPS_PPE_MBOX_INT); + + #if defined(CONFIG_PCI) && defined(USE_FIX_FOR_PCI_PPE) && USE_FIX_FOR_PCI_PPE + ret = request_irq(PPE_MAILBOX_IGU0_INT, pci_fix_irq_handler, SA_INTERRUPT, "ppe_pci_fix_isr", NULL); + if ( ret ) + printk("failed in registering mailbox 0 interrupt (pci fix)\n"); + #endif // defined(CONFIG_PCI) && defined(USE_FIX_FOR_PCI_PPE) && USE_FIX_FOR_PCI_PPE + + ret = pp32_start(); + if ( ret ) + goto PP32_START_FAIL; + + qsb_global_set(); + HTU_ENTRY(OAM_F4_SEG_HTU_ENTRY)->vld = 1; + HTU_ENTRY(OAM_F4_TOT_HTU_ENTRY)->vld = 1; + HTU_ENTRY(OAM_F5_HTU_ENTRY)->vld = 1; + + /* create proc file */ + proc_file_create(); + + printk("ppe: ATM init succeeded (firmware version 1.1.0.2.1.13\n"); + return 0; + +PP32_START_FAIL: + + free_irq(IFXMIPS_PPE_MBOX_INT, NULL); +REQUEST_IRQ_IFXMIPS_PPE_MBOX_INT_FAIL: +ATM_DEV_REGISTER_FAIL: + clear_ppe_dev(); +INIT_PPE_DEV_FAIL: + printk("ppe: ATM init failed\n"); + return ret; +} + +void __exit danube_ppe_exit(void) +{ + int port_num; + register int l; + proc_file_delete(); + HTU_ENTRY(OAM_F4_SEG_HTU_ENTRY)->vld = 0; + HTU_ENTRY(OAM_F4_TOT_HTU_ENTRY)->vld = 0; + HTU_ENTRY(OAM_F5_HTU_ENTRY)->vld = 0; + /* idle for a while to finish running HTU search */ + for (l = 0; l < IDLE_CYCLE_NUMBER; l++ ); + pp32_stop(); + free_irq(IFXMIPS_PPE_MBOX_INT, NULL); + for ( port_num = 0; port_num < ATM_PORT_NUMBER; port_num++ ) + if ( ppe_dev.port[port_num].max_connections != 0 ) + atm_dev_deregister(ppe_dev.port[port_num].dev); + clear_ppe_dev(); +} + +module_init(danube_ppe_init); +module_exit(danube_ppe_exit); + +MODULE_LICENSE("GPL"); + diff --git a/package/ifxmips-atm/src/ifx_ppe_fw.h b/package/ifxmips-atm/src/ifx_ppe_fw.h new file mode 100644 index 0000000000..af250f3a94 --- /dev/null +++ b/package/ifxmips-atm/src/ifx_ppe_fw.h @@ -0,0 +1,426 @@ +#ifndef __DANUBE_PPE_FW_H__2005_08_04__12_00__ +#define __DANUBE_PPE_FW_H__2005_08_04__12_00__ + + +/****************************************************************************** +** +** FILE NAME : danube_ppe_fw.h +** PROJECT : Danube +** MODULES : ATM (ADSL) +** +** DATE : 1 AUG 2005 +** AUTHOR : Xu Liang +** DESCRIPTION : ATM Driver (PP32 Firmware) +** COPYRIGHT : Copyright (c) 2006 +** Infineon Technologies AG +** Am Campeon 1-12, 85579 Neubiberg, Germany +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** HISTORY +** $Date $Author $Comment +** 4 AUG 2005 Xu Liang Initiate Version +** 23 OCT 2006 Xu Liang Add GPL header. +*******************************************************************************/ + + +static u32 firmware_binary_code[] = { + 0x800004A0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8000FFC8, 0x00000000, 0x00000000, 0x00000000, + 0xC1000002, 0xD90C0000, 0xC2000002, 0xDA080001, 0x80004710, 0xC2000000, 0xDA080001, 0x80003D98, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80003D50, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80004F18, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80003C50, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xC0400000, 0xC0004840, 0xC8840000, 0x800043D0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xC0400002, 0xC0004840, 0xC8840000, 0x80004350, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xC3C00004, 0xDBC80001, 0xC10C0002, 0xD90C0000, 0x8000FEC8, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xC10E0002, 0xD90C0000, 0xC0004808, 0xC8400000, 0x80004380, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xC3E1FFFE, 0x597DFFFE, 0x593DFE14, 0x900004D9, 0x00000000, 0x00000000, 0x00000000, 0x90CC0481, + 0x00000000, 0x00000000, 0x00000000, 0xC3C00000, 0xDBC80001, 0xC1400008, 0xC1900000, 0x71948000, + 0x15000100, 0xC140000A, 0xC1900002, 0x71948000, 0x15000100, 0xC140000C, 0xC1900004, 0x71948000, + 0x15000100, 0xC1400004, 0xC1900006, 0x71948000, 0x15000100, 0xC1400006, 0xC1900008, 0x71948000, + 0x15000100, 0xC140000E, 0xC190000A, 0x71948000, 0x15000100, 0xC1400000, 0xC190000C, 0x71948000, + 0x15000100, 0xC1400002, 0xC190000E, 0x71948000, 0x15000100, 0xC0400000, 0xC11C0000, 0xC000082C, + 0xCD040E08, 0xC11C0002, 0xC000082C, 0xCD040E08, 0xC0400002, 0xC11C0000, 0xC000082C, 0xCD040E08, + 0xC11C0002, 0xC000082C, 0xCD040E08, 0xC0000824, 0x00000000, 0xCBC00001, 0xCB800001, 0xCB400001, + 0xCB000000, 0xC0004878, 0x5BFC4000, 0xCFC00001, 0x5BB84000, 0xCF800001, 0x5B744000, 0xCF400001, + 0x5B304000, 0xCF000000, 0xC0000A10, 0x00000000, 0xCBC00001, 0xCB800000, 0xC0004874, 0x5BFC4000, + 0xCFC00001, 0x5BB84000, 0xCF800000, 0xC30001FE, 0xC000140A, 0xCF000000, 0xC3000000, 0x7F018000, + 0xC000042E, 0xCF000000, 0xC000040E, 0xCF000000, 0xC3C1FFFE, 0xC000490E, 0xCFC00080, 0xC000492C, + 0xCFC00080, 0xC0004924, 0xCFC00040, 0xC0004912, 0xCFC00040, 0xC0004966, 0xCFC00040, 0xC0004968, + 0xCFC00080, 0xC000496A, 0xCFC00080, 0xC3C00000, 0xC2800020, 0xC3000000, 0x7F018000, 0x6FF88000, + 0x6FD44000, 0x4395C000, 0x5BB84A00, 0x5838000A, 0xCF000000, 0x5BFC0002, 0xB7E8FFA8, 0x00000000, + 0xC3C00000, 0xC2800010, 0x6FF86000, 0x47F9C000, 0x5BB84C80, 0xC3400000, 0x58380004, 0xCB420080, + 0x00000000, 0x58380008, 0xCF400080, 0x5BFC0002, 0xB7E8FF90, 0x00000000, 0xC3C00000, 0xC2800020, + 0xC348001E, 0xC3000000, 0x7F018000, 0x6FF8A000, 0x6FD44000, 0x4579C000, 0x47F9C000, 0x5BB84E20, + 0x58380008, 0xCF400420, 0x5838000A, 0xCF000000, 0x5BFC0002, 0xB7E8FF90, 0x00000000, 0x00000000, + 0x00000000, 0xC121FFFE, 0x5911FE14, 0x15000000, 0x80000518, 0x00000000, 0x80002118, 0x00000000, + 0x8000FFC8, 0xC0004958, 0xC8400000, 0x00000000, 0xC3C00002, 0x7BC42000, 0xCC400000, 0xC0004848, + 0xCB840000, 0xC000495C, 0xCAC40000, 0xC0004844, 0xC8840000, 0x46F90000, 0x8400FF6A, 0xC000487C, + 0xC8040000, 0x00000000, 0x00000000, 0x40080000, 0xCA000000, 0xC0001624, 0xCB040000, 0xA63C005A, + 0x00000000, 0x00000000, 0xA71EFF02, 0x00000000, 0xC0000824, 0xCA840000, 0x6CA08000, 0x6CA42000, + 0x46610000, 0x42290000, 0xC35E0002, 0xC6340068, 0xC0001624, 0xCF440080, 0xC2000000, 0xC161FFFE, + 0x5955FFFE, 0x15400000, 0x00000000, 0xC0004844, 0xC8840000, 0xC000082C, 0xCA040040, 0x00000000, + 0x00000000, 0x58880002, 0xB608FFF8, 0x00000000, 0xC0800000, 0xC0004844, 0xCC840040, 0x5AEC0002, + 0xC000495C, 0xCEC40000, 0x5E6C0006, 0x84000048, 0xC0004848, 0xCB840000, 0xC0000838, 0xC2500002, + 0xCE440808, 0x5FB80002, 0xC0004848, 0xCF840000, 0x5EEC0002, 0xC000495C, 0xCEC40000, 0x00000000, + 0xC121FFFE, 0x5911FE14, 0x15000000, 0x8000FD80, 0xC000495A, 0xC8400000, 0x00000000, 0xC3C00002, + 0x7BC42000, 0xCC400000, 0xC0004960, 0xCAC40000, 0x00000000, 0x00000000, 0x5EEC0000, 0x840000F2, + 0x00000000, 0xB6FC0030, 0xC0001600, 0xCA040000, 0x00000000, 0x00000000, 0xA61E00B2, 0x6FE90000, + 0xC0000A28, 0xCE840808, 0xC2C00000, 0xC2800004, 0xB6E80080, 0xC0001604, 0xCA840000, 0xC0004960, + 0xCEC40000, 0xA69EFCA2, 0x00000000, 0x6FE90000, 0xC0000A28, 0xCE840808, 0xC2C00002, 0xC0001600, + 0xCA040000, 0x00000000, 0x00000000, 0xA61E000A, 0x6FE90000, 0xC0000A28, 0xCE840808, 0xC2C00000, + 0xC0001604, 0xCA840000, 0xC0004960, 0xCEC40000, 0xA69EFC0A, 0xC2400000, 0xC0000A14, 0xCA440030, + 0x00000000, 0x00000000, 0x46E52000, 0xA4400000, 0xC2800000, 0xDFEB0031, 0x8000FFF8, 0xDFEA0031, + 0xB668FB82, 0x00000000, 0xC00048A0, 0xCB040000, 0xC0000A10, 0xCA840000, 0x6F208000, 0x6F242000, + 0x46610000, 0x42A10000, 0xC2400000, 0xC0000A14, 0xCA440030, 0xC35E0002, 0xC6340068, 0xC0001604, + 0xCF440080, 0x5B300002, 0xB670FFF8, 0x5AEC0002, 0xC3000000, 0xC00048A0, 0xCF040000, 0xC0004960, + 0xCEC40000, 0x8000FAC0, 0xC0004918, 0xD2800000, 0xC2000000, 0xDF600040, 0x5E600080, 0x8400025A, + 0x00000000, 0xC161FFFE, 0x5955FFFE, 0x15400000, 0x00000000, 0xC000480A, 0xCA000000, 0xC0004912, + 0xCA400000, 0xC0004924, 0xCA800000, 0xC0004966, 0xCAC00000, 0x00000000, 0xC121FFFE, 0x5911FE14, + 0x15000000, 0x76610000, 0x76A10000, 0x76E10000, 0x840001B2, 0xC0004918, 0xCA400000, 0xC28001FE, + 0x76A10000, 0x5A640002, 0x6A254010, 0x5EE80000, 0x84000002, 0x6AA54000, 0x8000FFF8, 0xC6280000, + 0x62818008, 0xC0004918, 0xCF000000, 0xC161FFFE, 0x5955FFFE, 0x15400000, 0x00000000, 0xC0004966, + 0xCA400000, 0xC2000002, 0x6A310000, 0x7E010000, 0x76252000, 0xCE400000, 0x00000000, 0xC121FFFE, + 0x5911FE14, 0x15000000, 0x6F346000, 0x4735A000, 0x5B744C80, 0xC2800000, 0x58340006, 0xCA800080, + 0xC2C00000, 0x58340000, 0xCAC000E0, 0xC2400000, 0x5834000A, 0xCA420080, 0x6EA82000, 0x42E9E000, + 0x6F2CA000, 0x42E56000, 0x5AEC1400, 0xC3990040, 0xC7381C20, 0xC6F80068, 0x99005930, 0xDB980000, + 0xDBD80001, 0x00000000, 0xDEA00000, 0x47210000, 0x8400FD68, 0xC0004958, 0xC8400000, 0x00000000, + 0xC3C00002, 0x7BC42000, 0xCC400000, 0xC0004848, 0xCB840000, 0xC0004844, 0xC8840000, 0x5FB80000, + 0x8400F7DA, 0xC0001A1C, 0xCA000000, 0xC2400002, 0x6A452000, 0x76610000, 0x8400F7AA, 0xC000487C, + 0xC8040000, 0x00000000, 0x00000000, 0x40080000, 0xCA000000, 0xC4240000, 0x00000000, 0xA63C17BA, + 0x00000000, 0xC0004878, 0xC8040000, 0x6C908000, 0x44908000, 0x44908000, 0x40100000, 0xCA000000, + 0xC4240000, 0x00000000, 0xC0004934, 0xCE000000, 0xC2800002, 0xC4681C10, 0xC62821D8, 0xC2600010, + 0x5A650040, 0xC0004800, 0xCB400000, 0xC2200400, 0x5A200000, 0xC7601048, 0xC0001220, 0xCE800000, + 0xC0001200, 0xCE400000, 0xC0001202, 0xCE000000, 0xC0001240, 0xCB400000, 0x00000000, 0x00000000, + 0xA754FFC0, 0xC2000000, 0xC7600048, 0xA7520022, 0x00000000, 0x00000000, 0x990060A8, 0xC0004822, + 0xC9400000, 0xC1800002, 0x80001668, 0x58204080, 0xC2000000, 0xCA000020, 0xC2400000, 0xCA414008, + 0xC2800000, 0xCA812008, 0xC2C00000, 0xCAC20020, 0xC0004938, 0xCE000000, 0xC0004920, 0xCE400000, + 0xC0004916, 0xCE800000, 0xC0004922, 0xCEC00000, 0xA6400520, 0x00000000, 0xC0004938, 0xCBC00000, + 0x00000000, 0xC3800000, 0x6FF48000, 0x6FD44000, 0x4355A000, 0x5B744A00, 0x58340000, 0xCB802018, + 0x00000000, 0xC2000000, 0x6FB46000, 0x47B5A000, 0x5B744C80, 0x5834000C, 0xCA000028, 0xC000491A, + 0xCF800000, 0x5E200000, 0x84000452, 0xC2000000, 0xDF610050, 0x5E6001E8, 0x8800FFD0, 0xC2000002, + 0xC2400466, 0xC2A00000, 0x5AA80000, 0xC0001006, 0xCE000000, 0xC0001008, 0xCE400000, 0xC000100A, + 0xCE800000, 0x99005370, 0xC1A0FFFE, 0xC0000824, 0xC9840068, 0xC0004934, 0xCA400000, 0xC2000000, + 0xC2800002, 0x990053B0, 0xDA980000, 0xC6140000, 0xC6580000, 0xC161FFFE, 0x5955FFFE, 0x15400000, + 0x00000000, 0x99005498, 0xC000491A, 0xC9400000, 0x00000000, 0x00000000, 0xC121FFFE, 0x5911FE14, + 0x15000000, 0xC0004922, 0xCA001120, 0xC3C00000, 0xC3800000, 0xC0004930, 0xCE001120, 0xC0004932, + 0xCBC000E0, 0xC2800000, 0xC000491E, 0xCFC00000, 0xC0004862, 0xCA800068, 0xC3A0001A, 0x5BB94000, + 0xC6B80068, 0xC000491C, 0xCF800000, 0x99005708, 0xC000491C, 0xC1400000, 0xC9420050, 0x00000000, + 0x00000000, 0x00000000, 0xA8E2FFC8, 0xC2000000, 0xC1220002, 0xD90C0000, 0xDF600040, 0x5E600080, + 0x8400FFDA, 0xC000491C, 0xCA000000, 0xC000491E, 0xCA400000, 0x00000000, 0x00000000, 0x99005930, + 0xDA180000, 0xDA580001, 0x00000000, 0xC2000000, 0xDF610050, 0x5E6001FE, 0x8800FFD0, 0xC0004916, + 0xCA800000, 0xC2C00000, 0xDFEC0050, 0xC2400000, 0x46E52000, 0x84000032, 0x5EA80000, 0x84000022, + 0xC2600002, 0x990060A8, 0xC000482E, 0xC9400000, 0xC1800002, 0x80000018, 0xC2600000, 0x990060A8, + 0xC000482C, 0xC9400000, 0xC1800002, 0xC2000068, 0xC6240080, 0xC0004930, 0xCE400088, 0xC000491A, + 0xC9800000, 0xC0004862, 0xC9400000, 0x6D9C6000, 0x459CE000, 0x59DC4C80, 0x99005790, 0xD9580000, + 0xD9980001, 0xD9D40000, 0x99005708, 0xC000491C, 0xC1400000, 0xC9420050, 0xC2000000, 0xDF600040, + 0x5E600080, 0x8400FFD2, 0x00000000, 0xC000491C, 0xCA000000, 0xC000491E, 0xCA400000, 0x00000000, + 0x00000000, 0x99005930, 0xDA180000, 0xDA580001, 0x00000000, 0x800010D0, 0x00000000, 0x990060A8, + 0xC000482A, 0xC9400000, 0xC1800002, 0x800010A0, 0xC0004938, 0xCBC00000, 0x00000000, 0x00000000, + 0x6FF88000, 0x6FD44000, 0x4395C000, 0x5BB84A00, 0x58380008, 0xCA000000, 0x00000000, 0x00000000, + 0xA6000362, 0x00000000, 0xC0004938, 0xCBC00000, 0xC3000000, 0x00000000, 0x6FF88000, 0x6FD44000, + 0x4395C000, 0x5BB84A00, 0x58380000, 0xCB002018, 0xC2000000, 0x58380008, 0xCA020080, 0x5838000C, + 0xCAC00000, 0x5838000E, 0xCA400000, 0xC000491A, 0xCF000000, 0xC0004930, 0xCEC00000, 0xC000493C, + 0xCE000000, 0xC0004932, 0xCE400000, 0x5E200000, 0x84000108, 0xC2800000, 0xA6FE009A, 0x6F206000, + 0x47210000, 0x5A204C80, 0x5820000C, 0xCA800028, 0x00000000, 0x00000000, 0x5EA80000, 0x840001DA, + 0x00000000, 0xC161FFFE, 0x5955FFFE, 0x15400000, 0x00000000, 0x99005498, 0xC000491A, 0xC9400000, + 0x00000000, 0x00000000, 0xC121FFFE, 0x5911FE14, 0x15000000, 0xC0004930, 0xCAC00000, 0xC0004932, + 0xCA400000, 0xC7EC1120, 0xC0004930, 0xCEC00000, 0x5838000C, 0xCEC00000, 0x58000002, 0xCE400000, + 0xC0004934, 0xCA000000, 0xC2400002, 0x6E642000, 0x6E642000, 0x76252000, 0x84000012, 0xC2400002, + 0x6E684000, 0x58380008, 0xCE800208, 0xA6000000, 0x6E682000, 0x58380008, 0xCE800108, 0xC2400002, + 0x6E642000, 0x76252000, 0x840000D2, 0x58380008, 0xCA000000, 0xC2800000, 0xC2400000, 0xA60200A0, + 0xDBA80000, 0x6F386000, 0x4739C000, 0x5BB84C80, 0x58380004, 0xCA400080, 0x58380002, 0xCA800080, + 0x00000000, 0xDEB80000, 0x46694000, 0x88000048, 0x00000000, 0xC0004824, 0xCA000000, 0xC2400002, + 0x6E640000, 0x5A200002, 0xCE000000, 0x58380008, 0xCE400008, 0x80000000, 0x00000000, 0x80000030, + 0xC0004934, 0xCA000000, 0x00000000, 0x00000000, 0xA6020C4A, 0x00000000, 0x00000000, 0x80000C80, + 0xC2800000, 0xC2000200, 0xC240001A, 0xDF690050, 0x46A14000, 0x46694000, 0x8800FFBA, 0xC2000006, + 0xC2600982, 0x5A643B6E, 0x5838000A, 0xCA800000, 0xC0001006, 0xCE000000, 0xC0001008, 0xCE400000, + 0xC000100A, 0xCE800000, 0x99005370, 0xC1A0FFFE, 0xC0000824, 0xC9840068, 0xC2000000, 0xC0004930, + 0xCA02E010, 0x58380026, 0xCA400000, 0x00000000, 0xC2800000, 0x990053B0, 0xDA980000, 0xC6140000, + 0xC6580000, 0xC0004934, 0xCA000000, 0x00000000, 0x00000000, 0xA6020002, 0x00000000, 0x00000000, + 0x80000300, 0xC0004938, 0xCBC00000, 0xC0004878, 0xC8040000, 0x6C908000, 0x44908000, 0x44908000, + 0x40100000, 0xCA000000, 0xC4240000, 0x00000000, 0x58240018, 0xCA000000, 0x6FF88000, 0x6FD44000, + 0x4395C000, 0x5BB84A00, 0xC3000000, 0xC3400002, 0xC2C00000, 0xC62C0080, 0xC6270040, 0xC0004940, + 0xCE400040, 0xC6260040, 0xC0004942, 0xCE400040, 0xC000493C, 0xCA000000, 0x5EEC0000, 0x84000172, + 0x5A6C0010, 0x46614000, 0x88000178, 0x5A600052, 0x466D4000, 0x88000160, 0x58380006, 0xCA800000, + 0xC0004940, 0xCA000000, 0xC2400000, 0xC6A70040, 0x7E412000, 0x76252000, 0xC2000000, 0xC6A10040, + 0x46610000, 0x84000120, 0xC0004942, 0xCA000000, 0xC2400000, 0xC6A60040, 0x7E412000, 0x76252000, + 0xC2000000, 0xC6A00040, 0x58380002, 0xCA800000, 0x46610000, 0x840000D0, 0xC2400000, 0xC6A60080, + 0x46E50000, 0x880000C2, 0xC2400000, 0xC6A40080, 0x58380008, 0xCA800000, 0x466D0000, 0x880000A2, + 0x00000000, 0xA682FFF8, 0x00000000, 0xC7700B08, 0xA6840078, 0x00000000, 0xC7700A08, 0x80000068, + 0xC7700208, 0xC000493C, 0xCAC00000, 0x80000048, 0xC7700308, 0xC000493C, 0xCAC00000, 0x80000028, + 0xC7700908, 0x80000018, 0xC7700808, 0x80000008, 0xC7700708, 0x8000FFF8, 0xC7700508, 0xC0004944, + 0xCF000000, 0xC000493E, 0xCEC00000, 0xC0004938, 0xCA400000, 0xC000493C, 0xCB800000, 0xC000493E, + 0xCB400000, 0xC3000000, 0x6E608000, 0x6E544000, 0x42150000, 0x5A204A00, 0x5AA00008, 0x58200004, + 0xCB000080, 0xC0004934, 0xCA000000, 0xC2400000, 0xC0004930, 0xCA42E010, 0xC3C00018, 0xA6020078, + 0x00000000, 0x43656000, 0x46F90000, 0x88000038, 0x47AD6000, 0x6EE04010, 0x5BE00004, 0xC2000000, + 0xC6E00010, 0x5E200000, 0x8400002A, 0x5BFC0002, 0x80000018, 0xC3C00004, 0x5A2C0008, 0x46390000, + 0x8800FFFA, 0x5FB80008, 0x6FE04000, 0x42390000, 0x46312000, 0x88000050, 0xC2400000, 0xC0004930, + 0xCA42E010, 0xC2060002, 0xC6800000, 0xCE000308, 0x6FE04000, 0x4631C000, 0x5F700010, 0x4675A000, + 0xC2000000, 0xC6340010, 0xC25A000A, 0xC000491A, 0xCA401C20, 0xC2800000, 0xC0004932, 0xCA8000E0, + 0xC0004862, 0xCA400068, 0x6FA04010, 0x42290000, 0xC000491E, 0xCE000000, 0xC7E41050, 0xC000491C, + 0xCE400000, 0x6FE04000, 0x43A1C000, 0xC000493C, 0xCF800000, 0xC000493E, 0xCF400000, 0xC000493A, + 0xCFC00000, 0x8000FFF0, 0x00000000, 0x00000000, 0x00000000, 0xC2000000, 0xDCE00000, 0xA622FFB8, + 0xC1220002, 0xD90C0000, 0xC0004938, 0xCBC00000, 0xC0004944, 0xCB400000, 0xC0004862, 0xCB000000, + 0xC0004934, 0xCA000000, 0x6FF88000, 0x6FD44000, 0x4395C000, 0x5BB84A00, 0xA6020248, 0xC2400000, + 0x58380008, 0xCA406008, 0xDFE80000, 0xC2218E08, 0x5A21BAF6, 0x46294000, 0x8400000A, 0xC2080002, + 0x7235A000, 0x80000040, 0x5E640000, 0x8400000A, 0xC20C0002, 0x7235A000, 0x80000018, 0xC2000000, + 0xC760E718, 0xC7604220, 0x5E200000, 0x8400025A, 0xC2200002, 0xC0004930, 0xCE001008, 0x990060A8, + 0xC0004828, 0xC9400000, 0xC1800002, 0x58380000, 0xCA000000, 0x00000000, 0x00000000, 0xA6000112, + 0xC0004940, 0xCA800000, 0xC0004942, 0xCA400000, 0xC7600080, 0xC6A01840, 0xC6601040, 0xC000493A, + 0xCA400000, 0xC0004934, 0xCA800000, 0xC0007200, 0x40300000, 0x40240000, 0x5C000004, 0x5EC07400, + 0x8800FFFA, 0x5C000200, 0xCE000000, 0x58000002, 0x5EC07400, 0x8800FFFA, 0x5C000200, 0xCE800000, + 0xC000493E, 0xCA000000, 0xC2400000, 0x5838000C, 0xCE400000, 0x990060A8, 0xC0004830, 0xC9400000, + 0xC6180000, 0xC0004930, 0xC6100080, 0xCD000080, 0x80000090, 0xC2400002, 0x58380008, 0xCE400008, + 0xC0004944, 0xCF400000, 0x80000260, 0xC000493C, 0xCA400000, 0xDFE80000, 0x5A300018, 0xC0007200, + 0x40200000, 0xCA000000, 0x58380008, 0xC6501080, 0xCD001080, 0x5838000A, 0xCE800000, 0x58380026, + 0xCE000000, 0xC0004944, 0xCF400000, 0x99005708, 0xC000491C, 0xC1400000, 0xC9420050, 0x80000020, + 0x00000000, 0x990060A8, 0xC0004826, 0xC9400000, 0xC1800002, 0x8000FDC0, 0xC2000000, 0xC2400200, + 0xDF600040, 0xB624FFCA, 0xC000491C, 0xCA400000, 0xC000491E, 0xCA800000, 0x99005930, 0xDA580000, + 0xDA980001, 0x00000000, 0xC0004934, 0xCA000000, 0x00000000, 0xC2800000, 0xA6020140, 0xC2400004, + 0xC2000200, 0xDF690050, 0x46A14000, 0x46694000, 0x8800FFC2, 0x00000000, 0xC000491A, 0xC9800000, + 0xC0004862, 0xC9400000, 0x6D9C6000, 0x459CE000, 0x59DC4C80, 0x99005790, 0xD9580000, 0xD9980001, + 0xD9D40000, 0x99005708, 0xC000491C, 0xC1400000, 0xC9420050, 0xC2000000, 0xC2400200, 0xDF600040, + 0xB624FFCA, 0xC000491C, 0xCA400000, 0xC000491E, 0xCA800000, 0x99005930, 0xDA580000, 0xDA980001, + 0x00000000, 0x58380008, 0xCA400000, 0xC2000000, 0xCE000020, 0xC2A1FFFE, 0x5AA9FFFE, 0xCE001080, + 0x5838000A, 0xCE800000, 0xC161FFFE, 0x5955FFFE, 0x15400000, 0x00000000, 0xC0000838, 0xC2500002, + 0xCE440808, 0xC0004848, 0xCB840000, 0xC2000000, 0xC000082C, 0xCA040030, 0x5FB80002, 0xC0004848, + 0xCF840000, 0x58880002, 0xB608FFF8, 0x00000000, 0xC0800000, 0xC0004844, 0xCC840000, 0x00000000, + 0xC121FFFE, 0x5911FE14, 0x15000000, 0x8000DEC0, 0xC2000000, 0xDF600040, 0x5E200080, 0x84000252, + 0x00000000, 0xC161FFFE, 0x5955FFFE, 0x15400000, 0x00000000, 0xC000480C, 0xCA000000, 0xC0004910, + 0xCA400000, 0xC000492C, 0xCA800000, 0xC0004968, 0xCAC00000, 0x00000000, 0xC121FFFE, 0x5911FE14, + 0x15000000, 0x76610000, 0x76A10000, 0x762D6000, 0x840001AA, 0xC0004926, 0xCA400000, 0xC201FFFE, + 0x762D6000, 0x5A640002, 0x6AE50010, 0x5F200000, 0x84000002, 0x6A250000, 0x8000FFF8, 0xC6E00000, + 0x62014008, 0xC0004926, 0xCE800000, 0xC161FFFE, 0x5955FFFE, 0x15400000, 0x00000000, 0xC0004968, + 0xCA400000, 0xC2000002, 0x6A290000, 0x7E010000, 0x76252000, 0xCE400000, 0x00000000, 0xC121FFFE, + 0x5911FE14, 0x15000000, 0x6EB4A000, 0x6E944000, 0x4575A000, 0x46B5A000, 0x5B744E20, 0x58340002, + 0xC2000000, 0xCA0000E0, 0x5834002E, 0xC2400000, 0xCA400080, 0x6EB0A000, 0x6EBC4000, 0x47F18000, + 0x46B18000, 0x5B300E4E, 0x5B300004, 0x6E642000, 0x4225E000, 0xC39A8024, 0xC7380068, 0xC6B81C20, + 0x99005930, 0xDB980000, 0xDBD80001, 0x00000000, 0xC2000000, 0xDF600040, 0x5E200080, 0x8400028A, + 0x00000000, 0xC161FFFE, 0x5955FFFE, 0x15400000, 0x00000000, 0xC000490E, 0xCA000000, 0xC000492A, + 0xCA400000, 0xC000496A, 0xCB000000, 0xC0004956, 0xCAC00000, 0x00000000, 0xC121FFFE, 0x5911FE14, + 0x15000000, 0x76318000, 0x76718000, 0x840001EA, 0xC201FFFE, 0x76318000, 0x5AEC0002, 0x6B2D0010, + 0x5EA00000, 0x84000002, 0x6A2D0000, 0x8000FFF8, 0xC7200000, 0x62016008, 0xC0004956, 0xCEC00000, + 0xC161FFFE, 0x5955FFFE, 0x15400000, 0x00000000, 0xC000496A, 0xCA400000, 0xC2000002, 0x6A2D0000, + 0x7E010000, 0x76252000, 0xCE400000, 0x00000000, 0xC121FFFE, 0x5911FE14, 0x15000000, 0x6EF4A000, + 0x6ED44000, 0x4575A000, 0x46F5A000, 0x5B744E20, 0x5834000E, 0xC2000000, 0xCA0000E0, 0x58340008, + 0xC2400000, 0xCA420080, 0x5834000C, 0xC2800000, 0xCA832018, 0x6E644010, 0x42250000, 0x4229E000, + 0xC39A8008, 0x58340008, 0xCB809020, 0x58340008, 0xC2800000, 0xCA810018, 0x6EE0A000, 0x6EE44000, + 0x46610000, 0x46E10000, 0x5A200008, 0x5A200E28, 0x42290000, 0xC6380068, 0xC6F81C20, 0x99005930, + 0xDB980000, 0xDBD80001, 0x00000000, 0xC000495A, 0xC8400000, 0x00000000, 0xC3C00002, 0x7BC42000, + 0xCC400000, 0xC0001A1C, 0xCA000000, 0xC2400008, 0x6A452000, 0x76610000, 0x8400D91A, 0xC0000A28, + 0xC3800000, 0xCB840030, 0xC0000A14, 0xC3400000, 0xCB440030, 0xC0004880, 0xCB040000, 0xB7B4D8CA, + 0x58041802, 0xCAC00000, 0xA7000018, 0x00000000, 0x00000000, 0xA6C8D898, 0xC2800000, 0xC6E80020, + 0x80000030, 0xC2800000, 0xC7282020, 0xC000490E, 0xCA400000, 0x6BE9E000, 0x00000000, 0x77E52000, + 0x8400D848, 0x6EA0A000, 0x6E944000, 0x45610000, 0x46A10000, 0x5A204E20, 0x5820000C, 0xCA000000, + 0xC0004946, 0xCE800000, 0xA6220348, 0x00000000, 0xC2200060, 0xC0004948, 0xCE000010, 0xCE001040, + 0xC240000A, 0xC000494A, 0xCE400000, 0xC2B60002, 0xC0004964, 0xCE801B08, 0x99005C00, 0xC00048A0, + 0xC8840000, 0x00000000, 0xC0004946, 0xCBC00000, 0x00000000, 0x00000000, 0x6FF8A000, 0x6FD44000, + 0x4579C000, 0x47F9C000, 0x5BB84E20, 0x990059C0, 0xDBD80000, 0xDB980001, 0x00000000, 0x99005708, + 0xC000491C, 0xC1400000, 0xC9420050, 0xC000491C, 0x99005BB8, 0xC9400001, 0xC9800000, 0x00000000, + 0x99005930, 0xD9580000, 0xD9980001, 0x00000000, 0xC161FFFE, 0x5955FFFE, 0x15400000, 0x00000000, + 0x990055F8, 0xDBD80000, 0xDB980001, 0xC7D80000, 0x00000000, 0xC121FFFE, 0x5911FE14, 0x15000000, + 0x6FF8A000, 0x6FD44000, 0x4579C000, 0x47F9C000, 0x5BB84E20, 0x58380010, 0xCA000000, 0xC0004874, + 0xC8040000, 0x6C908000, 0x44908000, 0x44908000, 0x40100000, 0xCA400000, 0xC4340000, 0x00000000, + 0xC7400000, 0xCE000000, 0xC161FFFE, 0x5955FFFE, 0x15400000, 0x00000000, 0xC000490E, 0xCA400000, + 0xC2800002, 0x6ABD4000, 0x72A52000, 0xCE400000, 0x00000000, 0xC121FFFE, 0x5911FE14, 0x15000000, + 0x990060A8, 0xC0004836, 0xC9400000, 0xC1800002, 0x00000000, 0x00000000, 0x00000000, 0xA8E2FFC8, + 0x00000000, 0xC1220002, 0xD90C0000, 0xC2000000, 0xC0000A14, 0xCA040030, 0xC0000A28, 0xC2500002, + 0xCE440808, 0x58880002, 0xB608FFF8, 0xC00048A0, 0xC0800000, 0xCC840000, 0x8000D498, 0xC0004946, + 0xCBC00000, 0xC161FFFE, 0x5955FFFE, 0x15400000, 0x00000000, 0xC000490E, 0xCA400000, 0xC2800002, + 0x6ABD4000, 0x72A52000, 0xCE400000, 0x00000000, 0xC121FFFE, 0x5911FE14, 0x15000000, 0x6FF8A000, + 0x6FD44000, 0x4579C000, 0x47F9C000, 0x5BB84E20, 0x58380008, 0xCA000000, 0x5838000C, 0xCA400000, + 0xC3400000, 0xC6340008, 0xC000494E, 0xCF400000, 0xC2800000, 0xC62A0080, 0xC3000000, 0xC6308020, + 0x6F304000, 0x43298000, 0xC000493C, 0xCF000000, 0xC2C00000, 0xC66C0080, 0xC0004950, 0xCEC00000, + 0xC2800000, 0xC66AE028, 0xC0004954, 0xCE800000, 0x5F740000, 0x84000188, 0x5E300028, 0x462D2000, + 0x84000152, 0x462D2000, 0x8800011A, 0x5E300018, 0x462D2000, 0x88000012, 0x462D2000, 0x8400002A, + 0x00000000, 0x800000A8, 0x00000000, 0x99005D40, 0xDBD80000, 0xDB980001, 0xC7800000, 0xC3400002, + 0xC000494E, 0xCF400000, 0xC161FFFE, 0x5955FFFE, 0x15400000, 0x00000000, 0xC000490E, 0xCA400000, + 0xC2800002, 0x6ABD4000, 0x7E814000, 0x76A52000, 0xCE400000, 0x00000000, 0xC121FFFE, 0x5911FE14, + 0x15000000, 0xC2200060, 0xC0004948, 0xCE001040, 0xC2000000, 0xC000494C, 0xCE000000, 0x80000068, + 0x00000000, 0x99005D40, 0xDBD80000, 0xDB980001, 0xC7800000, 0x99005F40, 0xDBD80000, 0xDB980001, + 0xC7800000, 0xC2200058, 0xC0004948, 0xCE001040, 0xC2000002, 0xC000494C, 0xCE000000, 0xC2000006, + 0xC0001006, 0xCE000000, 0x5838000A, 0xCA400000, 0xC2200982, 0x5A203B6E, 0xC0001008, 0xCE000000, + 0xC000100A, 0xCE400000, 0xC0004954, 0xCA800000, 0xC200000C, 0xC000494A, 0xCE000000, 0xC0004948, + 0xCE800010, 0xC2B60000, 0xC0004964, 0xCE800000, 0x99005C00, 0xC00048A0, 0xC8840000, 0x00000000, + 0xC0004946, 0xCBC00000, 0xC000494C, 0xCA000000, 0x6FF8A000, 0x6FD44000, 0x4579C000, 0x47F9C000, + 0x5BB84E20, 0x5E200000, 0x840000E2, 0x00000000, 0x990059C0, 0xDBD80000, 0xDB980001, 0x00000000, + 0x99005708, 0xC000491C, 0xC1400000, 0xC9420050, 0xC000491C, 0x99005BB8, 0xC9400001, 0xC9800000, + 0x00000000, 0x99005930, 0xD9580000, 0xD9980001, 0x00000000, 0xC161FFFE, 0x5955FFFE, 0x15400000, + 0x00000000, 0x990055F8, 0xDBD80000, 0xDB980001, 0xC7D80000, 0x00000000, 0xC121FFFE, 0x5911FE14, + 0x15000000, 0xC000493C, 0xCA800000, 0xC000494E, 0xCAC00000, 0xC3000018, 0xC3400006, 0x5E200000, + 0x84000012, 0xC2800000, 0xC2C00000, 0xC300001E, 0xC3400000, 0xC6AC1080, 0xC72C0420, 0xC76C0818, + 0x58380010, 0xCA800000, 0x58380008, 0xCEC00000, 0xC6280108, 0xC0004874, 0xC8040000, 0x6C908000, + 0x44908000, 0x44908000, 0x40100000, 0xCB000000, 0xC4340000, 0x00000000, 0xC7400000, 0xCE800000, + 0xC0004952, 0xCE800000, 0x00000000, 0x00000000, 0x00000000, 0xA8E2FFC8, 0x00000000, 0xC000494C, + 0xCA000000, 0xC0004950, 0xCAC00000, 0x5E200000, 0x84000052, 0xDFE80000, 0x7E814000, 0x5834001A, + 0xCE800000, 0x990060A8, 0xC0004834, 0xC9400000, 0xC1800002, 0x990060A8, 0xC0004838, 0xC9400000, + 0xC6D80000, 0xC1220002, 0xD90C0000, 0x5E200000, 0x84000028, 0x5838002C, 0xCB000000, 0xDFE80000, + 0x00000000, 0x58380014, 0xCF000000, 0x80000000, 0xC2A1FFFE, 0x5AA9FFFE, 0x5838000A, 0xCE800000, + 0xC3000000, 0xC0000A14, 0xCB040030, 0xC2D00002, 0xC0000A28, 0xCEC40808, 0xC000494E, 0xCA800000, + 0x58880002, 0xB4B0FFF8, 0xC00048A0, 0xC0800000, 0xCC840000, 0x5EA80000, 0x8400013A, 0x5E200000, + 0x84000128, 0xC000493C, 0xCA800000, 0x00000000, 0x00000000, 0x5AA80060, 0xCE800000, 0x99005D40, + 0xDBD80000, 0xDB980001, 0xC7800000, 0x99005F40, 0xDBD80000, 0xDB980001, 0xC7800000, 0xC0004952, + 0xCAC00000, 0x58380000, 0xCA800000, 0xC30C0002, 0xC7F00020, 0xA6800078, 0x00000000, 0x00000000, + 0xC161FFFE, 0x5955FFFE, 0x15400000, 0x00000000, 0xC0001800, 0xCA000000, 0x00000000, 0x00000000, + 0xA60CFFCA, 0xC6F00508, 0xC6B0C408, 0xCF000000, 0x00000000, 0xC121FFFE, 0x5911FE14, 0x15000000, + 0x8000CB48, 0xDCBC0001, 0x5FFC0000, 0x8400003A, 0xC3800002, 0xDB880001, 0x5FFC0004, 0x8400C4B2, + 0xC3800000, 0xDB880001, 0xC3CE0002, 0xC0000800, 0xCFC00708, 0xC3E1FFFE, 0x597DFFFE, 0x593DFE14, + 0x94000001, 0x00000000, 0x00000000, 0x00000000, 0xC000487C, 0xC8040000, 0x00000000, 0x00000000, + 0x40080000, 0xCBC00000, 0xC4380000, 0x00000000, 0xC000480E, 0xCA000000, 0xC0004858, 0xCB440000, + 0x00000000, 0x00000000, 0x46350000, 0x88000098, 0x00000000, 0xA7C00028, 0xC0004854, 0xC1000002, + 0xCD040000, 0xC11C0000, 0xC000082C, 0xCD040E08, 0x800000C0, 0x00000000, 0xA7D20118, 0x00000000, + 0xC7E14048, 0xC2400000, 0xC6246030, 0xC200006A, 0x46610000, 0xC6240038, 0xC0000810, 0xCE440038, + 0x8000FF58, 0xC2000000, 0xC0000808, 0xCA040018, 0xC11C0000, 0xC000082C, 0xCD040E08, 0x5A200002, + 0x5E600010, 0x8400FFF8, 0xC2000000, 0xC0000808, 0xCE040018, 0xC3400000, 0x80000010, 0xC1200002, + 0xC0000818, 0xCD041008, 0x5B740002, 0xC0004858, 0xCF440000, 0x99005348, 0xC0004848, 0xC9440000, + 0xC1800000, 0xC11C0002, 0xC000082C, 0xCD040E08, 0x800005C8, 0x5B740002, 0xC0004858, 0xCF440000, + 0xC7800000, 0xC13C0002, 0xCD001E08, 0xC0004848, 0xC9440000, 0xC1800000, 0xC000082C, 0xC9840030, + 0x59540002, 0xC0004848, 0xCD440000, 0x58880002, 0xB4980540, 0x00000000, 0xC0800000, 0x80000530, + 0xC000487C, 0xC8040000, 0x00000000, 0x00000000, 0x40080000, 0xCBC00000, 0xC4280000, 0x00000000, + 0xA7C00110, 0xC000484C, 0xCA040000, 0xC2400000, 0xC0001AEC, 0xCA440020, 0x5A200002, 0xC000484C, + 0xCE040000, 0xB624006A, 0xC6800000, 0xC13C0002, 0xCD001E08, 0xC0004848, 0xC9440000, 0xC1800000, + 0xC000082C, 0xC9840030, 0x59540002, 0xC0004848, 0xCD440000, 0x58880002, 0xB4980430, 0x00000000, + 0xC0800000, 0x80000420, 0xC0004854, 0xC1000004, 0xCD040000, 0xC0000820, 0xC2000002, 0xCE040000, + 0xC2000000, 0xC000484C, 0xCE040000, 0xC0004858, 0xCE040000, 0x8000FF10, 0xC0004854, 0xC1000000, + 0xCD040000, 0xC11C0000, 0xC000082C, 0xCD040E08, 0x99005348, 0xC0004848, 0xC9440000, 0xC1800000, + 0xC1200000, 0xC0000818, 0xCD041008, 0xC11C0002, 0xC000082C, 0xCD040E08, 0xC2000000, 0xC000484C, + 0xCE040000, 0x80000320, 0xC0001AC0, 0xCB840000, 0xC000487C, 0xC8040000, 0x00000000, 0x00000000, + 0x40080000, 0xCBC00000, 0xC4280000, 0x00000000, 0xA780022A, 0x00000000, 0x00000000, 0xA7C001EA, + 0x00000000, 0xC0001B00, 0xC2060006, 0xCE040310, 0xA7E801A2, 0x00000000, 0xC0004850, 0xCA040000, + 0xC2400000, 0xC0001AEC, 0xCA448020, 0x5A200002, 0xC0004850, 0xCE040000, 0xB624008A, 0x00000000, + 0xC6800000, 0xC13C0002, 0xCD001E08, 0xC0001ACC, 0xC2000002, 0xCE040008, 0xC0004848, 0xC9440000, + 0xC1800000, 0xC000082C, 0xC9840030, 0x59540002, 0xC0004848, 0xCD440000, 0x58880002, 0xB49801A8, + 0x00000000, 0xC0800000, 0x80000198, 0xC0004854, 0xC1000000, 0xCD040000, 0xC11C0000, 0xC000082C, + 0xCD040E08, 0x99005348, 0xC0004848, 0xC9440000, 0xC1800000, 0xC2000000, 0xC0000820, 0xCE040000, + 0xC1200000, 0xC0000818, 0xCD041008, 0xC11C0002, 0xC000082C, 0xCD040E08, 0xC0004850, 0xCE040000, + 0xC2000002, 0xC0001ACC, 0xCE040010, 0x800000D0, 0xC2000002, 0xC0004850, 0xCE040000, 0x8000FE70, + 0xC2000000, 0xC0004850, 0xCE040000, 0xA7E60012, 0x00000000, 0xC2000002, 0xC0001B00, 0xCE040008, + 0x8000FE58, 0x00000000, 0xA7860032, 0x00000000, 0xC6800000, 0xC13C0002, 0xCD001E08, 0xC2020002, + 0xC7E2A548, 0xC0001B00, 0xCE040000, 0x8000FE00, 0xC2040002, 0xC0001B00, 0xCE040208, 0x8000FDE0, + 0xC2C80002, 0x6AC56000, 0xDACC0000, 0xC0004854, 0xCB440000, 0xC0004848, 0xCB840000, 0xC0000838, + 0xC3C00000, 0xCBC40030, 0x5EF40004, 0x8400000A, 0xC3000000, 0xC0001ACC, 0xCF040108, 0x47BD8000, + 0x84000012, 0x47BD8000, 0x88000018, 0xC1006E8C, 0x8000B908, 0xC0004840, 0xCC840000, 0x8000F6B8, + 0xC0001AC0, 0xCAC40000, 0xC0004854, 0xCB440000, 0xA6C0FBD2, 0x00000000, 0x5EF40000, 0x8400F712, + 0x5EF40002, 0x8400F9A2, 0x5EF40004, 0x8400FBA2, 0xC1006CE8, 0x8000B880, 0x00000000, 0xC0800000, + 0xDF4B0040, 0xC0004900, 0xCB800000, 0xC2000000, 0xC000490A, 0xA78000B0, 0xCBC00000, 0xC1000000, + 0xD9000001, 0xC1000002, 0xD90C0000, 0x6FF46000, 0x47F5A000, 0x5B744C80, 0xC2400000, 0x58340004, + 0xCA400080, 0xC0004900, 0xCE000008, 0x5A640002, 0x58340004, 0xC6500080, 0xCD000080, 0xC0004914, + 0xCA400000, 0xC2000002, 0x6A3D0000, 0x72252000, 0xCE400000, 0xC0000408, 0xCE000000, 0xA78200B8, + 0xC0004908, 0xCBC00000, 0xC1000000, 0xD9000001, 0xC1000002, 0xD90C0000, 0x6FF4A000, 0x6FD44000, + 0x4575A000, 0x47F5A000, 0x5B744E20, 0xC2800000, 0x58340006, 0xCA800080, 0xC2000000, 0xC0004900, + 0xCE000108, 0x5EA80002, 0x58340006, 0xC6900080, 0xCD000080, 0x5A7C0020, 0xC2000002, 0x6A250000, + 0xC0000408, 0xCE000000, 0xDCA80001, 0x5EA80000, 0x8400B6F0, 0x00000000, 0xA4800210, 0x00000000, + 0xC3C00000, 0xC000140E, 0xCBC00020, 0xC3400000, 0xC2400000, 0x6FF86000, 0x47F9C000, 0x5BB84C80, + 0x58380008, 0xCB400080, 0x58380006, 0xCA400080, 0x5F740002, 0x58380008, 0xC7500080, 0xCD000080, + 0xC2000000, 0x58380004, 0xCA020080, 0xC3000000, 0x5838000C, 0xCB000028, 0x5A640002, 0x46250000, + 0x8400FFF8, 0xC2400000, 0x58380006, 0xC6500080, 0xCD000080, 0xC2000000, 0x5838000A, 0xCA020080, + 0x5B300002, 0x5838000C, 0xC7100028, 0xCD000028, 0xC2420020, 0x5A200004, 0x46612000, 0x8400FFF8, + 0xC2000000, 0x5838000A, 0xC6101080, 0xCD001080, 0xC0004966, 0xCA400000, 0xC2000002, 0x6A3D0000, + 0x72252000, 0xCE400000, 0x5F740000, 0x84000028, 0xC0004912, 0xCA000000, 0xC2C00002, 0x6AFD6000, + 0x7EC16000, 0x76E10000, 0xCE000000, 0x5F300020, 0x84000028, 0xC0004924, 0xCA000000, 0xC2C00002, + 0x6AFD6000, 0x7EC16000, 0x76E10000, 0xCE000000, 0xA4820050, 0xC2400000, 0xC000140E, 0xCA408020, + 0xC2000002, 0xC0004900, 0xCE000008, 0xC000490A, 0xCE400000, 0xC1000000, 0xD9000001, 0xD8400080, + 0xC1000004, 0xD9000001, 0xA4840288, 0x00000000, 0xC3C00000, 0xC000140E, 0xCBC10020, 0xC2800000, + 0xC2000000, 0x6FF8A000, 0x6FD44000, 0x4579C000, 0x47F9C000, 0x5BB84E20, 0x5838002E, 0xCA800080, + 0x58380006, 0xCA020080, 0xC3400000, 0x5838002E, 0xCB420080, 0x5AA80002, 0x46290000, 0x8400FFF8, + 0xC2800000, 0x5838002E, 0xC6900080, 0xCD000080, 0x5F740002, 0x5838002E, 0xC7501080, 0xCD001080, + 0xC0004968, 0xCA400000, 0xC2000002, 0x6A3D0000, 0x72252000, 0xCE400000, 0xC000492A, 0xCA800000, + 0x5E740000, 0x84000028, 0xC0004910, 0xCA000000, 0xC2C00002, 0x6AFD6000, 0x7EC16000, 0x76E10000, + 0xCE000000, 0x6ABD4010, 0xA68000D2, 0x00000000, 0xC0004910, 0xCA000000, 0xC2C00002, 0x6AFD6000, + 0x7EC16000, 0x76E10000, 0xCE000000, 0x58380032, 0xCA000000, 0x58000002, 0xCA400000, 0x5838000C, + 0x00000000, 0xCE000001, 0xCE400000, 0xC000492A, 0xCA000000, 0xC2C00002, 0x6AFD6000, 0x72E10000, + 0xCE000000, 0xC000492C, 0xCA000000, 0xC2C00002, 0x6AFD6000, 0x72E10000, 0xCE000000, 0x80000028, + 0xC000492C, 0xCA000000, 0xC2C00002, 0x6AFD6000, 0x7EC16000, 0x76E10000, 0xCE000000, 0xA4880100, + 0xC2C00000, 0xC000140E, 0xCAC20020, 0xC000490E, 0xCA400000, 0xC2000002, 0x6A2D0000, 0x7E010000, + 0x76252000, 0xCE400000, 0xC000496A, 0xCA400000, 0xC2000002, 0x6A2D0000, 0x72252000, 0xCE400000, + 0x6EF0A000, 0x6ED44000, 0x45718000, 0x46F18000, 0x5B304E20, 0x58300000, 0xCA000000, 0x00000000, + 0xC2400002, 0x76252000, 0x84000032, 0xC24C0002, 0xC6E40020, 0xC624C408, 0x58300010, 0xCA400508, + 0x00000000, 0xC0001800, 0xCE400000, 0xA4860050, 0xC2400000, 0xC000140E, 0xCA418020, 0xC2020002, + 0xC0004900, 0xCE000108, 0xC0004908, 0xCE400000, 0xC1000000, 0xD9000001, 0xD8400080, 0xC1000004, + 0xD9000001, 0xC0001408, 0xCC800000, 0xC10E0002, 0xD90C0000, 0x8000EDA8, 0xDFBC0001, 0xC000496E, + 0x99006050, 0xC9400000, 0xC7D80000, 0x00000000, 0xC5700000, 0x5EF00020, 0x88000130, 0x6F346000, + 0x4735A000, 0x5B744C80, 0x58340008, 0xC2400000, 0xCA400080, 0x00000000, 0xC2000000, 0x5A640002, + 0xCE400080, 0x58340004, 0xCA000080, 0x00000000, 0x00000000, 0x5E200002, 0xCE000080, 0xC0004912, + 0xCA800000, 0xC2400002, 0x6A712000, 0x72694000, 0xCE800000, 0x5E200000, 0x8400003A, 0xC000480A, + 0xCA000000, 0xC0000408, 0xCA800000, 0x76610000, 0x00000000, 0x72294000, 0xCE800000, 0x80000020, + 0xC0004914, 0xCA000000, 0x7E412000, 0x00000000, 0x76610000, 0xCE000000, 0x800000B8, 0x6EF4A000, + 0x6ED44000, 0x4575A000, 0x46F5A000, 0x5B744E20, 0x5834002E, 0xC2400000, 0xCA420080, 0x00000000, + 0xC2000000, 0x5A640002, 0xC6501080, 0xCD001080, 0x58340006, 0xCA000080, 0x00000000, 0x00000000, + 0x5A200002, 0xCE000080, 0xC0004910, 0xCA400000, 0xC2000002, 0x6A2D0000, 0x72252000, 0xCE400000, + 0xC2000002, 0x6A310000, 0xC000042A, 0xCE000000, 0xC1040002, 0xD90C0000, 0x00000000, 0x8000EB18, + 0x00000000, 0xC4980930, 0x9D000000, 0xC5580030, 0xC0000838, 0xCD840000, 0xC1440200, 0xC1C03200, + 0xC55C1078, 0xC000100E, 0x9D000000, 0xCD800000, 0xC000100C, 0xCDC00000, 0xC0004862, 0xC9C00000, + 0x00000000, 0x00000000, 0xD9D80001, 0xC0007200, 0x401C0000, 0x5DC07400, 0x8800FFFA, 0x5C000200, + 0xCD800000, 0xC1F0000A, 0x71D4A000, 0xDD980000, 0xDD9C0001, 0x41D8E000, 0xC5D40268, 0xC0001010, + 0xCD400000, 0x6C9C8000, 0x449CE000, 0x449CE000, 0x59DC0004, 0xC1601260, 0xC5D40268, 0x9D000000, + 0xC0001012, 0xCD400000, 0x00000000, 0x00000000, 0xD9580000, 0x6D586000, 0x4558C000, 0x59984C80, + 0xD9980001, 0x5818000A, 0xC1800000, 0xC9800080, 0xC0005400, 0x6D5CA000, 0x401C0000, 0x40180000, + 0xC9400000, 0x58000002, 0x00000000, 0xC9C00000, 0xC0004930, 0xCD400000, 0xC0004932, 0xCDC00000, + 0x59980004, 0xC1C20020, 0xB59CFFF8, 0x00000000, 0xC1800000, 0xDD9C0001, 0x581C000A, 0xCD800080, + 0x581C000C, 0xC1800000, 0xC9800028, 0xC1C00002, 0xDD940000, 0x69D4E000, 0x5D980002, 0xCD800028, + 0xC0004924, 0xC9800000, 0x00000000, 0x9D000000, 0x00000000, 0x71D8C000, 0xCD800000, 0xC000492A, + 0xC9400000, 0xC1C00002, 0x69D8E000, 0x7DC0C000, 0x7594A000, 0xCD400000, 0xC000492C, 0xC9400000, + 0xDD800001, 0x58000032, 0x75D4A000, 0x84000078, 0xC9400001, 0xC9800000, 0xDD800001, 0x5800000C, + 0x00000000, 0xCD400001, 0xCD800000, 0xC000492C, 0xC9400000, 0xC000492A, 0xC9800000, 0x71D4A000, + 0xC000492C, 0xCD400000, 0x71D8C000, 0xC000492A, 0xCD800000, 0x9D000000, 0x00000000, 0x00000000, + 0x00000000, 0xC0004862, 0xC9800000, 0x00000000, 0xC1C00200, 0x4194C000, 0x45D8E000, 0x8800FFFA, + 0xC5D80000, 0xC0004862, 0xCD800000, 0xC0001406, 0xC9800000, 0xC1C00002, 0x9D000000, 0xC5D80A08, + 0xC5581050, 0xCD800000, 0xC0004930, 0xC9800000, 0xC0004932, 0xC9C00000, 0xC140000E, 0xC5581C20, + 0xDD940000, 0xC0007200, 0x40140000, 0x5D407400, 0x8800FFFA, 0x5C000200, 0xCD800000, 0x58000002, + 0x5D407400, 0x8800FFFA, 0x5C000200, 0xCDC00000, 0xDD540000, 0xC1C00000, 0x58140006, 0xC9C20080, + 0xC1800000, 0x58140000, 0xC98000E0, 0x6DDC2000, 0xC000491E, 0x41D8E000, 0xCDC00000, 0xDD980000, + 0xC1C00022, 0xC5D80D78, 0xDD940001, 0xC5581C20, 0xC000491C, 0xCD800000, 0xDD540000, 0xC1C00000, + 0x58140006, 0xC9C20080, 0xC1800000, 0x58140004, 0xC9820080, 0x00000000, 0x59DC0002, 0x459CC000, + 0x8400FFF8, 0xC1C00000, 0x9D000000, 0x58140006, 0xC5D81080, 0xCD801080, 0xC0004860, 0xC9400000, + 0xC1800100, 0xC1D00002, 0x58146B00, 0xD5800000, 0x58000002, 0xD5800001, 0x59540004, 0xB558FFF8, + 0xC0004860, 0xC1400000, 0xCD400000, 0xDD980001, 0x9D000000, 0xDD940000, 0xC0001404, 0xCDC00808, + 0xC1C00000, 0xC1800200, 0x5D980004, 0xDF5D0050, 0x45D8A000, 0x8800FFDA, 0xDD800001, 0x5800000C, + 0x00000000, 0xC9400001, 0xC9800000, 0xC1C00002, 0xC5D43F08, 0xC5D81E08, 0xC0004862, 0xC9C00000, + 0x00000000, 0x00000000, 0x581C7200, 0x5DC07400, 0x8800FFFA, 0x5C000200, 0xCD400000, 0x58000002, + 0x5DC07400, 0x8800FFFA, 0x5C000200, 0xCD800000, 0xC0004862, 0xC9C00000, 0x00000000, 0xC15004C0, + 0xC5D40068, 0xDD9C0000, 0xC5D41C20, 0xC1C00000, 0xDD800001, 0x58000030, 0xC9C00080, 0xDD800001, + 0x58000002, 0xC9800000, 0x6DDC2000, 0xC000491C, 0x41D8E000, 0xCD400001, 0xCDC00000, 0xDD940001, + 0xC1C00000, 0x58140030, 0xC9C00080, 0xC1800000, 0x58140006, 0xC9820080, 0x00000000, 0x59DC0002, + 0x459CC000, 0x8400FFF8, 0xC1C00000, 0x9D000000, 0x58140030, 0xC5D80080, 0xCD800080, 0xC1C00000, + 0xDF5C0040, 0x5DDC0080, 0x8400FFD2, 0x00000000, 0x9D000000, 0x00000000, 0x00000000, 0x00000000, + 0xC160FFFE, 0xC0000A10, 0xC9440068, 0xC1A0FFFE, 0x59980E28, 0xC000100C, 0xCD400000, 0xC000100E, + 0xCD800000, 0xC0004964, 0xC9800000, 0x00000000, 0xC170000A, 0x7194A000, 0x6C988000, 0x4498C000, + 0x4498C000, 0x59980004, 0xC5940278, 0xC0001010, 0xCD400000, 0xC0004946, 0xC9400000, 0x00000000, + 0x00000000, 0x6D58A000, 0x6D5C4000, 0x45D8C000, 0x4558C000, 0xC000494A, 0xC9400000, 0xC0004948, + 0xC9C00000, 0x4194C000, 0xC1400012, 0xC55C1820, 0x9D000000, 0xC59C0270, 0xC0001012, 0xCDC00000, + 0xC1400000, 0x58000012, 0xC9410040, 0xC0004950, 0xC9C00000, 0xC5580000, 0xC5940840, 0xC5581080, + 0xD9940000, 0xC000493C, 0xC9400000, 0xC0004954, 0xC9800000, 0x59DC00A8, 0x455CE000, 0x41D8E000, + 0x5D5C0030, 0x8800FFF8, 0xC1C00030, 0xC1800000, 0xC5D84030, 0xC1400000, 0xC5D40010, 0x5DD40002, + 0x8400005A, 0x5DD40004, 0x84000082, 0x5DD40006, 0x840000AA, 0x5DD80026, 0x840000D2, 0xDD540000, + 0xDD800001, 0x58000008, 0x40180000, 0xCD400000, 0x59980002, 0x8000FFA8, 0xDD540000, 0xDD800001, + 0x58000008, 0x40180000, 0xCD4000C0, 0x59980002, 0x8000FF70, 0xDD540000, 0xDD800001, 0x58000008, + 0x40180000, 0xCD400080, 0x59980002, 0x8000FF38, 0xDD540000, 0xDD800001, 0x58000008, 0x40180000, + 0xCD400040, 0x59980002, 0x8000FF00, 0x00000000, 0x9D000000, 0x00000000, 0x00000000, 0x00000000, + 0x58000012, 0xC9400000, 0xC0004954, 0xC9C00000, 0xC0004950, 0xC9400080, 0xDD800001, 0x58000028, + 0x5D9C0000, 0x8400003A, 0x5D9C0002, 0x8400003A, 0x5D9C0004, 0x84000052, 0xC55B0040, 0xC55C08C0, + 0xCD800041, 0xCDC008C0, 0x80000048, 0xCD400000, 0x80000038, 0xC55900C0, 0xC55C1840, 0xCD8000C1, + 0xCDC01840, 0x80000010, 0xC55A0080, 0xC55C1080, 0xCD800081, 0xCDC01080, 0x9D000000, 0x00000000, + 0x00000000, 0x00000000, 0x59540002, 0x6994E018, 0x61C0C008, 0x4194A000, 0x5D940040, 0x8800FFFA, + 0xC5940000, 0x9D000000, 0xCD400000, 0x00000000, 0x00000000, 0x9D000000, 0x4158A000, 0xCD400000, + 0x00000000, +}; + +static u32 firmware_binary_data[] = { +}; + + +#endif // __DANUBE_PPE_FW_H__2005_08_04__12_00__ + diff --git a/package/ifxmips-atm/src/irq.c b/package/ifxmips-atm/src/irq.c new file mode 100644 index 0000000000..02651686b9 --- /dev/null +++ b/package/ifxmips-atm/src/irq.c @@ -0,0 +1,506 @@ +#include <linux/atmdev.h> +#include <linux/irq.h> + +#include "common.h" + +void mailbox_signal(unsigned int channel, int is_tx) +{ + if(is_tx) + { + while(MBOX_IGU3_ISR_ISR(channel + 16)); + *MBOX_IGU3_ISRS = MBOX_IGU3_ISRS_SET(channel + 16); + } else { + while(MBOX_IGU3_ISR_ISR(channel)); + *MBOX_IGU3_ISRS = MBOX_IGU3_ISRS_SET(channel); + } +} + +static int mailbox_rx_irq_handler(unsigned int channel, unsigned int *len) +{ + int conn; + int skb_base; + register struct rx_descriptor reg_desc; + struct rx_descriptor *desc; + struct sk_buff *skb; + struct atm_vcc *vcc; + struct rx_inband_trailer *trailer; + + /* get sk_buff pointer and descriptor */ + skb_base = ppe_dev.dma.rx_descriptor_number * channel + ppe_dev.dma.rx_desc_read_pos[channel]; + desc = &ppe_dev.dma.rx_descriptor_base[skb_base]; + reg_desc = *desc; + if ( reg_desc.own || !reg_desc.c ) + return -EAGAIN; + + if ( ++ppe_dev.dma.rx_desc_read_pos[channel] == ppe_dev.dma.rx_descriptor_number ) + ppe_dev.dma.rx_desc_read_pos[channel] = 0; + + skb = *(struct sk_buff **)((((u32)reg_desc.dataptr << 2) | KSEG0) - 4); + if ( (u32)skb <= 0x80000000 ) + { + int key = 0; + printk("skb problem: skb = %08X, system is panic!\n", (u32)skb); + for ( ; !key; ); + } + + conn = reg_desc.id; + + if ( conn == ppe_dev.oam_rx_queue ) + { + /* OAM */ + struct uni_cell_header *header = (struct uni_cell_header *)skb->data; + + if ( header->pti == ATM_PTI_SEGF5 || header->pti == ATM_PTI_E2EF5 ) + conn = find_vpivci(header->vpi, header->vci); + else if ( header->vci == 0x03 || header->vci == 0x04 ) + conn = find_vpi(header->vpi); + else + conn = -1; + + if ( conn >= 0 && ppe_dev.connection[conn].vcc != NULL ) + { + vcc = ppe_dev.connection[conn].vcc; + ppe_dev.connection[conn].access_time = xtime; + if ( vcc->push_oam != NULL ) + vcc->push_oam(vcc, skb->data); + } + + /* don't need resize */ + } + else + { + if ( len ) + *len = 0; + + if ( ppe_dev.connection[conn].vcc != NULL ) + { + vcc = ppe_dev.connection[conn].vcc; + + if ( !reg_desc.err ) + if ( vcc->qos.aal == ATM_AAL5 ) + { + /* AAL5 packet */ + resize_skb_rx(skb, reg_desc.datalen + reg_desc.byteoff, 0); + skb_reserve(skb, reg_desc.byteoff); + skb_put(skb, reg_desc.datalen); + + if ( (u32)ATM_SKB(skb) <= 0x80000000 ) + { + int key = 0; + printk("ATM_SKB(skb) problem: ATM_SKB(skb) = %08X, system is panic!\n", (u32)ATM_SKB(skb)); + for ( ; !key; ); + } + ATM_SKB(skb)->vcc = vcc; + ppe_dev.connection[conn].access_time = xtime; + if ( atm_charge(vcc, skb->truesize) ) + { + struct sk_buff *new_skb; + + new_skb = alloc_skb_rx(); + if ( new_skb ) + { + + UPDATE_VCC_STAT(conn, rx_pdu, 1); + + ppe_dev.mib.wrx_pdu++; + if ( vcc->stats ) + atomic_inc(&vcc->stats->rx); + vcc->push(vcc, skb); + { + struct k_atm_aal_stats stats = *vcc->stats; + int flag = 0; + + vcc->push(vcc, skb); + if ( vcc->stats->rx.counter != stats.rx.counter ) + { + printk("vcc->stats->rx (diff) = %d", vcc->stats->rx.counter - stats.rx.counter); + flag++; + } + if ( vcc->stats->rx_err.counter != stats.rx_err.counter ) + { + printk("vcc->stats->rx_err (diff) = %d", vcc->stats->rx_err.counter - stats.rx_err.counter); + flag++; + } + if ( vcc->stats->rx_drop.counter != stats.rx_drop.counter ) + { + printk("vcc->stats->rx_drop (diff) = %d", vcc->stats->rx_drop.counter - stats.rx_drop.counter); + flag++; + } + if ( vcc->stats->tx.counter != stats.tx.counter ) + { + printk("vcc->stats->tx (diff) = %d", vcc->stats->tx.counter - stats.tx.counter); + flag++; + } + if ( vcc->stats->tx_err.counter != stats.tx_err.counter ) + { + printk("vcc->stats->tx_err (diff) = %d", vcc->stats->tx_err.counter - stats.tx_err.counter); + flag++; + } + if ( !flag ) + printk("vcc->stats not changed"); + } + reg_desc.dataptr = (u32)new_skb->data >> 2; + + if ( len ) + *len = reg_desc.datalen; + } + else + { + /* no sk buffer */ + UPDATE_VCC_STAT(conn, rx_sw_drop_pdu, 1); + + ppe_dev.mib.wrx_drop_pdu++; + if ( vcc->stats ) + atomic_inc(&vcc->stats->rx_drop); + + resize_skb_rx(skb, ppe_dev.aal5.rx_buffer_size, 0); + } + } + else + { + /* no enough space */ + UPDATE_VCC_STAT(conn, rx_sw_drop_pdu, 1); + + ppe_dev.mib.wrx_drop_pdu++; + if ( vcc->stats ) + atomic_inc(&vcc->stats->rx_drop); + + resize_skb_rx(skb, ppe_dev.aal5.rx_buffer_size, 0); + } + } + else + { + /* AAL0 cell */ + resize_skb_rx(skb, CELL_SIZE, 1); + skb_put(skb, CELL_SIZE); + + ATM_SKB(skb)->vcc = vcc; + ppe_dev.connection[conn].access_time = xtime; + if ( atm_charge(vcc, skb->truesize) ) + { + struct sk_buff *new_skb; + + new_skb = alloc_skb_rx(); + if ( new_skb ) + { + if ( vcc->stats ) + atomic_inc(&vcc->stats->rx); + vcc->push(vcc, skb); + reg_desc.dataptr = (u32)new_skb->data >> 2; + + if ( len ) + *len = CELL_SIZE; + } + else + { + if ( vcc->stats ) + atomic_inc(&vcc->stats->rx_drop); + resize_skb_rx(skb, ppe_dev.aal5.rx_buffer_size, 0); + } + } + else + { + if ( vcc->stats ) + atomic_inc(&vcc->stats->rx_drop); + resize_skb_rx(skb, ppe_dev.aal5.rx_buffer_size, 0); + } + } + else + { +printk("reg_desc.err\n"); + + /* drop packet/cell */ + if ( vcc->qos.aal == ATM_AAL5 ) + { + UPDATE_VCC_STAT(conn, rx_err_pdu, 1); + + trailer = (struct rx_inband_trailer *)((u32)skb->data + ((reg_desc.byteoff + reg_desc.datalen + DMA_ALIGNMENT - 1) & ~ (DMA_ALIGNMENT - 1))); + if ( trailer->stw_crc ) + ppe_dev.connection[conn].aal5_vcc_crc_err++; + if ( trailer->stw_ovz ) + ppe_dev.connection[conn].aal5_vcc_oversize_sdu++; + } + if ( vcc->stats ) + atomic_inc(&vcc->stats->rx_err); + /* don't need resize */ + } + } + else + { +printk("ppe_dev.connection[%d].vcc == NULL\n", conn); + + ppe_dev.mib.wrx_drop_pdu++; + + /* don't need resize */ + } + } + + reg_desc.byteoff = 0; + reg_desc.datalen = ppe_dev.aal5.rx_buffer_size; + reg_desc.own = 1; + reg_desc.c = 0; + + /* write discriptor to memory */ + *desc = reg_desc; + +printk("leave mailbox_rx_irq_handler"); + + return 0; +} + +static inline void mailbox_tx_irq_handler(unsigned int conn) +{ + if ( ppe_dev.dma.tx_desc_alloc_flag[conn] ) + { + int desc_base; + int *release_pos; + struct sk_buff *skb; + + release_pos = &ppe_dev.dma.tx_desc_release_pos[conn]; + desc_base = ppe_dev.dma.tx_descriptor_number * (conn - QSB_QUEUE_NUMBER_BASE) + *release_pos; + while ( !ppe_dev.dma.tx_descriptor_base[desc_base].own ) + { + skb = ppe_dev.dma.tx_skb_pointers[desc_base]; + + ppe_dev.dma.tx_descriptor_base[desc_base].own = 1; // pretend PP32 hold owner bit, so that won't be released more than once, so allocation process don't check this bit + + if ( ++*release_pos == ppe_dev.dma.tx_descriptor_number ) + *release_pos = 0; + + if ( *release_pos == ppe_dev.dma.tx_desc_alloc_pos[conn] ) + { + ppe_dev.dma.tx_desc_alloc_flag[conn] = 0; + + atm_free_tx_skb_vcc(skb); + break; + } + + if ( *release_pos == 0 ) + desc_base = ppe_dev.dma.tx_descriptor_number * (conn - QSB_QUEUE_NUMBER_BASE); + else + desc_base++; + + atm_free_tx_skb_vcc(skb); + } + } +} + +#if defined(ENABLE_RX_QOS) && ENABLE_RX_QOS +static inline int check_desc_valid(unsigned int channel) +{ + int skb_base; + struct rx_descriptor *desc; + + skb_base = ppe_dev.dma.rx_descriptor_number * channel + ppe_dev.dma.rx_desc_read_pos[channel]; + desc = &ppe_dev.dma.rx_descriptor_base[skb_base]; + return !desc->own && desc->c ? 1 : 0; +} +#endif + +irqreturn_t mailbox_irq_handler(int irq, void *dev_id) +{ + int channel_mask; /* DMA channel accordant IRQ bit mask */ + int channel; + unsigned int rx_irq_number[MAX_RX_DMA_CHANNEL_NUMBER] = {0}; + unsigned int total_rx_irq_number = 0; + +printk("mailbox_irq_handler"); + + if ( !*MBOX_IGU1_ISR ) + return IRQ_RETVAL(1); + + channel_mask = 1; + channel = 0; + while ( channel < ppe_dev.dma.rx_total_channel_used ) + { + if ( (*MBOX_IGU1_ISR & channel_mask) ) + { + /* RX */ + /* clear IRQ */ + *MBOX_IGU1_ISRC = channel_mask; +printk(" RX: *MBOX_IGU1_ISR = 0x%08X\n", *MBOX_IGU1_ISR); + /* wait for mailbox cleared */ + while ( (*MBOX_IGU3_ISR & channel_mask) ); + + /* shadow the number of valid descriptor */ + rx_irq_number[channel] = WRX_DMA_CHANNEL_CONFIG(channel)->vlddes; + + total_rx_irq_number += rx_irq_number[channel]; + +printk("total_rx_irq_number = %d", total_rx_irq_number); +printk("vlddes = %d, rx_irq_number[%d] = %d, total_rx_irq_number = %d\n", WRX_DMA_CHANNEL_CONFIG(channel)->vlddes, channel, rx_irq_number[channel], total_rx_irq_number); + } + + channel_mask <<= 1; + channel++; + } + + channel_mask = 1 << (16 + QSB_QUEUE_NUMBER_BASE); + channel = QSB_QUEUE_NUMBER_BASE; + while ( channel - QSB_QUEUE_NUMBER_BASE < ppe_dev.dma.tx_total_channel_used ) + { + if ( (*MBOX_IGU1_ISR & channel_mask) ) + { +// if ( channel != 1 ) +// { +printk("TX irq error\n"); +// while ( 1 ) +// { +// } +// } + /* TX */ + /* clear IRQ */ + *MBOX_IGU1_ISRC = channel_mask; +printk(" TX: *MBOX_IGU1_ISR = 0x%08X\n", *MBOX_IGU1_ISR); + mailbox_tx_irq_handler(channel); + } + + channel_mask <<= 1; + channel++; + } + + #if defined(ENABLE_RX_QOS) && ENABLE_RX_QOS + channel = 0; + while ( total_rx_irq_number ) + { + switch ( channel ) + { + case RX_DMA_CH_CBR: + case RX_DMA_CH_OAM: + /* handle it as soon as possible */ + while ( rx_irq_number[channel] != 0 && mailbox_rx_irq_handler(channel, NULL) == 0 ) + { + rx_irq_number[channel]--; + total_rx_irq_number--; +printk("RX_DMA_CH_CBR, total_rx_irq_number = %d", total_rx_irq_number); +printk("RX_DMA_CH_CBR, total_rx_irq_number = %d, rx_irq_number[%d] = %d\n", total_rx_irq_number, channel, rx_irq_number[channel]); + /* signal firmware that descriptor is updated */ + mailbox_signal(channel, 0); + } +// if ( rx_irq_number[channel] != 0 ) +printk("RX_DMA_CH_CBR, rx_irq_number[channel] = %d", rx_irq_number[channel]); + break; + case RX_DMA_CH_VBR_RT: + /* WFQ */ + if ( rx_irq_number[RX_DMA_CH_VBR_RT] != 0 + && (rx_irq_number[RX_DMA_CH_VBR_NRT] == 0 || !check_desc_valid(RX_DMA_CH_VBR_NRT) || ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT] < ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT]) + && (rx_irq_number[RX_DMA_CH_AVR] == 0 || !check_desc_valid(RX_DMA_CH_AVR) || ppe_dev.dma.rx_weight[RX_DMA_CH_AVR] < ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT]) + ) + { + unsigned int len; + + if ( mailbox_rx_irq_handler(RX_DMA_CH_VBR_RT, &len) == 0 ) + { + rx_irq_number[RX_DMA_CH_VBR_RT]--; + total_rx_irq_number--; +printk("RX_DMA_CH_VBR_RT, total_rx_irq_number = %d", total_rx_irq_number); +printk("RX_DMA_CH_VBR_RT, total_rx_irq_number = %d, rx_irq_number[%d] = %d\n", total_rx_irq_number, channel, rx_irq_number[channel]); + /* signal firmware that descriptor is updated */ + mailbox_signal(channel, 0); + + len = (len + CELL_SIZE - 1) / CELL_SIZE; + if ( ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT] <= len ) + ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT] = ppe_dev.dma.rx_default_weight[RX_DMA_CH_VBR_RT] + ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT] - len; + } + } +// if ( rx_irq_number[channel] != 0 ) +// { +printk("RX_DMA_CH_VBR_RT, rx_irq_number[channel] = %d, total_rx_irq_number = %d", rx_irq_number[channel], total_rx_irq_number); +// rx_irq_number[channel] = 0; +// total_rx_irq_number = 0; +// } + break; + case RX_DMA_CH_VBR_NRT: + /* WFQ */ + if ( rx_irq_number[RX_DMA_CH_VBR_NRT] != 0 + && (rx_irq_number[RX_DMA_CH_VBR_RT] == 0 || !check_desc_valid(RX_DMA_CH_VBR_RT) || ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT] < ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT]) + && (rx_irq_number[RX_DMA_CH_AVR] == 0 || !check_desc_valid(RX_DMA_CH_AVR) || ppe_dev.dma.rx_weight[RX_DMA_CH_AVR] < ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT]) + ) + { + unsigned int len; + + if ( mailbox_rx_irq_handler(RX_DMA_CH_VBR_NRT, &len) == 0 ) + { + rx_irq_number[RX_DMA_CH_VBR_NRT]--; + total_rx_irq_number--; +printk("RX_DMA_CH_VBR_NRT, total_rx_irq_number = %d", total_rx_irq_number); +printk("RX_DMA_CH_VBR_NRT, total_rx_irq_number = %d, rx_irq_number[%d] = %d\n", total_rx_irq_number, channel, rx_irq_number[channel]); + /* signal firmware that descriptor is updated */ + mailbox_signal(channel, 0); + + len = (len + CELL_SIZE - 1) / CELL_SIZE; + if ( ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT] <= len ) + ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT] = ppe_dev.dma.rx_default_weight[RX_DMA_CH_VBR_NRT] + ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT] - len; + } + } +// if ( rx_irq_number[channel] != 0 ) +printk("RX_DMA_CH_VBR_NRT, rx_irq_number[channel] = %d", rx_irq_number[channel]); + break; + case RX_DMA_CH_AVR: + /* WFQ */ + if ( rx_irq_number[RX_DMA_CH_AVR] != 0 + && (rx_irq_number[RX_DMA_CH_VBR_RT] == 0 || !check_desc_valid(RX_DMA_CH_VBR_RT) || ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT] < ppe_dev.dma.rx_weight[RX_DMA_CH_AVR]) + && (rx_irq_number[RX_DMA_CH_VBR_NRT] == 0 || !check_desc_valid(RX_DMA_CH_VBR_NRT) || ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT] < ppe_dev.dma.rx_weight[RX_DMA_CH_AVR]) + ) + { + unsigned int len; + + if ( mailbox_rx_irq_handler(RX_DMA_CH_AVR, &len) == 0 ) + { + rx_irq_number[RX_DMA_CH_AVR]--; + total_rx_irq_number--; +printk("RX_DMA_CH_AVR, total_rx_irq_number = %d", total_rx_irq_number); +printk("RX_DMA_CH_AVR, total_rx_irq_number = %d, rx_irq_number[%d] = %d\n", total_rx_irq_number, channel, rx_irq_number[channel]); + /* signal firmware that descriptor is updated */ + mailbox_signal(channel, 0); + + len = (len + CELL_SIZE - 1) / CELL_SIZE; + if ( ppe_dev.dma.rx_weight[RX_DMA_CH_AVR] <= len ) + ppe_dev.dma.rx_weight[RX_DMA_CH_AVR] = ppe_dev.dma.rx_default_weight[RX_DMA_CH_AVR] + ppe_dev.dma.rx_weight[RX_DMA_CH_AVR] - len; + } + } +// if ( rx_irq_number[channel] != 0 ) +printk("RX_DMA_CH_AVR, rx_irq_number[channel] = %d", rx_irq_number[channel]); + break; + case RX_DMA_CH_UBR: + default: + /* Handle it when all others are handled or others are not available to handle. */ + if ( rx_irq_number[channel] != 0 + && (rx_irq_number[RX_DMA_CH_VBR_RT] == 0 || !check_desc_valid(RX_DMA_CH_VBR_RT)) + && (rx_irq_number[RX_DMA_CH_VBR_NRT] == 0 || !check_desc_valid(RX_DMA_CH_VBR_NRT)) + && (rx_irq_number[RX_DMA_CH_AVR] == 0 || !check_desc_valid(RX_DMA_CH_AVR)) ) + if ( mailbox_rx_irq_handler(channel, NULL) == 0 ) + { + rx_irq_number[channel]--; + total_rx_irq_number--; +printk("RX_DMA_CH_UBR, total_rx_irq_number = %d, rx_irq_number[%d] = %d", total_rx_irq_number, channel, rx_irq_number[channel]); +printk("RX_DMA_CH_UBR, total_rx_irq_number = %d, rx_irq_number[%d] = %d\n", total_rx_irq_number, channel, rx_irq_number[channel]); + /* signal firmware that descriptor is updated */ + mailbox_signal(channel, 0); + } +printk("RX_DMA_CH_UBR, rx_irq_number[channel] = %d", rx_irq_number[channel]); + } + + if ( ++channel == ppe_dev.dma.rx_total_channel_used ) + channel = 0; + } + #else + channel = 0; + while ( total_rx_irq_number ) + { + while ( rx_irq_number[channel] != 0 && mailbox_rx_irq_handler(channel, NULL) == 0 ) + { + rx_irq_number[channel]--; + total_rx_irq_number--; + /* signal firmware that descriptor is updated */ + mailbox_signal(channel, 0); + } + + if ( ++channel == ppe_dev.dma.rx_total_channel_used ) + channel = 0; + } + #endif // defined(ENABLE_RX_QOS) && ENABLE_RX_QOS + return IRQ_RETVAL(1); +} + + diff --git a/package/ifxmips-atm/src/ppe.c b/package/ifxmips-atm/src/ppe.c new file mode 100644 index 0000000000..65e4be9c65 --- /dev/null +++ b/package/ifxmips-atm/src/ppe.c @@ -0,0 +1,838 @@ +#include <asm/mach-ifxmips/cgu.h> +#include "common.h" + +#include "ifx_ppe_fw.h" +static void set_qsb(struct atm_vcc *vcc, struct atm_qos *qos, unsigned int connection) +{ + + u32 qsb_clk = cgu_get_fpi_bus_clock(2); /* FPI configuration 2 (slow FPI bus) */ + union qsb_queue_parameter_table qsb_queue_parameter_table = {{0}}; + union qsb_queue_vbr_parameter_table qsb_queue_vbr_parameter_table = {{0}}; + u32 tmp; + + /* + * Peak Cell Rate (PCR) Limiter + */ + if ( qos->txtp.max_pcr == 0 ) + qsb_queue_parameter_table.bit.tp = 0; /* disable PCR limiter */ + else + { + /* peak cell rate would be slightly lower than requested [maximum_rate / pcr = (qsb_clock / 8) * (time_step / 4) / pcr] */ + tmp = ((qsb_clk * ppe_dev.qsb.tstepc) >> 5) / qos->txtp.max_pcr + 1; + /* check if overflow takes place */ + qsb_queue_parameter_table.bit.tp = tmp > QSB_TP_TS_MAX ? QSB_TP_TS_MAX : tmp; + } + /* + * Weighted Fair Queueing Factor (WFQF) + */ + switch ( qos->txtp.traffic_class ) + { + case ATM_CBR: + case ATM_VBR_RT: + /* real time queue gets weighted fair queueing bypass */ + qsb_queue_parameter_table.bit.wfqf = 0; + break; + case ATM_VBR_NRT: + case ATM_UBR_PLUS: + /* WFQF calculation here is based on virtual cell rates, to reduce granularity for high rates */ + /* WFQF is maximum cell rate / garenteed cell rate */ + /* wfqf = qsb_minimum_cell_rate * QSB_WFQ_NONUBR_MAX / requested_minimum_peak_cell_rate */ + if ( qos->txtp.min_pcr == 0 ) + qsb_queue_parameter_table.bit.wfqf = QSB_WFQ_NONUBR_MAX; + else + { + tmp = QSB_GCR_MIN * QSB_WFQ_NONUBR_MAX / qos->txtp.min_pcr; + if ( tmp == 0 ) + qsb_queue_parameter_table.bit.wfqf = 1; + else if ( tmp > QSB_WFQ_NONUBR_MAX ) + qsb_queue_parameter_table.bit.wfqf = QSB_WFQ_NONUBR_MAX; + else + qsb_queue_parameter_table.bit.wfqf = tmp; + } + break; + default: + case ATM_UBR: + qsb_queue_parameter_table.bit.wfqf = QSB_WFQ_UBR_BYPASS; + } + /* + * Sustained Cell Rate (SCR) Leaky Bucket Shaper VBR.0/VBR.1 + */ + if ( qos->txtp.traffic_class == ATM_VBR_RT || qos->txtp.traffic_class == ATM_VBR_NRT ) + { + if ( qos->txtp.scr == 0 ) + { + /* disable shaper */ + qsb_queue_vbr_parameter_table.bit.taus = 0; + qsb_queue_vbr_parameter_table.bit.ts = 0; + } + else + { + /* Cell Loss Priority (CLP) */ + if ( (vcc->atm_options & ATM_ATMOPT_CLP) ) + /* CLP1 */ + qsb_queue_parameter_table.bit.vbr = 1; + else + /* CLP0 */ + qsb_queue_parameter_table.bit.vbr = 0; + /* Rate Shaper Parameter (TS) and Burst Tolerance Parameter for SCR (tauS) */ + tmp = ((qsb_clk * ppe_dev.qsb.tstepc) >> 5) / qos->txtp.scr + 1; + qsb_queue_vbr_parameter_table.bit.ts = tmp > QSB_TP_TS_MAX ? QSB_TP_TS_MAX : tmp; + tmp = (qos->txtp.mbs - 1) * (qsb_queue_vbr_parameter_table.bit.ts - qsb_queue_parameter_table.bit.tp) / 64; + if ( tmp == 0 ) + qsb_queue_vbr_parameter_table.bit.taus = 1; + else if ( tmp > QSB_TAUS_MAX ) + qsb_queue_vbr_parameter_table.bit.taus = QSB_TAUS_MAX; + else + qsb_queue_vbr_parameter_table.bit.taus = tmp; + } + } + else + { + qsb_queue_vbr_parameter_table.bit.taus = 0; + qsb_queue_vbr_parameter_table.bit.ts = 0; + } + + /* Queue Parameter Table (QPT) */ + *QSB_RTM = QSB_RTM_DM_SET(QSB_QPT_SET_MASK); + *QSB_RTD = QSB_RTD_TTV_SET(qsb_queue_parameter_table.dword); + *QSB_RAMAC = QSB_RAMAC_RW_SET(QSB_RAMAC_RW_WRITE) | QSB_RAMAC_TSEL_SET(QSB_RAMAC_TSEL_QPT) | QSB_RAMAC_LH_SET(QSB_RAMAC_LH_LOW) | QSB_RAMAC_TESEL_SET(connection); + /* Queue VBR Paramter Table (QVPT) */ + *QSB_RTM = QSB_RTM_DM_SET(QSB_QVPT_SET_MASK); + *QSB_RTD = QSB_RTD_TTV_SET(qsb_queue_vbr_parameter_table.dword); + *QSB_RAMAC = QSB_RAMAC_RW_SET(QSB_RAMAC_RW_WRITE) | QSB_RAMAC_TSEL_SET(QSB_RAMAC_TSEL_VBR) | QSB_RAMAC_LH_SET(QSB_RAMAC_LH_LOW) | QSB_RAMAC_TESEL_SET(connection); + +} + + +static inline void u64_add_u32(ppe_u64_t opt1, u32 opt2,ppe_u64_t *ret) +{ + ret->l = opt1.l + opt2; + if ( ret->l < opt1.l || ret->l < opt2 ) + ret->h++; +} + +int find_vcc(struct atm_vcc *vcc) +{ + int i; + struct connection *connection = ppe_dev.connection; + int max_connections = ppe_dev.port[(int)vcc->dev->dev_data].max_connections; + u32 occupation_table = ppe_dev.port[(int)vcc->dev->dev_data].connection_table; + int base = ppe_dev.port[(int)vcc->dev->dev_data].connection_base; + for ( i = 0; i < max_connections; i++, base++ ) + if ( (occupation_table & (1 << i)) + && connection[base].vcc == vcc ) + return base; + return -1; +} + +int find_vpi(unsigned int vpi) +{ + int i, j; + struct connection *connection = ppe_dev.connection; + struct port *port; + int base; + + port = ppe_dev.port; + for ( i = 0; i < ATM_PORT_NUMBER; i++, port++ ) + { + base = port->connection_base; + for ( j = 0; j < port->max_connections; j++, base++ ) + if ( (port->connection_table & (1 << j)) + && connection[base].vcc != NULL + && vpi == connection[base].vcc->vpi ) + return base; + } + return -1; +} + +int find_vpivci(unsigned int vpi, unsigned int vci) +{ + int i, j; + struct connection *connection = ppe_dev.connection; + struct port *port; + int base; + + port = ppe_dev.port; + for ( i = 0; i < ATM_PORT_NUMBER; i++, port++ ) + { + base = port->connection_base; + for ( j = 0; j < port->max_connections; j++, base++ ) + if ( (port->connection_table & (1 << j)) + && connection[base].vcc != NULL + && vpi == connection[base].vcc->vpi + && vci == connection[base].vcc->vci ) + return base; + } + return -1; +} + + +static inline void clear_htu_entry(unsigned int connection) +{ + HTU_ENTRY(connection - QSB_QUEUE_NUMBER_BASE + OAM_HTU_ENTRY_NUMBER)->vld = 0; +} + +static inline void set_htu_entry(unsigned int vpi, unsigned int vci, unsigned int connection, int aal5) +{ + struct htu_entry htu_entry = { res1: 0x00, + pid: ppe_dev.connection[connection].port & 0x01, + vpi: vpi, + vci: vci, + pti: 0x00, + vld: 0x01}; + + struct htu_mask htu_mask = { set: 0x03, + pid_mask: 0x02, + vpi_mask: 0x00, + vci_mask: 0x0000, + pti_mask: 0x03, // 0xx, user data + clear: 0x00}; + + struct htu_result htu_result = {res1: 0x00, + cellid: connection, + res2: 0x00, + type: aal5 ? 0x00 : 0x01, + ven: 0x01, + res3: 0x00, + qid: connection}; + + *HTU_RESULT(connection - QSB_QUEUE_NUMBER_BASE + OAM_HTU_ENTRY_NUMBER) = htu_result; + *HTU_MASK(connection - QSB_QUEUE_NUMBER_BASE + OAM_HTU_ENTRY_NUMBER) = htu_mask; + *HTU_ENTRY(connection - QSB_QUEUE_NUMBER_BASE + OAM_HTU_ENTRY_NUMBER) = htu_entry; +} + +int alloc_tx_connection(int connection) +{ + unsigned long sys_flag; + int desc_base; + + if ( ppe_dev.dma.tx_desc_alloc_pos[connection] == ppe_dev.dma.tx_desc_release_pos[connection] && ppe_dev.dma.tx_desc_alloc_flag[connection] ) + return -1; + + /* amend descriptor pointer and allocation number */ + local_irq_save(sys_flag); + desc_base = ppe_dev.dma.tx_descriptor_number * (connection - QSB_QUEUE_NUMBER_BASE) + ppe_dev.dma.tx_desc_alloc_pos[connection]; + if ( ++ppe_dev.dma.tx_desc_alloc_pos[connection] == ppe_dev.dma.tx_descriptor_number ) + ppe_dev.dma.tx_desc_alloc_pos[connection] = 0; + ppe_dev.dma.tx_desc_alloc_flag[connection] = 1; + local_irq_restore(sys_flag); + + return desc_base; +} + + +int ppe_open(struct atm_vcc *vcc) +{ + int ret; + struct port *port = &ppe_dev.port[(int)vcc->dev->dev_data]; + int conn; + int f_enable_irq = 0; + int i; +printk("%s:%s[%d] removed 2 args from signature\n", __FILE__, __func__, __LINE__); + +printk("ppe_open"); + + if ( vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0 ) + return -EPROTONOSUPPORT; + + down(&ppe_dev.sem); + + /* check bandwidth */ + if ( (vcc->qos.txtp.traffic_class == ATM_CBR && vcc->qos.txtp.max_pcr > (port->tx_max_cell_rate - port->tx_current_cell_rate)) + || (vcc->qos.txtp.traffic_class == ATM_VBR_RT && vcc->qos.txtp.max_pcr > (port->tx_max_cell_rate - port->tx_current_cell_rate)) + || (vcc->qos.txtp.traffic_class == ATM_VBR_NRT && vcc->qos.txtp.pcr > (port->tx_max_cell_rate - port->tx_current_cell_rate)) + || (vcc->qos.txtp.traffic_class == ATM_UBR_PLUS && vcc->qos.txtp.min_pcr > (port->tx_max_cell_rate - port->tx_current_cell_rate)) ) + { + ret = -EINVAL; + goto PPE_OPEN_EXIT; + } + + printk("alloc vpi = %d, vci = %d\n", vcc->vpi, vcc->vci); + + /* check existing vpi,vci */ + conn = find_vpivci(vcc->vpi, vcc->vci); + if ( conn >= 0 ) + { + ret = -EADDRINUSE; + goto PPE_OPEN_EXIT; + } + + /* check whether it need to enable irq */ + for ( i = 0; i < ATM_PORT_NUMBER; i++ ) + if ( ppe_dev.port[i].max_connections != 0 && ppe_dev.port[i].connection_table != 0 ) + break; + if ( i == ATM_PORT_NUMBER ) + f_enable_irq = 1; + + /* allocate connection */ + for ( i = 0, conn = port->connection_base; i < port->max_connections; i++, conn++ ) + if ( !(port->connection_table & (1 << i)) ) + { + port->connection_table |= 1 << i; + ppe_dev.connection[conn].vcc = vcc; + break; + } + if ( i == port->max_connections ) + { + ret = -EINVAL; + goto PPE_OPEN_EXIT; + } + +#if defined(ENABLE_RX_QOS) && ENABLE_RX_QOS + /* assign DMA channel and setup weight value for RX QoS */ + switch ( vcc->qos.rxtp.traffic_class ) + { + case ATM_CBR: + ppe_dev.connection[conn].rx_dma_channel = RX_DMA_CH_CBR; + break; + case ATM_VBR_RT: + ppe_dev.connection[conn].rx_dma_channel = RX_DMA_CH_VBR_RT; + ppe_dev.dma.rx_default_weight[RX_DMA_CH_VBR_RT] += vcc->qos.rxtp.max_pcr; + ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT] += vcc->qos.rxtp.max_pcr; + break; + case ATM_VBR_NRT: + ppe_dev.connection[conn].rx_dma_channel = RX_DMA_CH_VBR_NRT; + ppe_dev.dma.rx_default_weight[RX_DMA_CH_VBR_NRT] += vcc->qos.rxtp.pcr; + ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT] += vcc->qos.rxtp.pcr; + break; + case ATM_ABR: + ppe_dev.connection[conn].rx_dma_channel = RX_DMA_CH_AVR; + ppe_dev.dma.rx_default_weight[RX_DMA_CH_AVR] += vcc->qos.rxtp.min_pcr; + ppe_dev.dma.rx_weight[RX_DMA_CH_AVR] += vcc->qos.rxtp.min_pcr; + break; + case ATM_UBR_PLUS: + default: + ppe_dev.connection[conn].rx_dma_channel = RX_DMA_CH_UBR; + break; + } + + /* update RX queue configuration table */ + WRX_QUEUE_CONFIG(conn)->dmach = ppe_dev.connection[conn].rx_dma_channel; + + printk("ppe_open: QID %d, DMA %d\n", conn, WRX_QUEUE_CONFIG(conn)->dmach); + + printk("conn = %d, dmach = %d", conn, WRX_QUEUE_CONFIG(conn)->dmach); +#endif // defined(ENABLE_RX_QOS) && ENABLE_RX_QOS + + /* reserve bandwidth */ + switch ( vcc->qos.txtp.traffic_class ) + { + case ATM_CBR: + case ATM_VBR_RT: + port->tx_current_cell_rate += vcc->qos.txtp.max_pcr; + break; + case ATM_VBR_NRT: + port->tx_current_cell_rate += vcc->qos.txtp.pcr; + break; + case ATM_UBR_PLUS: + port->tx_current_cell_rate += vcc->qos.txtp.min_pcr; + break; + } + + /* set qsb */ + set_qsb(vcc, &vcc->qos, conn); + + /* update atm_vcc structure */ + vcc->itf = (int)vcc->dev->dev_data; + + set_bit(ATM_VF_READY, &vcc->flags); + + /* enable irq */ + printk("ppe_open: enable_irq\n"); + if ( f_enable_irq ) + enable_irq(IFXMIPS_PPE_MBOX_INT); + + /* enable mailbox */ + *MBOX_IGU1_ISRC = (1 << conn) | (1 << (conn + 16)); + *MBOX_IGU1_IER |= (1 << conn) | (1 << (conn + 16)); + *MBOX_IGU3_ISRC = (1 << conn) | (1 << (conn + 16)); + *MBOX_IGU3_IER |= (1 << conn) | (1 << (conn + 16)); + + /* set htu entry */ + set_htu_entry(vcc->vpi, vcc->vci, conn, vcc->qos.aal == ATM_AAL5 ? 1 : 0); + + ret = 0; + + printk("ppe_open(%d.%d): conn = %d, ppe_dev.dma = %08X\n", vcc->vpi, vcc->vci, conn, (u32)&ppe_dev.dma.rx_descriptor_number); + + +PPE_OPEN_EXIT: + up(&ppe_dev.sem); + + printk("open ATM itf = %d, vpi = %d, vci = %d, ret = %d", (int)vcc->dev->dev_data, (int)vcc->vpi, vcc->vci, ret); + return ret; +} + +void ppe_close(struct atm_vcc *vcc) +{ + int conn; + struct port *port; + struct connection *connection; + int i; + + if ( vcc == NULL ) + return; + + down(&ppe_dev.sem); + + /* get connection id */ + conn = find_vcc(vcc); + if ( conn < 0 ) + { + printk("can't find vcc\n"); + goto PPE_CLOSE_EXIT; + } + if(!((Atm_Priv *)vcc)->on) + goto PPE_CLOSE_EXIT; + connection = &ppe_dev.connection[conn]; + port = &ppe_dev.port[connection->port]; + + /* clear htu */ + clear_htu_entry(conn); + + /* release connection */ + port->connection_table &= ~(1 << (conn - port->connection_base)); + connection->vcc = NULL; + connection->access_time.tv_sec = 0; + connection->access_time.tv_nsec = 0; + connection->aal5_vcc_crc_err = 0; + connection->aal5_vcc_oversize_sdu = 0; + + /* disable irq */ + for ( i = 0; i < ATM_PORT_NUMBER; i++ ) + if ( ppe_dev.port[i].max_connections != 0 && ppe_dev.port[i].connection_table != 0 ) + break; + if ( i == ATM_PORT_NUMBER ) + disable_irq(IFXMIPS_PPE_MBOX_INT); + + *MBOX_IGU1_ISRC = (1 << conn) | (1 << (conn + 16)); + +#if defined(ENABLE_RX_QOS) && ENABLE_RX_QOS + /* remove weight value from RX DMA channel */ + switch ( vcc->qos.rxtp.traffic_class ) + { + case ATM_VBR_RT: + ppe_dev.dma.rx_default_weight[RX_DMA_CH_VBR_RT] -= vcc->qos.rxtp.max_pcr; + if ( ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT] > ppe_dev.dma.rx_default_weight[RX_DMA_CH_VBR_RT] ) + ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT] = ppe_dev.dma.rx_default_weight[RX_DMA_CH_VBR_RT]; + break; + case ATM_VBR_NRT: + ppe_dev.dma.rx_default_weight[RX_DMA_CH_VBR_NRT] -= vcc->qos.rxtp.pcr; + if ( ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT] > ppe_dev.dma.rx_default_weight[RX_DMA_CH_VBR_NRT] ) + ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT] = ppe_dev.dma.rx_default_weight[RX_DMA_CH_VBR_NRT]; + break; + case ATM_ABR: + ppe_dev.dma.rx_default_weight[RX_DMA_CH_AVR] -= vcc->qos.rxtp.min_pcr; + if ( ppe_dev.dma.rx_weight[RX_DMA_CH_AVR] > ppe_dev.dma.rx_default_weight[RX_DMA_CH_AVR] ) + ppe_dev.dma.rx_weight[RX_DMA_CH_AVR] = ppe_dev.dma.rx_default_weight[RX_DMA_CH_AVR]; + break; + case ATM_CBR: + case ATM_UBR_PLUS: + default: + break; + } +#endif // defined(ENABLE_RX_QOS) && ENABLE_RX_QOS + + /* release bandwidth */ + switch ( vcc->qos.txtp.traffic_class ) + { + case ATM_CBR: + case ATM_VBR_RT: + port->tx_current_cell_rate -= vcc->qos.txtp.max_pcr; + break; + case ATM_VBR_NRT: + port->tx_current_cell_rate -= vcc->qos.txtp.pcr; + break; + case ATM_UBR_PLUS: + port->tx_current_cell_rate -= vcc->qos.txtp.min_pcr; + break; + } + + /* idle for a while to let parallel operation finish */ + for ( i = 0; i < IDLE_CYCLE_NUMBER; i++ ); + ((Atm_Priv *)vcc)->on = 0; + +PPE_CLOSE_EXIT: + up(&ppe_dev.sem); +} + +int ppe_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) +{ + return -ENOTTY; +} + +int ppe_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + int ret; + int conn; + int desc_base; + register struct tx_descriptor reg_desc; + struct tx_descriptor *desc; + + +printk("ppe_send"); +printk("ppe_send\n"); +printk("skb->users = %d\n", skb->users.counter); + + if ( vcc == NULL || skb == NULL ) + return -EINVAL; + +// down(&ppe_dev.sem); + + ATM_SKB(skb)->vcc = vcc; + conn = find_vcc(vcc); +// if ( conn != 1 ) +printk("ppe_send: conn = %d\n", conn); + if ( conn < 0 ) + { + ret = -EINVAL; + goto FIND_VCC_FAIL; + } + +printk("find_vcc"); + + if ( vcc->qos.aal == ATM_AAL5 ) + { + int byteoff; + int datalen; + struct tx_inband_header *header; + + /* allocate descriptor */ + desc_base = alloc_tx_connection(conn); + if ( desc_base < 0 ) + { + ret = -EIO; + //goto ALLOC_TX_CONNECTION_FAIL; + } + desc = &ppe_dev.dma.tx_descriptor_base[desc_base]; + + /* load descriptor from memory */ + reg_desc = *desc; + + datalen = skb->len; + byteoff = (u32)skb->data & (DMA_ALIGNMENT - 1); + if ( skb_headroom(skb) < byteoff + TX_INBAND_HEADER_LENGTH ) + { + struct sk_buff *new_skb; + +printk("skb_headroom(skb) < byteoff + TX_INBAND_HEADER_LENGTH"); +printk("skb_headroom(skb 0x%08X, skb->data 0x%08X) (%d) < byteoff (%d) + TX_INBAND_HEADER_LENGTH (%d)\n", (u32)skb, (u32)skb->data, skb_headroom(skb), byteoff, TX_INBAND_HEADER_LENGTH); + + new_skb = alloc_skb_tx(datalen); + if ( new_skb == NULL ) + { + printk("alloc_skb_tx: fail\n"); + ret = -ENOMEM; + goto ALLOC_SKB_TX_FAIL; + } + ATM_SKB(new_skb)->vcc = NULL; + skb_put(new_skb, datalen); + memcpy(new_skb->data, skb->data, datalen); + atm_free_tx_skb_vcc(skb); + skb = new_skb; + byteoff = (u32)skb->data & (DMA_ALIGNMENT - 1); + } + else + { +printk("skb_headroom(skb) >= byteoff + TX_INBAND_HEADER_LENGTH"); + } +printk("before skb_push, skb->data = 0x%08X", (u32)skb->data); + skb_push(skb, byteoff + TX_INBAND_HEADER_LENGTH); +printk("after skb_push, skb->data = 0x%08X", (u32)skb->data); + + header = (struct tx_inband_header *)(u32)skb->data; +printk("header = 0x%08X", (u32)header); + + /* setup inband trailer */ + header->uu = 0; + header->cpi = 0; + header->pad = ppe_dev.aal5.padding_byte; + header->res1 = 0; + + /* setup cell header */ + header->clp = (vcc->atm_options & ATM_ATMOPT_CLP) ? 1 : 0; + header->pti = ATM_PTI_US0; + header->vci = vcc->vci; + header->vpi = vcc->vpi; + header->gfc = 0; + + /* setup descriptor */ + reg_desc.dataptr = (u32)skb->data >> 2; + reg_desc.datalen = datalen; + reg_desc.byteoff = byteoff; + reg_desc.iscell = 0; + +printk("setup header, datalen = %d, byteoff = %d", reg_desc.datalen, reg_desc.byteoff); + + UPDATE_VCC_STAT(conn, tx_pdu, 1); + + if ( vcc->stats ) + atomic_inc(&vcc->stats->tx); + } + else + { + /* allocate descriptor */ + desc_base = alloc_tx_connection(conn); + if ( desc_base < 0 ) + { + ret = -EIO; + goto ALLOC_TX_CONNECTION_FAIL; + } + desc = &ppe_dev.dma.tx_descriptor_base[desc_base]; + + /* load descriptor from memory */ + reg_desc = *desc; + + /* if data pointer is not aligned, allocate new sk_buff */ + if ( ((u32)skb->data & (DMA_ALIGNMENT - 1)) ) + { + struct sk_buff *new_skb; + + printk("skb->data not aligned\n"); + + new_skb = alloc_skb_tx(skb->len); + if ( new_skb == NULL ) + { + ret = -ENOMEM; + goto ALLOC_SKB_TX_FAIL; + } + ATM_SKB(new_skb)->vcc = NULL; + skb_put(new_skb, skb->len); + memcpy(new_skb->data, skb->data, skb->len); + atm_free_tx_skb_vcc(skb); + skb = new_skb; + } + + reg_desc.dataptr = (u32)skb->data >> 2; + reg_desc.datalen = skb->len; + reg_desc.byteoff = 0; + reg_desc.iscell = 1; + + if ( vcc->stats ) + atomic_inc(&vcc->stats->tx); + } + + reg_desc.own = 1; + reg_desc.c = 1; + +printk("update descriptor send pointer, desc = 0x%08X", (u32)desc); + + ppe_dev.dma.tx_skb_pointers[desc_base] = skb; + *desc = reg_desc; + dma_cache_wback((unsigned long)skb->data, skb->len); + + mailbox_signal(conn, 1); + +printk("ppe_send: success"); +// up(&ppe_dev.sem); + + return 0; + +FIND_VCC_FAIL: + printk("FIND_VCC_FAIL\n"); + +// up(&ppe_dev.sem); + ppe_dev.mib.wtx_err_pdu++; + atm_free_tx_skb_vcc(skb); + + return ret; + +ALLOC_SKB_TX_FAIL: + printk("ALLOC_SKB_TX_FAIL\n"); + +// up(&ppe_dev.sem); + if ( vcc->qos.aal == ATM_AAL5 ) + { + UPDATE_VCC_STAT(conn, tx_err_pdu, 1); + ppe_dev.mib.wtx_err_pdu++; + } + if ( vcc->stats ) + atomic_inc(&vcc->stats->tx_err); + atm_free_tx_skb_vcc(skb); + + return ret; + +ALLOC_TX_CONNECTION_FAIL: + printk("ALLOC_TX_CONNECTION_FAIL\n"); + +// up(&ppe_dev.sem); + if ( vcc->qos.aal == ATM_AAL5 ) + { + UPDATE_VCC_STAT(conn, tx_sw_drop_pdu, 1); + ppe_dev.mib.wtx_drop_pdu++; + } + if ( vcc->stats ) + atomic_inc(&vcc->stats->tx_err); + atm_free_tx_skb_vcc(skb); + + return ret; +} + +int ppe_send_oam(struct atm_vcc *vcc, void *cell, int flags) +{ + int conn; + struct uni_cell_header *uni_cell_header = (struct uni_cell_header *)cell; + int desc_base; + struct sk_buff *skb; + register struct tx_descriptor reg_desc; + struct tx_descriptor *desc; + +printk("ppe_send_oam"); + + if ( ((uni_cell_header->pti == ATM_PTI_SEGF5 || uni_cell_header->pti == ATM_PTI_E2EF5) + && find_vpivci(uni_cell_header->vpi, uni_cell_header->vci) < 0) + || ((uni_cell_header->vci == 0x03 || uni_cell_header->vci == 0x04) + && find_vpi(uni_cell_header->vpi) < 0) ) + return -EINVAL; + +#if OAM_TX_QUEUE_NUMBER_PER_PORT != 0 + /* get queue ID of OAM TX queue, and the TX DMA channel ID is the same as queue ID */ + conn = ppe_dev.port[(int)vcc->dev->dev_data].oam_tx_queue; +#else + /* find queue ID */ + conn = find_vcc(vcc); + if ( conn < 0 ) + { + printk("OAM not find queue\n"); +// up(&ppe_dev.sem); + return -EINVAL; + } +#endif // OAM_TX_QUEUE_NUMBER_PER_PORT != 0 + + /* allocate descriptor */ + desc_base = alloc_tx_connection(conn); + if ( desc_base < 0 ) + { + printk("OAM not alloc tx connection\n"); +// up(&ppe_dev.sem); + return -EIO; + } + + desc = &ppe_dev.dma.tx_descriptor_base[desc_base]; + + /* load descriptor from memory */ + reg_desc = *(struct tx_descriptor *)desc; + + /* allocate sk_buff */ + skb = alloc_skb_tx(CELL_SIZE); + if ( skb == NULL ) + { +// up(&ppe_dev.sem); + return -ENOMEM; + } +#if OAM_TX_QUEUE_NUMBER_PER_PORT != 0 + ATM_SKB(skb)->vcc = NULL; +#else + ATM_SKB(skb)->vcc = vcc; +#endif // OAM_TX_QUEUE_NUMBER_PER_PORT != 0 + + /* copy data */ + skb_put(skb, CELL_SIZE); + memcpy(skb->data, cell, CELL_SIZE); + + /* setup descriptor */ + reg_desc.dataptr = (u32)skb->data >> 2; + reg_desc.datalen = CELL_SIZE; + reg_desc.byteoff = 0; + reg_desc.iscell = 1; + reg_desc.own = 1; + reg_desc.c = 1; + + /* update descriptor send pointer */ + ppe_dev.dma.tx_skb_pointers[desc_base] = skb; + + /* write discriptor to memory and write back cache */ + *(struct tx_descriptor *)desc = reg_desc; + dma_cache_wback((unsigned long)skb->data, skb->len); + + /* signal PPE */ + mailbox_signal(conn, 1); + + return 0; +} + +int ppe_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags) +{ + int conn; + printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + + if(vcc == NULL || qos == NULL ) + return -EINVAL; + conn = find_vcc(vcc); + if ( conn < 0 ) + return -EINVAL; + set_qsb(vcc, qos, conn); + + return 0; +} + +static inline void init_chip(void) +{ + /* enable PPE module in PMU */ + *(unsigned long *)0xBF10201C &= ~((1 << 15) | (1 << 13) | (1 << 9)); + + *EMA_CMDCFG = (EMA_CMD_BUF_LEN << 16) | (EMA_CMD_BASE_ADDR >> 2); + *EMA_DATACFG = (EMA_DATA_BUF_LEN << 16) | (EMA_DATA_BASE_ADDR >> 2); + *EMA_IER = 0x000000FF; + *EMA_CFG = EMA_READ_BURST | (EMA_WRITE_BURST << 2); + + /* enable mailbox */ + *MBOX_IGU1_ISRC = 0xFFFFFFFF; + *MBOX_IGU1_IER = 0x00000000; + *MBOX_IGU3_ISRC = 0xFFFFFFFF; + *MBOX_IGU3_IER = 0x00000000; +} + +int pp32_download_code(u32 *code_src, unsigned int code_dword_len, u32 *data_src, unsigned int data_dword_len) +{ + u32 reg_old_value; + volatile u32 *dest; + + if ( code_src == 0 || ((unsigned long)code_src & 0x03) != 0 + || data_src == 0 || ((unsigned long)data_src & 0x03) ) + return -EINVAL; + + /* save the old value of CDM_CFG and set PPE code memory to FPI bus access mode */ + reg_old_value = *CDM_CFG; + if ( code_dword_len <= 4096 ) + *CDM_CFG = CDM_CFG_RAM1_SET(0x00) | CDM_CFG_RAM0_SET(0x00); + else + *CDM_CFG = CDM_CFG_RAM1_SET(0x01) | CDM_CFG_RAM0_SET(0x00); + + /* copy code */ + dest = CDM_CODE_MEMORY_RAM0_ADDR(0); + while ( code_dword_len-- > 0 ) + *dest++ = *code_src++; + + /* copy data */ + dest = PP32_DATA_MEMORY_RAM1_ADDR(0); + while ( data_dword_len-- > 0 ) + *dest++ = *data_src++; + + return 0; +} + +int pp32_start(void) +{ + int ret; + register int i; + init_chip(); + /* download firmware */ + ret = pp32_download_code(firmware_binary_code, sizeof(firmware_binary_code) / sizeof(*firmware_binary_code), firmware_binary_data, sizeof(firmware_binary_data) / sizeof(*firmware_binary_data)); + if ( ret ) + return ret; + + /* run PP32 */ + *PP32_DBG_CTRL = DBG_CTRL_START_SET(1); + + /* idle for a while to let PP32 init itself */ + for ( i = 0; i < IDLE_CYCLE_NUMBER; i++ ); + + return 0; +} + +void pp32_stop(void) +{ + /* halt PP32 */ + *PP32_DBG_CTRL = DBG_CTRL_STOP_SET(1); +} diff --git a/package/ifxmips-atm/src/proc.c b/package/ifxmips-atm/src/proc.c new file mode 100644 index 0000000000..47b8820522 --- /dev/null +++ b/package/ifxmips-atm/src/proc.c @@ -0,0 +1,98 @@ +#include <linux/atm.h> +#include <linux/proc_fs.h> + +#include "proc.h" +#include "common.h" + +struct proc_dir_entry *ppe_proc_dir; + +int proc_read_idle_counter(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = 0; + + len += sprintf(page + off, "Channel 0\n"); + len += sprintf(page + off + len, " TX\n"); + len += sprintf(page + off + len, + " DREG_AT_CELL0 = %d\n", *DREG_AT_CELL0 & 0xFFFF); + len += sprintf(page + off + len, + " DREG_AT_IDLE_CNT0 = %d\n", *DREG_AT_IDLE_CNT0 & 0xFFFF); + len += sprintf(page + off + len, " RX\n"); + len += sprintf(page + off + len, + " DREG_AR_CELL0 = %d\n", *DREG_AR_CELL0 & 0xFFFF); + len += sprintf(page + off + len, + " DREG_AR_IDLE_CNT0 = %d\n", *DREG_AR_IDLE_CNT0 & 0xFFFF); + len += sprintf(page + off + len, + " DREG_AR_AIIDLE_CNT0 = %d\n", *DREG_AR_AIIDLE_CNT0 & 0xFFFF); + len += sprintf(page + off + len, + " DREG_AR_BE_CNT0 = %d\n", *DREG_AR_BE_CNT0 & 0xFFFF); + len += sprintf(page + off + len, "Channel 1\n"); + len += sprintf(page + off + len, " TX\n"); + len += sprintf(page + off + len, + " DREG_AT_CELL1 = %d\n", *DREG_AT_CELL1 & 0xFFFF); + len += sprintf(page + off + len, + " DREG_AT_IDLE_CNT1 = %d\n", *DREG_AT_IDLE_CNT1 & 0xFFFF); + len += sprintf(page + off + len, " RX\n"); + len += sprintf(page + off + len, + " DREG_AR_CELL1 = %d\n", *DREG_AR_CELL1 & 0xFFFF); + len += sprintf(page + off + len, + " DREG_AR_IDLE_CNT1 = %d\n", *DREG_AR_IDLE_CNT1 & 0xFFFF); + len += sprintf(page + off + len, + " DREG_AR_AIIDLE_CNT1 = %d\n", *DREG_AR_AIIDLE_CNT1 & 0xFFFF); + len += sprintf(page + off + len, + " DREG_AR_BE_CNT1 = %d\n", *DREG_AR_BE_CNT1 & 0xFFFF); + + return len; +} + +int proc_read_stats(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = 0; + + int i, j; + struct connection *connection; + struct port *port; + int base; + + len += sprintf(page + off, "ATM Stats:\n"); + + connection = ppe_dev.connection; + port = ppe_dev.port; + for ( i = 0; i < ATM_PORT_NUMBER; i++, port++ ) + { + base = port->connection_base; + for ( j = 0; j < port->max_connections; j++, base++ ) + if ( (port->connection_table & (1 << j)) + && connection[base].vcc != NULL ) + { + if ( connection[base].vcc->stats ) + { + struct k_atm_aal_stats *stats = connection[base].vcc->stats; + + len += sprintf(page + off + len, " VCC %d.%d.%d (stats)\n", i, connection[base].vcc->vpi, connection[base].vcc->vci); + len += sprintf(page + off + len, " rx = %d\n", stats->rx.counter); + len += sprintf(page + off + len, " rx_err = %d\n", stats->rx_err.counter); + len += sprintf(page + off + len, " rx_drop = %d\n", stats->rx_drop.counter); + len += sprintf(page + off + len, " tx = %d\n", stats->tx.counter); + len += sprintf(page + off + len, " tx_err = %d\n", stats->tx_err.counter); + } + else + len += sprintf(page + off + len, " VCC %d.%d.%d\n", i, connection[base].vcc->vpi, connection[base].vcc->vci); + } + } + + return len; +} + +void proc_file_create(void) +{ + ppe_proc_dir = proc_mkdir("ppe", NULL); + create_proc_read_entry("idle_counter", 0, ppe_proc_dir, proc_read_idle_counter, NULL); + create_proc_read_entry("stats", 0, ppe_proc_dir, proc_read_stats, NULL); +} + +void proc_file_delete(void) +{ + remove_proc_entry("idle_counter", ppe_proc_dir); + remove_proc_entry("stats", ppe_proc_dir); + remove_proc_entry("ppe", NULL); +} diff --git a/package/ifxmips-atm/src/proc.h b/package/ifxmips-atm/src/proc.h new file mode 100644 index 0000000000..c632c0ce18 --- /dev/null +++ b/package/ifxmips-atm/src/proc.h @@ -0,0 +1,9 @@ +#ifndef _IFXMIPS_PPE_PROC_H__ +#define _IFXMIPS_PPE_PROC_H__ + +void proc_file_create(void); +void proc_file_delete(void); +int proc_read_idle_counter(char *page, char **start, off_t off, int count, int *eof, void *data); +int proc_read_stats(char *page, char **start, off_t off, int count, int *eof, void *data); + +#endif diff --git a/package/ifxmips-atm/src/skb.c b/package/ifxmips-atm/src/skb.c new file mode 100644 index 0000000000..7ad60fd757 --- /dev/null +++ b/package/ifxmips-atm/src/skb.c @@ -0,0 +1,128 @@ +#include <linux/skbuff.h> + +#include "common.h" + +void resize_skb_rx(struct sk_buff *skb, unsigned int size, int is_cell) +{ + if((u32)skb < 0x80000000) + { + int key = 0; + printk("resize_skb_rx problem: skb = %08X, size = %d, is_cell = %d\n", (u32)skb, size, is_cell); + while(!key){} + } + skb->data = (unsigned char*)(((u32)skb->head + 16 + (DMA_ALIGNMENT - 1)) & ~(DMA_ALIGNMENT - 1)); + skb->tail = skb->data; + + /* Set up other state */ + skb->len = 0; + skb->cloned = 0; +#if defined(CONFIG_IMQ) || defined (CONFIG_IMQ_MODULE) + skb->imq_flags = 0; + skb->nf_info = NULL; +#endif + skb->data_len = 0; +} + +struct sk_buff* alloc_skb_rx(void) +{ + struct sk_buff *skb; + + /* allocate memroy including trailer and padding */ + skb = dev_alloc_skb(ppe_dev.aal5.rx_buffer_size + DMA_ALIGNMENT); + if (skb) + { + /* must be burst length alignment */ + if ( ((u32)skb->data & (DMA_ALIGNMENT - 1)) != 0 ) + skb_reserve(skb, ~((u32)skb->data + (DMA_ALIGNMENT - 1)) & (DMA_ALIGNMENT - 1)); + /* put skb in reserved area "skb->data - 4" */ + *((u32*)skb->data - 1) = (u32)skb; + /* invalidate cache */ + dma_cache_inv((unsigned long)skb->head, (u32)skb->end - (u32)skb->head); + } + return skb; +} + +void atm_free_tx_skb_vcc(struct sk_buff *skb) +{ + struct atm_vcc* vcc; + + if ( (u32)skb <= 0x80000000 ) + { + volatile int key = 0; + printk("atm_free_tx_skb_vcc: skb = %08X\n", (u32)skb); + for ( ; !key; ); + } + + vcc = ATM_SKB(skb)->vcc; + if ( vcc != NULL && vcc->pop != NULL ) + { + if ( atomic_read(&skb->users) == 0 ) + { + volatile int key = 0; + printk("atm_free_tx_skb_vcc(vcc->pop): skb->users == 0, skb = %08X\n", (u32)skb); + for ( ; !key; ); + } + vcc->pop(vcc, skb); + } + else + { + if ( atomic_read(&skb->users) == 0 ) + { + volatile int key = 0; + printk("atm_free_tx_skb_vcc(dev_kfree_skb_any): skb->users == 0, skb = %08X\n", (u32)skb); + for ( ; !key; ); + } + dev_kfree_skb_any(skb); + } +} + +struct sk_buff* alloc_skb_tx(unsigned int size) +{ + struct sk_buff *skb; + + /* allocate memory including header and padding */ + size += TX_INBAND_HEADER_LENGTH + MAX_TX_PACKET_ALIGN_BYTES + MAX_TX_PACKET_PADDING_BYTES; + size &= ~(DMA_ALIGNMENT - 1); + skb = dev_alloc_skb(size + DMA_ALIGNMENT); + /* must be burst length alignment */ + if ( skb ) + skb_reserve(skb, (~((u32)skb->data + (DMA_ALIGNMENT - 1)) & (DMA_ALIGNMENT - 1)) + TX_INBAND_HEADER_LENGTH); + return skb; +} + +struct sk_buff* atm_alloc_tx(struct atm_vcc *vcc, unsigned int size) +{ + int conn; + struct sk_buff *skb; + + /* oversize packet */ + if ( ((size + TX_INBAND_HEADER_LENGTH + MAX_TX_PACKET_ALIGN_BYTES + MAX_TX_PACKET_PADDING_BYTES) & ~(DMA_ALIGNMENT - 1)) > ppe_dev.aal5.tx_max_packet_size ) + { + printk("atm_alloc_tx: oversize packet\n"); + return NULL; + } + /* send buffer overflow */ + if ( atomic_read(&vcc->sk.sk_wmem_alloc) && !atm_may_send(vcc, size) ) + { + printk("atm_alloc_tx: send buffer overflow\n"); + return NULL; + } + conn = find_vcc(vcc); + if ( conn < 0 ) + { + printk("atm_alloc_tx: unknown VCC\n"); + return NULL; + } + + skb = dev_alloc_skb(size); + if ( skb == NULL ) + { + printk("atm_alloc_tx: sk buffer is used up\n"); + return NULL; + } +#define ATM_PDU_OVHD 0 + atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->sk.sk_wmem_alloc); + + return skb; +} + |