Root/package/ltq-dsl/src/ifxmips_atm_core.c

1/******************************************************************************
2**
3** FILE NAME : ifxmips_atm_core.c
4** PROJECT : UEIP
5** MODULES : ATM
6**
7** DATE : 7 Jul 2009
8** AUTHOR : Xu Liang
9** DESCRIPTION : ATM driver common source file (core functions)
10** COPYRIGHT : Copyright (c) 2006
11** Infineon Technologies AG
12** Am Campeon 1-12, 85579 Neubiberg, Germany
13**
14** This program is free software; you can redistribute it and/or modify
15** it under the terms of the GNU General Public License as published by
16** the Free Software Foundation; either version 2 of the License, or
17** (at your option) any later version.
18**
19** HISTORY
20** $Date $Author $Comment
21** 07 JUL 2009 Xu Liang Init Version
22*******************************************************************************/
23
24
25
26/*
27 * ####################################
28 * Version No.
29 * ####################################
30 */
31
32#define IFX_ATM_VER_MAJOR 1
33#define IFX_ATM_VER_MID 0
34#define IFX_ATM_VER_MINOR 19
35
36
37
38/*
39 * ####################################
40 * Head File
41 * ####################################
42 */
43
44/*
45 * Common Head File
46 */
47#include <linux/kernel.h>
48#include <linux/vmalloc.h>
49#include <linux/module.h>
50#include <linux/version.h>
51#include <linux/types.h>
52#include <linux/errno.h>
53#include <linux/proc_fs.h>
54#include <linux/init.h>
55#include <linux/ioctl.h>
56#include <linux/atmdev.h>
57#include <linux/atm.h>
58#include <linux/clk.h>
59
60/*
61 * Chip Specific Head File
62 */
63#include <lantiq_soc.h>
64#include "ifxmips_compat.h"
65#define IFX_MEI_BSP 1
66#include "ifxmips_mei_interface.h"
67#include "ifxmips_atm_core.h"
68
69
70
71/*
72 * ####################################
73 * Kernel Version Adaption
74 * ####################################
75 */
76#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
77  #define MODULE_PARM_ARRAY(a, b) module_param_array(a, int, NULL, 0)
78  #define MODULE_PARM(a, b) module_param(a, int, 0)
79#else
80  #define MODULE_PARM_ARRAY(a, b) MODULE_PARM(a, b)
81#endif
82
83
84
85/*!
86  \addtogroup IFXMIPS_ATM_MODULE_PARAMS
87 */
88/*@{*/
89/*
90 * ####################################
91 * Parameters to Configure PPE
92 * ####################################
93 */
94/*!
95  \brief QSB cell delay variation due to concurrency
96 */
97static int qsb_tau = 1; /* QSB cell delay variation due to concurrency */
98/*!
99  \brief QSB scheduler burst length
100 */
101static int qsb_srvm = 0x0F; /* QSB scheduler burst length */
102/*!
103  \brief QSB time step, all legal values are 1, 2, 4
104 */
105static int qsb_tstep = 4 ; /* QSB time step, all legal values are 1, 2, 4 */
106
107/*!
108  \brief Write descriptor delay
109 */
110static int write_descriptor_delay = 0x20; /* Write descriptor delay */
111
112/*!
113  \brief AAL5 padding byte ('~')
114 */
115static int aal5_fill_pattern = 0x007E; /* AAL5 padding byte ('~') */
116/*!
117  \brief Max frame size for RX
118 */
119static int aal5r_max_packet_size = 0x0700; /* Max frame size for RX */
120/*!
121  \brief Min frame size for RX
122 */
123static int aal5r_min_packet_size = 0x0000; /* Min frame size for RX */
124/*!
125  \brief Max frame size for TX
126 */
127static int aal5s_max_packet_size = 0x0700; /* Max frame size for TX */
128/*!
129  \brief Min frame size for TX
130 */
131static int aal5s_min_packet_size = 0x0000; /* Min frame size for TX */
132/*!
133  \brief Drop error packet in RX path
134 */
135static int aal5r_drop_error_packet = 1; /* Drop error packet in RX path */
136
137/*!
138  \brief Number of descriptors per DMA RX channel
139 */
140static int dma_rx_descriptor_length = 128; /* Number of descriptors per DMA RX channel */
141/*!
142  \brief Number of descriptors per DMA TX channel
143 */
144static int dma_tx_descriptor_length = 64; /* Number of descriptors per DMA TX channel */
145/*!
146  \brief PPE core clock cycles between descriptor write and effectiveness in external RAM
147 */
148static int dma_rx_clp1_descriptor_threshold = 38;
149/*@}*/
150
151MODULE_PARM(qsb_tau, "i");
152MODULE_PARM_DESC(qsb_tau, "Cell delay variation. Value must be > 0");
153MODULE_PARM(qsb_srvm, "i");
154MODULE_PARM_DESC(qsb_srvm, "Maximum burst size");
155MODULE_PARM(qsb_tstep, "i");
156MODULE_PARM_DESC(qsb_tstep, "n*32 cycles per sbs cycles n=1,2,4");
157
158MODULE_PARM(write_descriptor_delay, "i");
159MODULE_PARM_DESC(write_descriptor_delay, "PPE core clock cycles between descriptor write and effectiveness in external RAM");
160
161MODULE_PARM(aal5_fill_pattern, "i");
162MODULE_PARM_DESC(aal5_fill_pattern, "Filling pattern (PAD) for AAL5 frames");
163MODULE_PARM(aal5r_max_packet_size, "i");
164MODULE_PARM_DESC(aal5r_max_packet_size, "Max packet size in byte for downstream AAL5 frames");
165MODULE_PARM(aal5r_min_packet_size, "i");
166MODULE_PARM_DESC(aal5r_min_packet_size, "Min packet size in byte for downstream AAL5 frames");
167MODULE_PARM(aal5s_max_packet_size, "i");
168MODULE_PARM_DESC(aal5s_max_packet_size, "Max packet size in byte for upstream AAL5 frames");
169MODULE_PARM(aal5s_min_packet_size, "i");
170MODULE_PARM_DESC(aal5s_min_packet_size, "Min packet size in byte for upstream AAL5 frames");
171MODULE_PARM(aal5r_drop_error_packet, "i");
172MODULE_PARM_DESC(aal5r_drop_error_packet, "Non-zero value to drop error packet for downstream");
173
174MODULE_PARM(dma_rx_descriptor_length, "i");
175MODULE_PARM_DESC(dma_rx_descriptor_length, "Number of descriptor assigned to DMA RX channel (>16)");
176MODULE_PARM(dma_tx_descriptor_length, "i");
177MODULE_PARM_DESC(dma_tx_descriptor_length, "Number of descriptor assigned to DMA TX channel (>16)");
178MODULE_PARM(dma_rx_clp1_descriptor_threshold, "i");
179MODULE_PARM_DESC(dma_rx_clp1_descriptor_threshold, "Descriptor threshold for cells with cell loss priority 1");
180
181
182
183/*
184 * ####################################
185 * Definition
186 * ####################################
187 */
188
189#define ENABLE_LED_FRAMEWORK 1
190
191#define DUMP_SKB_LEN ~0
192
193
194
195/*
196 * ####################################
197 * Declaration
198 * ####################################
199 */
200
201/*
202 * Network Operations
203 */
204static int ppe_ioctl(struct atm_dev *, unsigned int, void *);
205static int ppe_open(struct atm_vcc *);
206static void ppe_close(struct atm_vcc *);
207static int ppe_send(struct atm_vcc *, struct sk_buff *);
208static int ppe_send_oam(struct atm_vcc *, void *, int);
209static int ppe_change_qos(struct atm_vcc *, struct atm_qos *, int);
210
211/*
212 * ADSL LED
213 */
214static INLINE void adsl_led_flash(void);
215
216/*
217 * 64-bit operation used by MIB calculation
218 */
219static INLINE void u64_add_u32(ppe_u64_t, unsigned int, ppe_u64_t *);
220
221/*
222 * buffer manage functions
223 */
224static INLINE struct sk_buff* alloc_skb_rx(void);
225static INLINE struct sk_buff* alloc_skb_tx(unsigned int);
226struct sk_buff* atm_alloc_tx(struct atm_vcc *, unsigned int);
227static INLINE void atm_free_tx_skb_vcc(struct sk_buff *, struct atm_vcc *);
228static INLINE struct sk_buff *get_skb_rx_pointer(unsigned int);
229static INLINE int get_tx_desc(unsigned int);
230
231/*
232 * mailbox handler and signal function
233 */
234static INLINE void mailbox_oam_rx_handler(void);
235static INLINE void mailbox_aal_rx_handler(void);
236#if defined(ENABLE_TASKLET) && ENABLE_TASKLET
237  static void do_ppe_tasklet(unsigned long);
238#endif
239static irqreturn_t mailbox_irq_handler(int, void *);
240static INLINE void mailbox_signal(unsigned int, int);
241
242/*
243 * QSB & HTU setting functions
244 */
245static void set_qsb(struct atm_vcc *, struct atm_qos *, unsigned int);
246static void qsb_global_set(void);
247static INLINE void set_htu_entry(unsigned int, unsigned int, unsigned int, int, int);
248static INLINE void clear_htu_entry(unsigned int);
249static void validate_oam_htu_entry(void);
250static void invalidate_oam_htu_entry(void);
251
252/*
253 * look up for connection ID
254 */
255static INLINE int find_vpi(unsigned int);
256static INLINE int find_vpivci(unsigned int, unsigned int);
257static INLINE int find_vcc(struct atm_vcc *);
258
259/*
260 * ReTX functions
261 */
262#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
263  static void retx_polling_func(unsigned long);
264  static int init_atm_tc_retrans_param(void);
265  static void clear_atm_tc_retrans_param(void);
266#endif
267
268
269/*
270 * Debug Functions
271 */
272#if defined(DEBUG_DUMP_SKB) && DEBUG_DUMP_SKB
273  static void dump_skb(struct sk_buff *, unsigned int, char *, int, int, int);
274#else
275  #define dump_skb(skb, len, title, port, ch, is_tx) do {} while (0)
276#endif
277#if defined(ENABLE_DBG_PROC) && ENABLE_DBG_PROC
278  static void skb_swap(struct sk_buff *, unsigned int);
279#else
280  #define skb_swap(skb, byteoff) do {} while (0)
281#endif
282
283/*
284 * Proc File Functions
285 */
286static INLINE void proc_file_create(void);
287static INLINE void proc_file_delete(void);
288static int proc_read_version(char *, char **, off_t, int, int *, void *);
289static int proc_read_mib(char *, char **, off_t, int, int *, void *);
290static int proc_write_mib(struct file *, const char *, unsigned long, void *);
291#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
292  static int proc_read_retx_mib(char *, char **, off_t, int, int *, void *);
293  static int proc_write_retx_mib(struct file *, const char *, unsigned long, void *);
294#endif
295#if defined(ENABLE_DBG_PROC) && ENABLE_DBG_PROC
296  static int proc_read_dbg(char *, char **, off_t, int, int *, void *);
297  static int proc_write_dbg(struct file *, const char *, unsigned long, void *);
298  static int proc_write_mem(struct file *, const char *, unsigned long, void *);
299 #if defined(CONFIG_AR9) || defined(CONFIG_VR9) || defined(CONFIG_DANUBE) || defined(CONFIG_AMAZON_SE)
300  static int proc_read_pp32(char *, char **, off_t, int, int *, void *);
301  static int proc_write_pp32(struct file *, const char *, unsigned long, void *);
302 #endif
303#endif
304#if defined(ENABLE_FW_PROC) && ENABLE_FW_PROC
305  static int proc_read_htu(char *, char **, off_t, int, int *, void *);
306  static int proc_read_txq(char *, char **, off_t, int, int *, void *);
307 #if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
308  static int proc_read_retx_fw(char *, char **, off_t, int, int *, void *);
309  static int proc_read_retx_stats(char *, char **, off_t, int, int *, void *);
310  static int proc_write_retx_stats(struct file *, const char *, unsigned long, void *);
311  static int proc_read_retx_cfg(char *, char **, off_t, int, int *, void *);
312  static int proc_write_retx_cfg(struct file *, const char *, unsigned long, void *);
313  static int proc_read_retx_dsl_param(char *, char **, off_t, int, int *, void *);
314 #endif
315#endif
316
317/*
318 * Proc Help Functions
319 */
320static int stricmp(const char *, const char *);
321#if defined(ENABLE_DBG_PROC) && ENABLE_DBG_PROC
322  static int strincmp(const char *, const char *, int);
323  static int get_token(char **, char **, int *, int *);
324  static unsigned int get_number(char **, int *, int);
325  static void ignore_space(char **, int *);
326#endif
327static INLINE int ifx_atm_version(char *);
328
329/*
330 * Init & clean-up functions
331 */
332static INLINE void check_parameters(void);
333static INLINE int init_priv_data(void);
334static INLINE void clear_priv_data(void);
335static INLINE void init_rx_tables(void);
336static INLINE void init_tx_tables(void);
337
338/*
339 * Exteranl Function
340 */
341#if defined(CONFIG_IFX_OAM) || defined(CONFIG_IFX_OAM_MODULE)
342  extern void ifx_push_oam(unsigned char *);
343#else
344  static inline void ifx_push_oam(unsigned char *dummy) {}
345#endif
346#if defined(CONFIG_IFXMIPS_DSL_CPE_MEI) || defined(CONFIG_IFXMIPS_DSL_CPE_MEI_MODULE)
347 #if !defined(ENABLE_LED_FRAMEWORK) || !ENABLE_LED_FRAMEWORK
348  extern int ifx_mei_atm_led_blink(void) __attribute__ ((weak));
349 #endif
350  extern int ifx_mei_atm_showtime_check(int *is_showtime, struct port_cell_info *port_cell, void **xdata_addr) __attribute__ ((weak));
351#else
352 #if !defined(ENABLE_LED_FRAMEWORK) || !ENABLE_LED_FRAMEWORK
353  static inline int ifx_mei_atm_led_blink(void) { return IFX_SUCCESS; }
354 #endif
355  static inline int ifx_mei_atm_showtime_check(int *is_showtime, struct port_cell_info *port_cell, void **xdata_addr)
356  {
357    if ( is_showtime != NULL )
358        *is_showtime = 0;
359    return IFX_SUCCESS;
360  }
361#endif
362
363/*
364 * External variable
365 */
366struct sk_buff* (*ifx_atm_alloc_tx)(struct atm_vcc *, unsigned int) = NULL;
367
368
369//extern struct sk_buff* (*ifx_atm_alloc_tx)(struct atm_vcc *, unsigned int);
370#if defined(CONFIG_IFXMIPS_DSL_CPE_MEI) || defined(CONFIG_IFXMIPS_DSL_CPE_MEI_MODULE)
371  extern int (*ifx_mei_atm_showtime_enter)(struct port_cell_info *, void *) __attribute__ ((weak));
372  extern int (*ifx_mei_atm_showtime_exit)(void) __attribute__ ((weak));
373#else
374  int (*ifx_mei_atm_showtime_enter)(struct port_cell_info *, void *) = NULL;
375  EXPORT_SYMBOL(ifx_mei_atm_showtime_enter);
376  int (*ifx_mei_atm_showtime_exit)(void) = NULL;
377  EXPORT_SYMBOL(ifx_mei_atm_showtime_exit);
378#endif
379
380
381
382/*
383 * ####################################
384 * Local Variable
385 * ####################################
386 */
387
388static struct atm_priv_data g_atm_priv_data;
389
390static struct atmdev_ops g_ifx_atm_ops = {
391    .open = ppe_open,
392    .close = ppe_close,
393    .ioctl = ppe_ioctl,
394    .send = ppe_send,
395    .send_oam = ppe_send_oam,
396    .change_qos = ppe_change_qos,
397    .owner = THIS_MODULE,
398};
399
400#if defined(ENABLE_TASKLET) && ENABLE_TASKLET
401  DECLARE_TASKLET(g_dma_tasklet, do_ppe_tasklet, 0);
402#endif
403
404static int g_showtime = 0;
405static void *g_xdata_addr = NULL;
406
407#if 0 /*--- defined(ENABLE_LED_FRAMEWORK) && ENABLE_LED_FRAMEWORK ---*/
408  static void *g_data_led_trigger = NULL;
409#endif
410
411#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
412  static unsigned long g_retx_playout_buffer = 0;
413
414  static volatile int g_retx_htu = 1;
415  static struct dsl_param g_dsl_param = {0};
416  static int g_retx_polling_cnt = HZ;
417  static struct timeval g_retx_polling_start = {0}, g_retx_polling_end = {0};
418  static struct timer_list g_retx_polling_timer;
419#endif
420
421unsigned int ifx_atm_dbg_enable = 0;
422
423static struct proc_dir_entry* g_atm_dir = NULL;
424
425
426
427/*
428 * ####################################
429 * Local Function
430 * ####################################
431 */
432
433static int ppe_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
434{
435    int ret = 0;
436    atm_cell_ifEntry_t mib_cell;
437    atm_aal5_ifEntry_t mib_aal5;
438    atm_aal5_vcc_x_t mib_vcc;
439    unsigned int value;
440    int conn;
441
442    if ( _IOC_TYPE(cmd) != PPE_ATM_IOC_MAGIC
443        || _IOC_NR(cmd) >= PPE_ATM_IOC_MAXNR )
444        return -ENOTTY;
445
446    if ( _IOC_DIR(cmd) & _IOC_READ )
447        ret = !access_ok(VERIFY_WRITE, arg, _IOC_SIZE(cmd));
448    else if ( _IOC_DIR(cmd) & _IOC_WRITE )
449        ret = !access_ok(VERIFY_READ, arg, _IOC_SIZE(cmd));
450    if ( ret )
451        return -EFAULT;
452
453    switch ( cmd )
454    {
455    case PPE_ATM_MIB_CELL: /* cell level MIB */
456        /* These MIB should be read at ARC side, now put zero only. */
457        mib_cell.ifHCInOctets_h = 0;
458        mib_cell.ifHCInOctets_l = 0;
459        mib_cell.ifHCOutOctets_h = 0;
460        mib_cell.ifHCOutOctets_l = 0;
461        mib_cell.ifInErrors = 0;
462        mib_cell.ifInUnknownProtos = WAN_MIB_TABLE->wrx_drophtu_cell;
463        mib_cell.ifOutErrors = 0;
464
465        ret = sizeof(mib_cell) - copy_to_user(arg, &mib_cell, sizeof(mib_cell));
466        break;
467
468    case PPE_ATM_MIB_AAL5: /* AAL5 MIB */
469        value = WAN_MIB_TABLE->wrx_total_byte;
470        u64_add_u32(g_atm_priv_data.wrx_total_byte, value - g_atm_priv_data.prev_wrx_total_byte, &g_atm_priv_data.wrx_total_byte);
471        g_atm_priv_data.prev_wrx_total_byte = value;
472        mib_aal5.ifHCInOctets_h = g_atm_priv_data.wrx_total_byte.h;
473        mib_aal5.ifHCInOctets_l = g_atm_priv_data.wrx_total_byte.l;
474
475        value = WAN_MIB_TABLE->wtx_total_byte;
476        u64_add_u32(g_atm_priv_data.wtx_total_byte, value - g_atm_priv_data.prev_wtx_total_byte, &g_atm_priv_data.wtx_total_byte);
477        g_atm_priv_data.prev_wtx_total_byte = value;
478        mib_aal5.ifHCOutOctets_h = g_atm_priv_data.wtx_total_byte.h;
479        mib_aal5.ifHCOutOctets_l = g_atm_priv_data.wtx_total_byte.l;
480
481        mib_aal5.ifInUcastPkts = g_atm_priv_data.wrx_pdu;
482        mib_aal5.ifOutUcastPkts = WAN_MIB_TABLE->wtx_total_pdu;
483        mib_aal5.ifInErrors = WAN_MIB_TABLE->wrx_err_pdu;
484        mib_aal5.ifInDiscards = WAN_MIB_TABLE->wrx_dropdes_pdu + g_atm_priv_data.wrx_drop_pdu;
485        mib_aal5.ifOutErros = g_atm_priv_data.wtx_err_pdu;
486        mib_aal5.ifOutDiscards = g_atm_priv_data.wtx_drop_pdu;
487
488        ret = sizeof(mib_aal5) - copy_to_user(arg, &mib_aal5, sizeof(mib_aal5));
489        break;
490
491    case PPE_ATM_MIB_VCC: /* VCC related MIB */
492        copy_from_user(&mib_vcc, arg, sizeof(mib_vcc));
493        conn = find_vpivci(mib_vcc.vpi, mib_vcc.vci);
494        if ( conn >= 0 )
495        {
496            mib_vcc.mib_vcc.aal5VccCrcErrors = g_atm_priv_data.conn[conn].aal5_vcc_crc_err;
497            mib_vcc.mib_vcc.aal5VccOverSizedSDUs = g_atm_priv_data.conn[conn].aal5_vcc_oversize_sdu;
498            mib_vcc.mib_vcc.aal5VccSarTimeOuts = 0; /* no timer support */
499            ret = sizeof(mib_vcc) - copy_to_user(arg, &mib_vcc, sizeof(mib_vcc));
500        }
501        else
502            ret = -EINVAL;
503        break;
504
505    default:
506        ret = -ENOIOCTLCMD;
507    }
508
509    return ret;
510}
511
512static int ppe_open(struct atm_vcc *vcc)
513{
514    int ret;
515    short vpi = vcc->vpi;
516    int vci = vcc->vci;
517    struct port *port = &g_atm_priv_data.port[(int)vcc->dev->dev_data];
518    int conn;
519    int f_enable_irq = 0;
520#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
521    int sys_flag;
522#endif
523
524    if ( vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0 )
525        return -EPROTONOSUPPORT;
526
527#if !defined(DISABLE_QOS_WORKAROUND) || !DISABLE_QOS_WORKAROUND
528    /* check bandwidth */
529
530    if (vcc->qos.txtp.traffic_class == ATM_CBR &&
531                vcc->qos.txtp.max_pcr > (port->tx_max_cell_rate - port->tx_current_cell_rate))
532    {
533        printk("CBR set. %s, line %d returns EINVAL\n", __FUNCTION__, __LINE__);
534        ret = -EINVAL;
535        goto PPE_OPEN_EXIT;
536    }
537    if(vcc->qos.txtp.traffic_class == ATM_VBR_RT &&
538                vcc->qos.txtp.max_pcr > (port->tx_max_cell_rate - port->tx_current_cell_rate))
539    {
540        printk("VBR RT set. %s, line %d returns EINVAL\n", __FUNCTION__, __LINE__);
541        ret = -EINVAL;
542        goto PPE_OPEN_EXIT;
543    }
544
545    if (vcc->qos.txtp.traffic_class == ATM_VBR_NRT &&
546                vcc->qos.txtp.scr > (port->tx_max_cell_rate - port->tx_current_cell_rate))
547    {
548        printk("VBR NRT set. %s, line %d returns EINVAL\n", __FUNCTION__, __LINE__);
549        ret = -EINVAL;
550        goto PPE_OPEN_EXIT;
551    }
552
553    if (vcc->qos.txtp.traffic_class == ATM_UBR_PLUS &&
554                vcc->qos.txtp.min_pcr > (port->tx_max_cell_rate - port->tx_current_cell_rate))
555    {
556        printk("UBR PLUS set. %s, line %d returns EINVAL\n", __FUNCTION__, __LINE__);
557        ret = -EINVAL;
558        goto PPE_OPEN_EXIT;
559    }
560
561#endif
562
563    /* check existing vpi,vci */
564    conn = find_vpivci(vpi, vci);
565    if ( conn >= 0 ) {
566        ret = -EADDRINUSE;
567        goto PPE_OPEN_EXIT;
568    }
569
570    /* check whether it need to enable irq */
571    if ( g_atm_priv_data.conn_table == 0 )
572        f_enable_irq = 1;
573
574    /* allocate connection */
575    for ( conn = 0; conn < MAX_PVC_NUMBER; conn++ ) {
576        if ( test_and_set_bit(conn, &g_atm_priv_data.conn_table) == 0 ) {
577            g_atm_priv_data.conn[conn].vcc = vcc;
578            break;
579        }
580    }
581    if ( conn == MAX_PVC_NUMBER )
582    {
583        printk("max_pvc_number reached\n");
584        ret = -EINVAL;
585        goto PPE_OPEN_EXIT;
586    }
587
588    /* reserve bandwidth */
589    switch ( vcc->qos.txtp.traffic_class ) {
590    case ATM_CBR:
591    case ATM_VBR_RT:
592        port->tx_current_cell_rate += vcc->qos.txtp.max_pcr;
593        break;
594    case ATM_VBR_NRT:
595        port->tx_current_cell_rate += vcc->qos.txtp.scr;
596        break;
597    case ATM_UBR_PLUS:
598        port->tx_current_cell_rate += vcc->qos.txtp.min_pcr;
599        break;
600    }
601
602    /* set qsb */
603    set_qsb(vcc, &vcc->qos, conn);
604
605    /* update atm_vcc structure */
606    vcc->itf = (int)vcc->dev->dev_data;
607    vcc->vpi = vpi;
608    vcc->vci = vci;
609    set_bit(ATM_VF_READY, &vcc->flags);
610
611    /* enable irq */
612    if (f_enable_irq ) {
613        ifx_atm_alloc_tx = atm_alloc_tx;
614
615        *MBOX_IGU1_ISRC = (1 << RX_DMA_CH_AAL) | (1 << RX_DMA_CH_OAM);
616        *MBOX_IGU1_IER = (1 << RX_DMA_CH_AAL) | (1 << RX_DMA_CH_OAM);
617
618        enable_irq(PPE_MAILBOX_IGU1_INT);
619    }
620
621    /* set port */
622    WTX_QUEUE_CONFIG(conn + FIRST_QSB_QID)->sbid = (int)vcc->dev->dev_data;
623
624    /* set htu entry */
625    set_htu_entry(vpi, vci, conn, vcc->qos.aal == ATM_AAL5 ? 1 : 0, 0);
626
627#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
628    // ReTX: occupy second QID
629    local_irq_save(sys_flag);
630    if ( g_retx_htu && vcc->qos.aal == ATM_AAL5 )
631    {
632        int retx_conn = (conn + 8) % 16; // ReTX queue
633
634        if ( retx_conn < MAX_PVC_NUMBER && test_and_set_bit(retx_conn, &g_atm_priv_data.conn_table) == 0 ) {
635            g_atm_priv_data.conn[retx_conn].vcc = vcc;
636            set_htu_entry(vpi, vci, retx_conn, vcc->qos.aal == ATM_AAL5 ? 1 : 0, 1);
637        }
638    }
639    local_irq_restore(sys_flag);
640#endif
641
642    ret = 0;
643
644PPE_OPEN_EXIT:
645    return ret;
646}
647
648static void ppe_close(struct atm_vcc *vcc)
649{
650    int conn;
651    struct port *port;
652    struct connection *connection;
653#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
654    int sys_flag;
655#endif
656
657    if ( vcc == NULL )
658        return;
659
660    /* get connection id */
661    conn = find_vcc(vcc);
662    if ( conn < 0 ) {
663        err("can't find vcc");
664        goto PPE_CLOSE_EXIT;
665    }
666    connection = &g_atm_priv_data.conn[conn];
667    port = &g_atm_priv_data.port[connection->port];
668
669    /* clear htu */
670    clear_htu_entry(conn);
671
672#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
673    // ReTX: release second QID
674    local_irq_save(sys_flag);
675    if ( g_retx_htu && vcc->qos.aal == ATM_AAL5 )
676    {
677        int retx_conn = (conn + 8) % 16; // ReTX queue
678
679        if ( retx_conn < MAX_PVC_NUMBER && g_atm_priv_data.conn[retx_conn].vcc == vcc ) {
680            clear_htu_entry(retx_conn);
681            g_atm_priv_data.conn[retx_conn].vcc = NULL;
682            g_atm_priv_data.conn[retx_conn].aal5_vcc_crc_err = 0;
683            g_atm_priv_data.conn[retx_conn].aal5_vcc_oversize_sdu = 0;
684            clear_bit(retx_conn, &g_atm_priv_data.conn_table);
685        }
686    }
687    local_irq_restore(sys_flag);
688#endif
689
690    /* release connection */
691    connection->vcc = NULL;
692    connection->aal5_vcc_crc_err = 0;
693    connection->aal5_vcc_oversize_sdu = 0;
694    clear_bit(conn, &g_atm_priv_data.conn_table);
695
696    /* disable irq */
697    if ( g_atm_priv_data.conn_table == 0 ) {
698        disable_irq(PPE_MAILBOX_IGU1_INT);
699        ifx_atm_alloc_tx = NULL;
700    }
701
702    /* release bandwidth */
703    switch ( vcc->qos.txtp.traffic_class )
704    {
705    case ATM_CBR:
706    case ATM_VBR_RT:
707        port->tx_current_cell_rate -= vcc->qos.txtp.max_pcr;
708        break;
709    case ATM_VBR_NRT:
710        port->tx_current_cell_rate -= vcc->qos.txtp.scr;
711        break;
712    case ATM_UBR_PLUS:
713        port->tx_current_cell_rate -= vcc->qos.txtp.min_pcr;
714        break;
715    }
716
717PPE_CLOSE_EXIT:
718    return;
719}
720
721static int ppe_send(struct atm_vcc *vcc, struct sk_buff *skb)
722{
723    int ret;
724    int conn;
725    int desc_base;
726    struct tx_descriptor reg_desc = {0};
727
728    if ( vcc == NULL || skb == NULL )
729        return -EINVAL;
730
731    skb_orphan(skb);
732    skb_get(skb);
733    atm_free_tx_skb_vcc(skb, vcc);
734
735    conn = find_vcc(vcc);
736    if ( conn < 0 ) {
737        ret = -EINVAL;
738        goto FIND_VCC_FAIL;
739    }
740
741    if ( !g_showtime ) {
742        err("not in showtime");
743        ret = -EIO;
744        goto PPE_SEND_FAIL;
745    }
746
747    if ( vcc->qos.aal == ATM_AAL5 ) {
748        int byteoff;
749        int datalen;
750        struct tx_inband_header *header;
751
752        datalen = skb->len;
753        byteoff = (unsigned int)skb->data & (DATA_BUFFER_ALIGNMENT - 1);
754
755        if ( skb_headroom(skb) < byteoff + TX_INBAND_HEADER_LENGTH ) {
756            struct sk_buff *new_skb;
757
758            new_skb = alloc_skb_tx(datalen);
759            if ( new_skb == NULL ) {
760                err("ALLOC_SKB_TX_FAIL");
761                ret = -ENOMEM;
762                goto PPE_SEND_FAIL;
763            }
764            skb_put(new_skb, datalen);
765            memcpy(new_skb->data, skb->data, datalen);
766            dev_kfree_skb_any(skb);
767            skb = new_skb;
768            byteoff = (unsigned int)skb->data & (DATA_BUFFER_ALIGNMENT - 1);
769        }
770
771        skb_push(skb, byteoff + TX_INBAND_HEADER_LENGTH);
772
773        header = (struct tx_inband_header *)skb->data;
774
775        /* setup inband trailer */
776        header->uu = 0;
777        header->cpi = 0;
778        header->pad = aal5_fill_pattern;
779        header->res1 = 0;
780
781        /* setup cell header */
782        header->clp = (vcc->atm_options & ATM_ATMOPT_CLP) ? 1 : 0;
783        header->pti = ATM_PTI_US0;
784        header->vci = vcc->vci;
785        header->vpi = vcc->vpi;
786        header->gfc = 0;
787
788        /* setup descriptor */
789        reg_desc.dataptr = (unsigned int)skb->data >> 2;
790        reg_desc.datalen = datalen;
791        reg_desc.byteoff = byteoff;
792        reg_desc.iscell = 0;
793    }
794    else {
795        /* if data pointer is not aligned, allocate new sk_buff */
796        if ( ((unsigned int)skb->data & (DATA_BUFFER_ALIGNMENT - 1)) != 0 ) {
797            struct sk_buff *new_skb;
798
799            err("skb->data not aligned");
800
801            new_skb = alloc_skb_tx(skb->len);
802            if ( new_skb == NULL ) {
803                err("ALLOC_SKB_TX_FAIL");
804                ret = -ENOMEM;
805                goto PPE_SEND_FAIL;
806            }
807            skb_put(new_skb, skb->len);
808            memcpy(new_skb->data, skb->data, skb->len);
809            dev_kfree_skb_any(skb);
810            skb = new_skb;
811        }
812
813        reg_desc.dataptr = (unsigned int)skb->data >> 2;
814        reg_desc.datalen = skb->len;
815        reg_desc.byteoff = 0;
816        reg_desc.iscell = 1;
817    }
818
819    reg_desc.own = 1;
820    reg_desc.c = 1;
821    reg_desc.sop = reg_desc.eop = 1;
822
823    desc_base = get_tx_desc(conn);
824    if ( desc_base < 0 ) {
825        err("ALLOC_TX_CONNECTION_FAIL");
826        ret = -EIO;
827        goto PPE_SEND_FAIL;
828    }
829
830    if ( vcc->stats )
831        atomic_inc(&vcc->stats->tx);
832    if ( vcc->qos.aal == ATM_AAL5 )
833        g_atm_priv_data.wtx_pdu++;
834
835    /* update descriptor send pointer */
836    if ( g_atm_priv_data.conn[conn].tx_skb[desc_base] != NULL )
837        dev_kfree_skb_any(g_atm_priv_data.conn[conn].tx_skb[desc_base]);
838    g_atm_priv_data.conn[conn].tx_skb[desc_base] = skb;
839
840    /* write discriptor to memory and write back cache */
841#ifdef CONFIG_DEBUG_SLAB
842    /* be sure that "redzone 1" is written back to memory */
843    dma_cache_wback((unsigned long)skb->head, 32);
844#endif
845    dma_cache_wback((unsigned long)skb_shinfo(skb), sizeof(struct skb_shared_info));
846    dma_cache_wback((unsigned long)skb->data, skb->len);
847    g_atm_priv_data.conn[conn].tx_desc[desc_base] = reg_desc;
848     
849    dump_skb(skb, DUMP_SKB_LEN, (char *)__func__, 0, conn, 1);
850
851    mailbox_signal(conn, 1);
852
853    adsl_led_flash();
854
855    return 0;
856
857FIND_VCC_FAIL:
858    err("FIND_VCC_FAIL");
859    g_atm_priv_data.wtx_err_pdu++;
860    dev_kfree_skb_any(skb);
861    return ret;
862
863PPE_SEND_FAIL:
864    if ( vcc->qos.aal == ATM_AAL5 )
865        g_atm_priv_data.wtx_drop_pdu++;
866    if ( vcc->stats )
867        atomic_inc(&vcc->stats->tx_err);
868    dev_kfree_skb_any(skb);
869    return ret;
870}
871
872static int ppe_send_oam(struct atm_vcc *vcc, void *cell, int flags)
873{
874    int conn;
875    struct uni_cell_header *uni_cell_header = (struct uni_cell_header *)cell;
876    int desc_base;
877    struct sk_buff *skb;
878    struct tx_descriptor reg_desc = {0};
879
880    if ( ((uni_cell_header->pti == ATM_PTI_SEGF5 || uni_cell_header->pti == ATM_PTI_E2EF5)
881        && find_vpivci(uni_cell_header->vpi, uni_cell_header->vci) < 0)
882        || ((uni_cell_header->vci == 0x03 || uni_cell_header->vci == 0x04)
883        && find_vpi(uni_cell_header->vpi) < 0) )
884        return -EINVAL;
885
886    if ( !g_showtime ) {
887        err("not in showtime");
888        return -EIO;
889    }
890
891    conn = find_vcc(vcc);
892    if ( conn < 0 ) {
893        err("FIND_VCC_FAIL");
894        return -EINVAL;
895    }
896
897    skb = alloc_skb_tx(CELL_SIZE);
898    if ( skb == NULL ) {
899        err("ALLOC_SKB_TX_FAIL");
900        return -ENOMEM;
901    }
902    memcpy(skb->data, cell, CELL_SIZE);
903
904    reg_desc.dataptr = (unsigned int)skb->data >> 2;
905    reg_desc.datalen = CELL_SIZE;
906    reg_desc.byteoff = 0;
907    reg_desc.iscell = 1;
908
909    reg_desc.own = 1;
910    reg_desc.c = 1;
911    reg_desc.sop = reg_desc.eop = 1;
912
913    desc_base = get_tx_desc(conn);
914    if ( desc_base < 0 ) {
915        dev_kfree_skb_any(skb);
916        err("ALLOC_TX_CONNECTION_FAIL");
917        return -EIO;
918    }
919
920    if ( vcc->stats )
921        atomic_inc(&vcc->stats->tx);
922
923    /* update descriptor send pointer */
924    if ( g_atm_priv_data.conn[conn].tx_skb[desc_base] != NULL )
925        dev_kfree_skb_any(g_atm_priv_data.conn[conn].tx_skb[desc_base]);
926    g_atm_priv_data.conn[conn].tx_skb[desc_base] = skb;
927
928    /* write discriptor to memory and write back cache */
929    g_atm_priv_data.conn[conn].tx_desc[desc_base] = reg_desc;
930    dma_cache_wback((unsigned long)skb->data, CELL_SIZE);
931
932    dump_skb(skb, DUMP_SKB_LEN, (char *)__func__, 0, conn, 1);
933
934    if ( vcc->qos.aal == ATM_AAL5 && (ifx_atm_dbg_enable & DBG_ENABLE_MASK_MAC_SWAP) ) {
935        skb_swap(skb, reg_desc.byteoff);
936    }
937
938    mailbox_signal(conn, 1);
939
940    adsl_led_flash();
941
942    return 0;
943}
944
945static int ppe_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags)
946{
947    int conn;
948
949    if ( vcc == NULL || qos == NULL )
950        return -EINVAL;
951
952    conn = find_vcc(vcc);
953    if ( conn < 0 )
954        return -EINVAL;
955
956    set_qsb(vcc, qos, conn);
957
958    return 0;
959}
960
961static INLINE void adsl_led_flash(void)
962{
963#if 0
964#if defined(ENABLE_LED_FRAMEWORK) && ENABLE_LED_FRAMEWORK
965    if ( g_data_led_trigger != NULL )
966        ifx_led_trigger_activate(g_data_led_trigger);
967#else
968    if (!IS_ERR(&ifx_mei_atm_led_blink) && &ifx_mei_atm_led_blink )
969        ifx_mei_atm_led_blink();
970#endif
971#endif
972}
973
974/*
975 * Description:
976 * Add a 32-bit value to 64-bit value, and put result in a 64-bit variable.
977 * Input:
978 * opt1 --- ppe_u64_t, first operand, a 64-bit unsigned integer value
979 * opt2 --- unsigned int, second operand, a 32-bit unsigned integer value
980 * ret --- ppe_u64_t, pointer to a variable to hold result
981 * Output:
982 * none
983 */
984static INLINE void u64_add_u32(ppe_u64_t opt1, unsigned int opt2, ppe_u64_t *ret)
985{
986    ret->l = opt1.l + opt2;
987    if ( ret->l < opt1.l || ret->l < opt2 )
988        ret->h++;
989}
990
991static INLINE struct sk_buff* alloc_skb_rx(void)
992{
993    struct sk_buff *skb;
994
995    skb = dev_alloc_skb(RX_DMA_CH_AAL_BUF_SIZE + DATA_BUFFER_ALIGNMENT);
996    if ( skb != NULL ) {
997        /* must be burst length alignment */
998        if ( ((unsigned int)skb->data & (DATA_BUFFER_ALIGNMENT - 1)) != 0 )
999            skb_reserve(skb, ~((unsigned int)skb->data + (DATA_BUFFER_ALIGNMENT - 1)) & (DATA_BUFFER_ALIGNMENT - 1));
1000        /* pub skb in reserved area "skb->data - 4" */
1001        *((struct sk_buff **)skb->data - 1) = skb;
1002        /* write back and invalidate cache */
1003        dma_cache_wback_inv((unsigned long)skb->data - sizeof(skb), sizeof(skb));
1004        /* invalidate cache */
1005        dma_cache_inv((unsigned long)skb->data, (unsigned int)skb->end - (unsigned int)skb->data);
1006    }
1007
1008    return skb;
1009}
1010
1011static INLINE struct sk_buff* alloc_skb_tx(unsigned int size)
1012{
1013    struct sk_buff *skb;
1014
1015    /* allocate memory including header and padding */
1016    size += TX_INBAND_HEADER_LENGTH + MAX_TX_PACKET_ALIGN_BYTES + MAX_TX_PACKET_PADDING_BYTES;
1017    size &= ~(DATA_BUFFER_ALIGNMENT - 1);
1018    skb = dev_alloc_skb(size + DATA_BUFFER_ALIGNMENT);
1019    /* must be burst length alignment */
1020    if ( skb != NULL )
1021        skb_reserve(skb, (~((unsigned int)skb->data + (DATA_BUFFER_ALIGNMENT - 1)) & (DATA_BUFFER_ALIGNMENT - 1)) + TX_INBAND_HEADER_LENGTH);
1022    return skb;
1023}
1024
1025struct sk_buff* atm_alloc_tx(struct atm_vcc *vcc, unsigned int size)
1026{
1027    int conn;
1028    struct sk_buff *skb;
1029
1030    /* oversize packet */
1031    if ( size > aal5s_max_packet_size ) {
1032        err("atm_alloc_tx: oversize packet");
1033        return NULL;
1034    }
1035    /* send buffer overflow */
1036    if ( atomic_read(&sk_atm(vcc)->sk_wmem_alloc) && !atm_may_send(vcc, size) ) {
1037        err("atm_alloc_tx: send buffer overflow");
1038        return NULL;
1039    }
1040    conn = find_vcc(vcc);
1041    if ( conn < 0 ) {
1042        err("atm_alloc_tx: unknown VCC");
1043        return NULL;
1044    }
1045
1046    skb = dev_alloc_skb(size);
1047    if ( skb == NULL ) {
1048        err("atm_alloc_tx: sk buffer is used up");
1049        return NULL;
1050    }
1051
1052    atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
1053
1054    return skb;
1055}
1056
1057static INLINE void atm_free_tx_skb_vcc(struct sk_buff *skb, struct atm_vcc *vcc)
1058{
1059    if ( vcc->pop != NULL )
1060        vcc->pop(vcc, skb);
1061    else
1062        dev_kfree_skb_any(skb);
1063}
1064
1065static INLINE struct sk_buff *get_skb_rx_pointer(unsigned int dataptr)
1066{
1067    unsigned int skb_dataptr;
1068    struct sk_buff *skb;
1069
1070    skb_dataptr = ((dataptr - 1) << 2) | KSEG1;
1071    skb = *(struct sk_buff **)skb_dataptr;
1072
1073    ASSERT((unsigned int)skb >= KSEG0, "invalid skb - skb = %#08x, dataptr = %#08x", (unsigned int)skb, dataptr);
1074    ASSERT(((unsigned int)skb->data | KSEG1) == ((dataptr << 2) | KSEG1), "invalid skb - skb = %#08x, skb->data = %#08x, dataptr = %#08x", (unsigned int)skb, (unsigned int)skb->data, dataptr);
1075
1076    return skb;
1077}
1078
1079static INLINE int get_tx_desc(unsigned int conn)
1080{
1081    int desc_base = -1;
1082    struct connection *p_conn = &g_atm_priv_data.conn[conn];
1083
1084    if ( p_conn->tx_desc[p_conn->tx_desc_pos].own == 0 ) {
1085        desc_base = p_conn->tx_desc_pos;
1086        if ( ++(p_conn->tx_desc_pos) == dma_tx_descriptor_length )
1087            p_conn->tx_desc_pos = 0;
1088    }
1089
1090    return desc_base;
1091}
1092
1093static INLINE void mailbox_oam_rx_handler(void)
1094{
1095    unsigned int vlddes = WRX_DMA_CHANNEL_CONFIG(RX_DMA_CH_OAM)->vlddes;
1096    struct rx_descriptor reg_desc;
1097    struct uni_cell_header *header;
1098    int conn;
1099    struct atm_vcc *vcc;
1100    unsigned int i;
1101
1102    for ( i = 0; i < vlddes; i++ ) {
1103        do {
1104            reg_desc = g_atm_priv_data.oam_desc[g_atm_priv_data.oam_desc_pos];
1105        } while ( reg_desc.own || !reg_desc.c ); // keep test OWN and C bit until data is ready
1106
1107        header = (struct uni_cell_header *)&g_atm_priv_data.oam_buf[g_atm_priv_data.oam_desc_pos * RX_DMA_CH_OAM_BUF_SIZE];
1108
1109        if ( header->pti == ATM_PTI_SEGF5 || header->pti == ATM_PTI_E2EF5 )
1110            conn = find_vpivci(header->vpi, header->vci);
1111        else if ( header->vci == 0x03 || header->vci == 0x04 )
1112            conn = find_vpi(header->vpi);
1113        else
1114            conn = -1;
1115
1116        if ( conn >= 0 && g_atm_priv_data.conn[conn].vcc != NULL ) {
1117            vcc = g_atm_priv_data.conn[conn].vcc;
1118
1119            if ( vcc->push_oam != NULL )
1120                vcc->push_oam(vcc, header);
1121            else
1122                ifx_push_oam((unsigned char *)header);
1123            adsl_led_flash();
1124        }
1125
1126        reg_desc.byteoff = 0;
1127        reg_desc.datalen = RX_DMA_CH_OAM_BUF_SIZE;
1128        reg_desc.own = 1;
1129        reg_desc.c = 0;
1130
1131        g_atm_priv_data.oam_desc[g_atm_priv_data.oam_desc_pos] = reg_desc;
1132        if ( ++g_atm_priv_data.oam_desc_pos == RX_DMA_CH_OAM_DESC_LEN )
1133            g_atm_priv_data.oam_desc_pos = 0;
1134
1135        mailbox_signal(RX_DMA_CH_OAM, 0);
1136    }
1137}
1138
1139static INLINE void mailbox_aal_rx_handler(void)
1140{
1141    unsigned int vlddes = WRX_DMA_CHANNEL_CONFIG(RX_DMA_CH_AAL)->vlddes;
1142    struct rx_descriptor reg_desc;
1143    int conn;
1144    struct atm_vcc *vcc;
1145    struct sk_buff *skb, *new_skb;
1146    struct rx_inband_trailer *trailer;
1147    unsigned int i;
1148
1149    for ( i = 0; i < vlddes; i++ ) {
1150        do {
1151            reg_desc = g_atm_priv_data.aal_desc[g_atm_priv_data.aal_desc_pos];
1152        } while ( reg_desc.own || !reg_desc.c ); // keep test OWN and C bit until data is ready
1153
1154        conn = reg_desc.id;
1155
1156        if ( g_atm_priv_data.conn[conn].vcc != NULL ) {
1157            vcc = g_atm_priv_data.conn[conn].vcc;
1158
1159            skb = get_skb_rx_pointer(reg_desc.dataptr);
1160
1161            if ( reg_desc.err ) {
1162                if ( vcc->qos.aal == ATM_AAL5 ) {
1163                    trailer = (struct rx_inband_trailer *)((unsigned int)skb->data + ((reg_desc.byteoff + reg_desc.datalen + MAX_RX_PACKET_PADDING_BYTES) & ~MAX_RX_PACKET_PADDING_BYTES));
1164                    if ( trailer->stw_crc )
1165                        g_atm_priv_data.conn[conn].aal5_vcc_crc_err++;
1166                    if ( trailer->stw_ovz )
1167                        g_atm_priv_data.conn[conn].aal5_vcc_oversize_sdu++;
1168                    g_atm_priv_data.wrx_drop_pdu++;
1169                }
1170                if ( vcc->stats ) {
1171                    atomic_inc(&vcc->stats->rx_drop);
1172                    atomic_inc(&vcc->stats->rx_err);
1173                }
1174            }
1175            else if ( atm_charge(vcc, skb->truesize) ) {
1176                new_skb = alloc_skb_rx();
1177                if ( new_skb != NULL ) {
1178                    skb_reserve(skb, reg_desc.byteoff);
1179                    skb_put(skb, reg_desc.datalen);
1180                    ATM_SKB(skb)->vcc = vcc;
1181
1182                    dump_skb(skb, DUMP_SKB_LEN, (char *)__func__, 0, conn, 0);
1183
1184                    vcc->push(vcc, skb);
1185
1186                    if ( vcc->qos.aal == ATM_AAL5 )
1187                        g_atm_priv_data.wrx_pdu++;
1188                    if ( vcc->stats )
1189                        atomic_inc(&vcc->stats->rx);
1190                    adsl_led_flash();
1191
1192                    reg_desc.dataptr = (unsigned int)new_skb->data >> 2;
1193                }
1194                else {
1195                    atm_return(vcc, skb->truesize);
1196                    if ( vcc->qos.aal == ATM_AAL5 )
1197                        g_atm_priv_data.wrx_drop_pdu++;
1198                    if ( vcc->stats )
1199                        atomic_inc(&vcc->stats->rx_drop);
1200                }
1201            }
1202            else {
1203                if ( vcc->qos.aal == ATM_AAL5 )
1204                    g_atm_priv_data.wrx_drop_pdu++;
1205                if ( vcc->stats )
1206                    atomic_inc(&vcc->stats->rx_drop);
1207            }
1208        }
1209        else {
1210            g_atm_priv_data.wrx_drop_pdu++;
1211        }
1212
1213        reg_desc.byteoff = 0;
1214        reg_desc.datalen = RX_DMA_CH_AAL_BUF_SIZE;
1215        reg_desc.own = 1;
1216        reg_desc.c = 0;
1217
1218        g_atm_priv_data.aal_desc[g_atm_priv_data.aal_desc_pos] = reg_desc;
1219        if ( ++g_atm_priv_data.aal_desc_pos == dma_rx_descriptor_length )
1220            g_atm_priv_data.aal_desc_pos = 0;
1221
1222        mailbox_signal(RX_DMA_CH_AAL, 0);
1223    }
1224}
1225
1226#if defined(ENABLE_TASKLET) && ENABLE_TASKLET
1227static void do_ppe_tasklet(unsigned long arg)
1228{
1229    *MBOX_IGU1_ISRC = *MBOX_IGU1_ISR;
1230    mailbox_oam_rx_handler();
1231    mailbox_aal_rx_handler();
1232    if ( (*MBOX_IGU1_ISR & ((1 << RX_DMA_CH_AAL) | (1 << RX_DMA_CH_OAM))) != 0 )
1233        tasklet_schedule(&g_dma_tasklet);
1234    else
1235        enable_irq(PPE_MAILBOX_IGU1_INT);
1236}
1237#endif
1238
1239static irqreturn_t mailbox_irq_handler(int irq, void *dev_id)
1240{
1241    if ( !*MBOX_IGU1_ISR )
1242        return IRQ_HANDLED;
1243
1244#if defined(ENABLE_TASKLET) && ENABLE_TASKLET
1245    disable_irq(PPE_MAILBOX_IGU1_INT);
1246    tasklet_schedule(&g_dma_tasklet);
1247#else
1248    *MBOX_IGU1_ISRC = *MBOX_IGU1_ISR;
1249    mailbox_oam_rx_handler();
1250    mailbox_aal_rx_handler();
1251#endif
1252
1253    return IRQ_HANDLED;
1254}
1255
1256static INLINE void mailbox_signal(unsigned int queue, int is_tx)
1257{
1258    int count = 1000;
1259
1260    if ( is_tx ) {
1261        while ( MBOX_IGU3_ISR_ISR(queue + FIRST_QSB_QID + 16) && count)
1262        count--;
1263        *MBOX_IGU3_ISRS = MBOX_IGU3_ISRS_SET(queue + FIRST_QSB_QID + 16);
1264    }
1265    else {
1266        while ( MBOX_IGU3_ISR_ISR(queue) && count)
1267        count--;
1268        *MBOX_IGU3_ISRS = MBOX_IGU3_ISRS_SET(queue);
1269    }
1270    ASSERT(count != 0, "MBOX_IGU3_ISR = 0x%08x", ltq_r32(MBOX_IGU3_ISR));
1271}
1272
1273static void set_qsb(struct atm_vcc *vcc, struct atm_qos *qos, unsigned int queue)
1274{
1275    struct clk *clk = clk_get(0, "fpi");
1276    unsigned int qsb_clk = clk_get_rate(clk);
1277    unsigned int qsb_qid = queue + FIRST_QSB_QID;
1278    union qsb_queue_parameter_table qsb_queue_parameter_table = {{0}};
1279    union qsb_queue_vbr_parameter_table qsb_queue_vbr_parameter_table = {{0}};
1280    unsigned int tmp;
1281
1282#if defined(DEBUG_QOS) && DEBUG_QOS
1283    if ( (ifx_atm_dbg_enable & DBG_ENABLE_MASK_DUMP_QOS) ) {
1284        static char *str_traffic_class[9] = {
1285            "ATM_NONE",
1286            "ATM_UBR",
1287            "ATM_CBR",
1288            "ATM_VBR",
1289            "ATM_ABR",
1290            "ATM_ANYCLASS",
1291            "ATM_VBR_RT",
1292            "ATM_UBR_PLUS",
1293            "ATM_MAX_PCR"
1294        };
1295        printk(KERN_INFO "QoS Parameters:\n");
1296        printk(KERN_INFO "\tAAL : %d\n", qos->aal);
1297        printk(KERN_INFO "\tTX Traffic Class: %s\n", str_traffic_class[qos->txtp.traffic_class]);
1298        printk(KERN_INFO "\tTX Max PCR : %d\n", qos->txtp.max_pcr);
1299        printk(KERN_INFO "\tTX Min PCR : %d\n", qos->txtp.min_pcr);
1300        printk(KERN_INFO "\tTX PCR : %d\n", qos->txtp.pcr);
1301        printk(KERN_INFO "\tTX Max CDV : %d\n", qos->txtp.max_cdv);
1302        printk(KERN_INFO "\tTX Max SDU : %d\n", qos->txtp.max_sdu);
1303        printk(KERN_INFO "\tTX SCR : %d\n", qos->txtp.scr);
1304        printk(KERN_INFO "\tTX MBS : %d\n", qos->txtp.mbs);
1305        printk(KERN_INFO "\tTX CDV : %d\n", qos->txtp.cdv);
1306        printk(KERN_INFO "\tRX Traffic Class: %s\n", str_traffic_class[qos->rxtp.traffic_class]);
1307        printk(KERN_INFO "\tRX Max PCR : %d\n", qos->rxtp.max_pcr);
1308        printk(KERN_INFO "\tRX Min PCR : %d\n", qos->rxtp.min_pcr);
1309        printk(KERN_INFO "\tRX PCR : %d\n", qos->rxtp.pcr);
1310        printk(KERN_INFO "\tRX Max CDV : %d\n", qos->rxtp.max_cdv);
1311        printk(KERN_INFO "\tRX Max SDU : %d\n", qos->rxtp.max_sdu);
1312        printk(KERN_INFO "\tRX SCR : %d\n", qos->rxtp.scr);
1313        printk(KERN_INFO "\tRX MBS : %d\n", qos->rxtp.mbs);
1314        printk(KERN_INFO "\tRX CDV : %d\n", qos->rxtp.cdv);
1315    }
1316#endif // defined(DEBUG_QOS) && DEBUG_QOS
1317
1318    /*
1319     * Peak Cell Rate (PCR) Limiter
1320     */
1321    if ( qos->txtp.max_pcr == 0 )
1322        qsb_queue_parameter_table.bit.tp = 0; /* disable PCR limiter */
1323    else {
1324        /* peak cell rate would be slightly lower than requested [maximum_rate / pcr = (qsb_clock / 8) * (time_step / 4) / pcr] */
1325        tmp = ((qsb_clk * qsb_tstep) >> 5) / qos->txtp.max_pcr + 1;
1326        /* check if overflow takes place */
1327        qsb_queue_parameter_table.bit.tp = tmp > QSB_TP_TS_MAX ? QSB_TP_TS_MAX : tmp;
1328    }
1329
1330    // A funny issue. Create two PVCs, one UBR and one UBR with max_pcr.
1331    // Send packets to these two PVCs at same time, it trigger strange behavior.
1332    // In A1, RAM from 0x80000000 to 0x0x8007FFFF was corrupted with fixed pattern 0x00000000 0x40000000.
1333    // In A4, PPE firmware keep emiting unknown cell and do not respond to driver.
1334    // To work around, create UBR always with max_pcr.
1335    // If user want to create UBR without max_pcr, we give a default one larger than line-rate.
1336    if ( qos->txtp.traffic_class == ATM_UBR && qsb_queue_parameter_table.bit.tp == 0 ) {
1337        int port = g_atm_priv_data.conn[queue].port;
1338        unsigned int max_pcr = g_atm_priv_data.port[port].tx_max_cell_rate + 1000;
1339
1340        tmp = ((qsb_clk * qsb_tstep) >> 5) / max_pcr + 1;
1341        if ( tmp > QSB_TP_TS_MAX )
1342            tmp = QSB_TP_TS_MAX;
1343        else if ( tmp < 1 )
1344            tmp = 1;
1345        qsb_queue_parameter_table.bit.tp = tmp;
1346    }
1347
1348    /*
1349     * Weighted Fair Queueing Factor (WFQF)
1350     */
1351    switch ( qos->txtp.traffic_class ) {
1352    case ATM_CBR:
1353    case ATM_VBR_RT:
1354        /* real time queue gets weighted fair queueing bypass */
1355        qsb_queue_parameter_table.bit.wfqf = 0;
1356        break;
1357    case ATM_VBR_NRT:
1358    case ATM_UBR_PLUS:
1359        /* WFQF calculation here is based on virtual cell rates, to reduce granularity for high rates */
1360        /* WFQF is maximum cell rate / garenteed cell rate */
1361        /* wfqf = qsb_minimum_cell_rate * QSB_WFQ_NONUBR_MAX / requested_minimum_peak_cell_rate */
1362        if ( qos->txtp.min_pcr == 0 )
1363            qsb_queue_parameter_table.bit.wfqf = QSB_WFQ_NONUBR_MAX;
1364        else
1365        {
1366            tmp = QSB_GCR_MIN * QSB_WFQ_NONUBR_MAX / qos->txtp.min_pcr;
1367            if ( tmp == 0 )
1368                qsb_queue_parameter_table.bit.wfqf = 1;
1369            else if ( tmp > QSB_WFQ_NONUBR_MAX )
1370                qsb_queue_parameter_table.bit.wfqf = QSB_WFQ_NONUBR_MAX;
1371            else
1372                qsb_queue_parameter_table.bit.wfqf = tmp;
1373        }
1374        break;
1375    default:
1376    case ATM_UBR:
1377        qsb_queue_parameter_table.bit.wfqf = QSB_WFQ_UBR_BYPASS;
1378    }
1379
1380    /*
1381     * Sustained Cell Rate (SCR) Leaky Bucket Shaper VBR.0/VBR.1
1382     */
1383    if ( qos->txtp.traffic_class == ATM_VBR_RT || qos->txtp.traffic_class == ATM_VBR_NRT ) {
1384        if ( qos->txtp.scr == 0 ) {
1385            /* disable shaper */
1386            qsb_queue_vbr_parameter_table.bit.taus = 0;
1387            qsb_queue_vbr_parameter_table.bit.ts = 0;
1388        }
1389        else {
1390            /* Cell Loss Priority (CLP) */
1391            if ( (vcc->atm_options & ATM_ATMOPT_CLP) )
1392                /* CLP1 */
1393                qsb_queue_parameter_table.bit.vbr = 1;
1394            else
1395                /* CLP0 */
1396                qsb_queue_parameter_table.bit.vbr = 0;
1397            /* Rate Shaper Parameter (TS) and Burst Tolerance Parameter for SCR (tauS) */
1398            tmp = ((qsb_clk * qsb_tstep) >> 5) / qos->txtp.scr + 1;
1399            qsb_queue_vbr_parameter_table.bit.ts = tmp > QSB_TP_TS_MAX ? QSB_TP_TS_MAX : tmp;
1400            tmp = (qos->txtp.mbs - 1) * (qsb_queue_vbr_parameter_table.bit.ts - qsb_queue_parameter_table.bit.tp) / 64;
1401            if ( tmp == 0 )
1402                qsb_queue_vbr_parameter_table.bit.taus = 1;
1403            else if ( tmp > QSB_TAUS_MAX )
1404                qsb_queue_vbr_parameter_table.bit.taus = QSB_TAUS_MAX;
1405            else
1406                qsb_queue_vbr_parameter_table.bit.taus = tmp;
1407        }
1408    }
1409    else {
1410        qsb_queue_vbr_parameter_table.bit.taus = 0;
1411        qsb_queue_vbr_parameter_table.bit.ts = 0;
1412    }
1413
1414    /* Queue Parameter Table (QPT) */
1415    *QSB_RTM = QSB_RTM_DM_SET(QSB_QPT_SET_MASK);
1416    *QSB_RTD = QSB_RTD_TTV_SET(qsb_queue_parameter_table.dword);
1417    *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);
1418#if defined(DEBUG_QOS) && DEBUG_QOS
1419    if ( (ifx_atm_dbg_enable & DBG_ENABLE_MASK_DUMP_QOS) )
1420        printk("QPT: QSB_RTM (%08X) = 0x%08X, QSB_RTD (%08X) = 0x%08X, QSB_RAMAC (%08X) = 0x%08X\n", (unsigned int)QSB_RTM, *QSB_RTM, (unsigned int)QSB_RTD, *QSB_RTD, (unsigned int)QSB_RAMAC, *QSB_RAMAC);
1421#endif
1422    /* Queue VBR Paramter Table (QVPT) */
1423    *QSB_RTM = QSB_RTM_DM_SET(QSB_QVPT_SET_MASK);
1424    *QSB_RTD = QSB_RTD_TTV_SET(qsb_queue_vbr_parameter_table.dword);
1425    *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);
1426#if defined(DEBUG_QOS) && DEBUG_QOS
1427    if ( (ifx_atm_dbg_enable & DBG_ENABLE_MASK_DUMP_QOS) )
1428        printk("QVPT: QSB_RTM (%08X) = 0x%08X, QSB_RTD (%08X) = 0x%08X, QSB_RAMAC (%08X) = 0x%08X\n", (unsigned int)QSB_RTM, *QSB_RTM, (unsigned int)QSB_RTD, *QSB_RTD, (unsigned int)QSB_RAMAC, *QSB_RAMAC);
1429#endif
1430
1431#if defined(DEBUG_QOS) && DEBUG_QOS
1432    if ( (ifx_atm_dbg_enable & DBG_ENABLE_MASK_DUMP_QOS) ) {
1433        printk("set_qsb\n");
1434        printk(" qsb_clk = %lu\n", (unsigned long)qsb_clk);
1435        printk(" qsb_queue_parameter_table.bit.tp = %d\n", (int)qsb_queue_parameter_table.bit.tp);
1436        printk(" qsb_queue_parameter_table.bit.wfqf = %d (0x%08X)\n", (int)qsb_queue_parameter_table.bit.wfqf, (int)qsb_queue_parameter_table.bit.wfqf);
1437        printk(" qsb_queue_parameter_table.bit.vbr = %d\n", (int)qsb_queue_parameter_table.bit.vbr);
1438        printk(" qsb_queue_parameter_table.dword = 0x%08X\n", (int)qsb_queue_parameter_table.dword);
1439        printk(" qsb_queue_vbr_parameter_table.bit.ts = %d\n", (int)qsb_queue_vbr_parameter_table.bit.ts);
1440        printk(" qsb_queue_vbr_parameter_table.bit.taus = %d\n", (int)qsb_queue_vbr_parameter_table.bit.taus);
1441        printk(" qsb_queue_vbr_parameter_table.dword = 0x%08X\n", (int)qsb_queue_vbr_parameter_table.dword);
1442    }
1443#endif
1444}
1445
1446static void qsb_global_set(void)
1447{
1448    struct clk *clk = clk_get(0, "fpi");
1449    unsigned int qsb_clk = clk_get_rate(clk);
1450    int i;
1451    unsigned int tmp1, tmp2, tmp3;
1452
1453    *QSB_ICDV = QSB_ICDV_TAU_SET(qsb_tau);
1454    *QSB_SBL = QSB_SBL_SBL_SET(qsb_srvm);
1455    *QSB_CFG = QSB_CFG_TSTEPC_SET(qsb_tstep >> 1);
1456#if defined(DEBUG_QOS) && DEBUG_QOS
1457    if ( (ifx_atm_dbg_enable & DBG_ENABLE_MASK_DUMP_QOS) ) {
1458        printk("qsb_clk = %u\n", qsb_clk);
1459        printk("QSB_ICDV (%08X) = %d (%d), QSB_SBL (%08X) = %d (%d), QSB_CFG (%08X) = %d (%d)\n", (unsigned int)QSB_ICDV, *QSB_ICDV, QSB_ICDV_TAU_SET(qsb_tau), (unsigned int)QSB_SBL, *QSB_SBL, QSB_SBL_SBL_SET(qsb_srvm), (unsigned int)QSB_CFG, *QSB_CFG, QSB_CFG_TSTEPC_SET(qsb_tstep >> 1));
1460    }
1461#endif
1462
1463    /*
1464     * set SCT and SPT per port
1465     */
1466    for ( i = 0; i < ATM_PORT_NUMBER; i++ ) {
1467        if ( g_atm_priv_data.port[i].tx_max_cell_rate != 0 ) {
1468            tmp1 = ((qsb_clk * qsb_tstep) >> 1) / g_atm_priv_data.port[i].tx_max_cell_rate;
1469            tmp2 = tmp1 >> 6; /* integer value of Tsb */
1470            tmp3 = (tmp1 & ((1 << 6) - 1)) + 1; /* fractional part of Tsb */
1471            /* carry over to integer part (?) */
1472            if ( tmp3 == (1 << 6) )
1473            {
1474                tmp3 = 0;
1475                tmp2++;
1476            }
1477            if ( tmp2 == 0 )
1478                tmp2 = tmp3 = 1;
1479            /* 1. set mask */
1480            /* 2. write value to data transfer register */
1481            /* 3. start the tranfer */
1482            /* SCT (FracRate) */
1483            *QSB_RTM = QSB_RTM_DM_SET(QSB_SET_SCT_MASK);
1484            *QSB_RTD = QSB_RTD_TTV_SET(tmp3);
1485            *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);
1486#if defined(DEBUG_QOS) && DEBUG_QOS
1487            if ( (ifx_atm_dbg_enable & DBG_ENABLE_MASK_DUMP_QOS) )
1488                printk("SCT: QSB_RTM (%08X) = 0x%08X, QSB_RTD (%08X) = 0x%08X, QSB_RAMAC (%08X) = 0x%08X\n", (unsigned int)QSB_RTM, *QSB_RTM, (unsigned int)QSB_RTD, *QSB_RTD, (unsigned int)QSB_RAMAC, *QSB_RAMAC);
1489#endif
1490            /* SPT (SBV + PN + IntRage) */
1491            *QSB_RTM = QSB_RTM_DM_SET(QSB_SET_SPT_MASK);
1492            *QSB_RTD = QSB_RTD_TTV_SET(QSB_SPT_SBV_VALID | QSB_SPT_PN_SET(i & 0x01) | QSB_SPT_INTRATE_SET(tmp2));
1493            *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);
1494#if defined(DEBUG_QOS) && DEBUG_QOS
1495            if ( (ifx_atm_dbg_enable & DBG_ENABLE_MASK_DUMP_QOS) )
1496                printk("SPT: QSB_RTM (%08X) = 0x%08X, QSB_RTD (%08X) = 0x%08X, QSB_RAMAC (%08X) = 0x%08X\n", (unsigned int)QSB_RTM, *QSB_RTM, (unsigned int)QSB_RTD, *QSB_RTD, (unsigned int)QSB_RAMAC, *QSB_RAMAC);
1497#endif
1498        }
1499    }
1500}
1501
1502static INLINE void set_htu_entry(unsigned int vpi, unsigned int vci, unsigned int queue, int aal5, int is_retx)
1503{
1504    struct htu_entry htu_entry = { res1: 0x00,
1505                                    clp: is_retx ? 0x01 : 0x00,
1506                                    pid: g_atm_priv_data.conn[queue].port & 0x01,
1507                                    vpi: vpi,
1508                                    vci: vci,
1509                                    pti: 0x00,
1510                                    vld: 0x01};
1511
1512    struct htu_mask htu_mask = { set: 0x01,
1513#if !defined(ENABLE_ATM_RETX) || !ENABLE_ATM_RETX
1514                                    clp: 0x01,
1515                                    pid_mask: 0x02,
1516#else
1517                                    clp: g_retx_htu ? 0x00 : 0x01,
1518                                    pid_mask: RETX_MODE_CFG->retx_en ? 0x03 : 0x02,
1519#endif
1520                                    vpi_mask: 0x00,
1521#if !defined(ENABLE_ATM_RETX) || !ENABLE_ATM_RETX
1522                                    vci_mask: 0x0000,
1523#else
1524                                    vci_mask: RETX_MODE_CFG->retx_en ? 0xFF00 : 0x0000,
1525#endif
1526                                    pti_mask: 0x03, // 0xx, user data
1527                                    clear: 0x00};
1528
1529    struct htu_result htu_result = {res1: 0x00,
1530                                    cellid: queue,
1531                                    res2: 0x00,
1532                                    type: aal5 ? 0x00 : 0x01,
1533                                    ven: 0x01,
1534                                    res3: 0x00,
1535                                    qid: queue};
1536
1537    *HTU_RESULT(queue + OAM_HTU_ENTRY_NUMBER) = htu_result;
1538    *HTU_MASK(queue + OAM_HTU_ENTRY_NUMBER) = htu_mask;
1539    *HTU_ENTRY(queue + OAM_HTU_ENTRY_NUMBER) = htu_entry;
1540}
1541
1542static INLINE void clear_htu_entry(unsigned int queue)
1543{
1544    HTU_ENTRY(queue + OAM_HTU_ENTRY_NUMBER)->vld = 0;
1545}
1546
1547static void validate_oam_htu_entry(void)
1548{
1549    HTU_ENTRY(OAM_F4_SEG_HTU_ENTRY)->vld = 1;
1550    HTU_ENTRY(OAM_F4_TOT_HTU_ENTRY)->vld = 1;
1551    HTU_ENTRY(OAM_F5_HTU_ENTRY)->vld = 1;
1552#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
1553    HTU_ENTRY(OAM_ARQ_HTU_ENTRY)->vld = 1;
1554#endif
1555}
1556
1557static void invalidate_oam_htu_entry(void)
1558{
1559    HTU_ENTRY(OAM_F4_SEG_HTU_ENTRY)->vld = 0;
1560    HTU_ENTRY(OAM_F4_TOT_HTU_ENTRY)->vld = 0;
1561    HTU_ENTRY(OAM_F5_HTU_ENTRY)->vld = 0;
1562#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
1563    HTU_ENTRY(OAM_ARQ_HTU_ENTRY)->vld = 0;
1564#endif
1565}
1566
1567static INLINE int find_vpi(unsigned int vpi)
1568{
1569    int i;
1570    unsigned int bit;
1571
1572    for ( i = 0, bit = 1; i < MAX_PVC_NUMBER; i++, bit <<= 1 ) {
1573        if ( (g_atm_priv_data.conn_table & bit) != 0
1574            && g_atm_priv_data.conn[i].vcc != NULL
1575            && vpi == g_atm_priv_data.conn[i].vcc->vpi )
1576            return i;
1577    }
1578
1579    return -1;
1580}
1581
1582static INLINE int find_vpivci(unsigned int vpi, unsigned int vci)
1583{
1584    int i;
1585    unsigned int bit;
1586
1587    for ( i = 0, bit = 1; i < MAX_PVC_NUMBER; i++, bit <<= 1 ) {
1588        if ( (g_atm_priv_data.conn_table & bit) != 0
1589            && g_atm_priv_data.conn[i].vcc != NULL
1590            && vpi == g_atm_priv_data.conn[i].vcc->vpi
1591            && vci == g_atm_priv_data.conn[i].vcc->vci )
1592            return i;
1593    }
1594
1595    return -1;
1596}
1597
1598static INLINE int find_vcc(struct atm_vcc *vcc)
1599{
1600    int i;
1601    unsigned int bit;
1602
1603    for ( i = 0, bit = 1; i < MAX_PVC_NUMBER; i++, bit <<= 1 ) {
1604        if ( (g_atm_priv_data.conn_table & bit) != 0
1605            && g_atm_priv_data.conn[i].vcc == vcc )
1606            return i;
1607    }
1608
1609    return -1;
1610}
1611
1612#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
1613
1614static void retx_polling_func(unsigned long arg)
1615{
1616    int sys_flag;
1617    volatile struct dsl_param *p_dsl_param;
1618    int new_retx_htu;
1619    int retx_en;
1620    int i, max_htu;
1621
1622    local_irq_save(sys_flag);
1623    if ( g_retx_playout_buffer == 0 && g_xdata_addr != NULL && (((volatile struct dsl_param *)g_xdata_addr)->RetxEnable || ((volatile struct dsl_param *)g_xdata_addr)->ServiceSpecificReTx) ) {
1624        local_irq_restore(sys_flag);
1625        g_retx_playout_buffer = __get_free_pages(GFP_KERNEL, RETX_PLAYOUT_BUFFER_ORDER);
1626        if ( g_retx_playout_buffer == 0 )
1627            panic("no memory for g_retx_playout_buffer\n");
1628        memset((void *)g_retx_playout_buffer, 0, RETX_PLAYOUT_BUFFER_SIZE);
1629        dma_cache_inv(g_retx_playout_buffer, RETX_PLAYOUT_BUFFER_SIZE);
1630    }
1631    else
1632        local_irq_restore(sys_flag);
1633
1634
1635    local_irq_save(sys_flag);
1636    if ( g_xdata_addr != NULL ) {
1637        p_dsl_param = (volatile struct dsl_param *)g_xdata_addr;
1638        g_retx_polling_cnt += RETX_POLLING_INTERVAL;
1639
1640        if ( p_dsl_param->update_flag ) {
1641            do_gettimeofday(&g_retx_polling_start);
1642
1643            g_dsl_param = *p_dsl_param;
1644
1645            // we always enable retx (just for test purpose)
1646            //g_dsl_param.RetxEnable = 1;
1647            //RETX_TSYNC_CFG->fw_alpha = 0;
1648
1649            if ( g_dsl_param.RetxEnable || g_dsl_param.ServiceSpecificReTx ) {
1650                // ReTX enabled
1651                // MIB counter updated for each polling
1652                p_dsl_param->RxDtuCorruptedCNT = *RxDTUCorruptedCNT;
1653                p_dsl_param->RxRetxDtuUnCorrectedCNT = *RxRetxDTUUncorrectedCNT;
1654                p_dsl_param->RxLastEFB = *RxLastEFBCNT;
1655                p_dsl_param->RxDtuCorrectedCNT = *RxDTUCorrectedCNT;
1656
1657                // for RETX paramters, we check only once for every second
1658                if ( g_retx_polling_cnt < HZ )
1659                    goto _clear_update_flag;
1660
1661                g_retx_polling_cnt -= HZ;
1662
1663                if ( g_dsl_param.ServiceSpecificReTx && g_dsl_param.ReTxPVC == 0 )
1664                    new_retx_htu = 1;
1665                else
1666                    new_retx_htu = 0;
1667
1668                // default fw_alpha equals to default hardware alpha
1669                RETX_TSYNC_CFG->fw_alpha = 0;
1670
1671                RETX_TD_CFG->td_max = g_dsl_param.MaxDelayrt;
1672                RETX_TD_CFG->td_min = g_dsl_param.MinDelayrt;
1673
1674                *RETX_PLAYOUT_BUFFER_BASE = ((((unsigned int)g_retx_playout_buffer | KSEG1) + 15) & 0xFFFFFFF0) >> 2;
1675
1676                if ( g_dsl_param.ServiceSpecificReTx ) {
1677                    *RETX_SERVICE_HEADER_CFG= g_dsl_param.ReTxPVC << 4;
1678                    if ( g_dsl_param.ReTxPVC == 0 )
1679                        *RETX_MASK_HEADER_CFG = 1;
1680                    else
1681                        *RETX_MASK_HEADER_CFG = 0;
1682                }
1683                else {
1684                    *RETX_SERVICE_HEADER_CFG= 0;
1685                    *RETX_MASK_HEADER_CFG = 0;
1686                }
1687
1688                retx_en = 1;
1689            }
1690            else {
1691                // ReTX disabled
1692
1693                new_retx_htu = 0;
1694
1695                RETX_TSYNC_CFG->fw_alpha = 7;
1696
1697                *RETX_SERVICE_HEADER_CFG = 0;
1698                *RETX_MASK_HEADER_CFG = 0;
1699
1700                retx_en = 0;
1701            }
1702
1703
1704            if ( retx_en != RETX_MODE_CFG->retx_en ) {
1705                unsigned int pid_mask, vci_mask;
1706
1707                if ( retx_en ) {
1708                    pid_mask = 0x03;
1709                    vci_mask = 0xFF00;
1710                }
1711                else {
1712                    pid_mask = 0x02;
1713                    vci_mask = 0x0000;
1714                }
1715
1716                max_htu = *CFG_WRX_HTUTS;
1717                for ( i = OAM_HTU_ENTRY_NUMBER; i < max_htu; i++ )
1718                    if ( HTU_ENTRY(i)->vld ) {
1719                        HTU_MASK(i)->pid_mask = pid_mask;
1720                        HTU_MASK(i)->vci_mask = vci_mask;
1721                    }
1722            }
1723
1724            if ( new_retx_htu != g_retx_htu ) {
1725                int conn, retx_conn;
1726
1727                g_retx_htu = new_retx_htu;
1728
1729                if ( g_retx_htu ) {
1730                    max_htu = *CFG_WRX_HTUTS;
1731                    for ( i = OAM_HTU_ENTRY_NUMBER; i < max_htu; i++ )
1732                        if ( HTU_ENTRY(i)->vld )
1733                            HTU_MASK(i)->clp = 0;
1734
1735                    for ( conn = 0; conn < MAX_PVC_NUMBER; conn++ )
1736                        if ( g_atm_priv_data.conn[conn].vcc && g_atm_priv_data.conn[conn].vcc->qos.aal == ATM_AAL5 && !HTU_ENTRY(conn + OAM_HTU_ENTRY_NUMBER)->clp ) {
1737                            retx_conn = (conn + 8) % 16; // ReTX queue
1738
1739                            if ( retx_conn < MAX_PVC_NUMBER && test_and_set_bit(retx_conn, &g_atm_priv_data.conn_table) == 0 ) {
1740                                g_atm_priv_data.conn[retx_conn].vcc = g_atm_priv_data.conn[conn].vcc;
1741                                set_htu_entry(g_atm_priv_data.conn[conn].vcc->vpi, g_atm_priv_data.conn[conn].vcc->vci, retx_conn, g_atm_priv_data.conn[conn].vcc->qos.aal == ATM_AAL5 ? 1 : 0, 1);
1742                            }
1743                            else {
1744                                err("Queue number %d for ReTX queue of PVC(%d.%d) is not available!", retx_conn, g_atm_priv_data.conn[conn].vcc->vpi, g_atm_priv_data.conn[conn].vcc->vci);
1745                            }
1746                        }
1747                }
1748                else
1749                {
1750                    for ( retx_conn = 0; retx_conn < MAX_PVC_NUMBER; retx_conn++ )
1751                        if ( g_atm_priv_data.conn[retx_conn].vcc && HTU_ENTRY(retx_conn + OAM_HTU_ENTRY_NUMBER)->clp ) {
1752                            clear_htu_entry(retx_conn);
1753                            g_atm_priv_data.conn[retx_conn].vcc = NULL;
1754                            g_atm_priv_data.conn[retx_conn].aal5_vcc_crc_err = 0;
1755                            g_atm_priv_data.conn[retx_conn].aal5_vcc_oversize_sdu = 0;
1756                            clear_bit(retx_conn, &g_atm_priv_data.conn_table);
1757                        }
1758
1759                    max_htu = *CFG_WRX_HTUTS;
1760                    for ( i = OAM_HTU_ENTRY_NUMBER; i < max_htu; i++ )
1761                        if ( HTU_ENTRY(i)->vld )
1762                            HTU_MASK(i)->clp = 1;
1763                }
1764            }
1765
1766            RETX_MODE_CFG->retx_en = retx_en;
1767
1768_clear_update_flag:
1769            p_dsl_param->update_flag = 0;
1770
1771            do_gettimeofday(&g_retx_polling_end);
1772        }
1773
1774        g_retx_polling_timer.expires = jiffies + RETX_POLLING_INTERVAL;
1775        add_timer(&g_retx_polling_timer);
1776    }
1777    local_irq_restore(sys_flag);
1778}
1779
1780static int init_atm_tc_retrans_param(void)
1781{
1782    int i = 0;
1783    struct DTU_stat_info reset_val;
1784
1785    RETX_MODE_CFG->invld_range = 128;
1786    RETX_MODE_CFG->buff_size = RETX_PLAYOUT_FW_BUFF_SIZE > 4096/32 ? 4096/32 : RETX_PLAYOUT_FW_BUFF_SIZE ;
1787    RETX_MODE_CFG->retx_en = 1;
1788
1789    // default fw_alpha equals to default hardware alpha
1790    RETX_TSYNC_CFG->fw_alpha = 7;
1791    RETX_TSYNC_CFG->sync_inp = 0;
1792
1793    RETX_TD_CFG->td_max = 0;
1794    RETX_TD_CFG->td_min = 0;
1795
1796    // *RETX_PLAYOUT_BUFFER_BASE = KSEG1ADDR(g_retx_playout_buffer); // need " >> 2 " ?
1797    *RETX_PLAYOUT_BUFFER_BASE = ((((unsigned int)g_retx_playout_buffer | KSEG1) + 15) & 0xFFFFFFF0) >> 2;
1798
1799    *RETX_SERVICE_HEADER_CFG = 0;
1800    *RETX_MASK_HEADER_CFG = 0;
1801
1802    // 20us
1803    RETX_MIB_TIMER_CFG->tick_cycle = 4800;
1804    RETX_MIB_TIMER_CFG->ticks_per_sec = 50000;
1805
1806    *LAST_DTU_SID_IN = 255;
1807    *RFBI_FIRST_CW = 1;
1808    // init DTU_STAT_INFO
1809
1810    memset(&reset_val, 0, sizeof(reset_val));
1811    reset_val.dtu_rd_ptr = reset_val.dtu_wr_ptr = 0xffff;
1812
1813    for(i = 0 ; i < 256; i ++) {
1814        DTU_STAT_INFO[i] = reset_val;
1815    }
1816    return 0;
1817}
1818
1819static void clear_atm_tc_retrans_param(void)
1820{
1821    if ( g_retx_playout_buffer ) {
1822        free_pages(g_retx_playout_buffer, RETX_PLAYOUT_BUFFER_ORDER);
1823        g_retx_playout_buffer = 0;
1824    }
1825}
1826
1827#endif
1828
1829#if defined(DEBUG_DUMP_SKB) && DEBUG_DUMP_SKB
1830static void dump_skb(struct sk_buff *skb, unsigned int len, char *title, int port, int ch, int is_tx)
1831{
1832    int i;
1833
1834    if ( !(ifx_atm_dbg_enable & (is_tx ? DBG_ENABLE_MASK_DUMP_SKB_TX : DBG_ENABLE_MASK_DUMP_SKB_RX)) )
1835        return;
1836
1837    if ( skb->len < len )
1838        len = skb->len;
1839
1840    if ( len > RX_DMA_CH_AAL_BUF_SIZE ) {
1841        printk("too big data length: skb = %08x, skb->data = %08x, skb->len = %d\n", (unsigned int)skb, (unsigned int)skb->data, skb->len);
1842        return;
1843    }
1844
1845    if ( ch >= 0 )
1846        printk("%s (port %d, ch %d)\n", title, port, ch);
1847    else
1848        printk("%s\n", title);
1849    printk(" skb->data = %08X, skb->tail = %08X, skb->len = %d\n", (unsigned int)skb->data, (unsigned int)skb->tail, (int)skb->len);
1850    for ( i = 1; i <= len; i++ ) {
1851        if ( i % 16 == 1 )
1852            printk(" %4d:", i - 1);
1853        printk(" %02X", (int)(*((char*)skb->data + i - 1) & 0xFF));
1854        if ( i % 16 == 0 )
1855            printk("\n");
1856    }
1857    if ( (i - 1) % 16 != 0 )
1858        printk("\n");
1859}
1860#endif
1861
1862#if defined(ENABLE_DBG_PROC) && ENABLE_DBG_PROC
1863static void skb_swap(struct sk_buff *skb, unsigned int byteoff)
1864{
1865    unsigned int mac_offset = ~0;
1866    unsigned int ip_offset = ~0;
1867    unsigned char tmp[8];
1868    unsigned char *p = NULL;
1869
1870    skb_pull(skb, byteoff + TX_INBAND_HEADER_LENGTH);
1871
1872    if ( skb->data[0] == 0xAA && skb->data[1] == 0xAA && skb->data[2] == 0x03 ) {
1873        // LLC
1874        if ( skb->data[3] == 0x00 && skb->data[4] == 0x80 && skb->data[5] == 0xC2 ) {
1875            // EoA
1876            if ( skb->data[22] == 0x08 && skb->data[23] == 0x00 ) {
1877                // IPv4
1878                mac_offset = 10;
1879                ip_offset = 24;
1880            }
1881            else if ( skb->data[31] == 0x21 ) {
1882                // PPPoE IPv4
1883                mac_offset = 10;
1884                ip_offset = 32;
1885            }
1886        }
1887        else {
1888            // IPoA
1889            if ( skb->data[6] == 0x08 && skb->data[7] == 0x00 ) {
1890                // IPv4
1891                ip_offset = 8;
1892            }
1893        }
1894    }
1895    else if ( skb->data[0] == 0xFE && skb->data[1] == 0xFE && skb->data[2] == 0x03 ) {
1896        // LLC PPPoA
1897        if ( skb->data[4] == 0x00 && skb->data[5] == 0x21 ) {
1898            // IPv4
1899            ip_offset = 6;
1900        }
1901    }
1902    else {
1903        // VC-mux
1904        if ( skb->data[0] == 0x00 && skb->data[1] == 0x21 ) {
1905            // PPPoA IPv4
1906            ip_offset = 2;
1907        }
1908        else if ( skb->data[0] == 0x00 && skb->data[1] == 0x00 ) {
1909            // EoA
1910            if ( skb->data[14] == 0x08 && skb->data[15] ==0x00 ) {
1911                // IPv4
1912                mac_offset = 2;
1913                ip_offset = 16;
1914            }
1915            else if ( skb->data[23] == 0x21 ) {
1916                // PPPoE IPv4
1917                mac_offset = 2;
1918                ip_offset = 26;
1919            }
1920        }
1921        else {
1922            // IPoA
1923            ip_offset = 0;
1924        }
1925    }
1926
1927    if ( mac_offset != ~0 && !(skb->data[mac_offset] & 0x01) ) {
1928        p = skb->data + mac_offset;
1929        // swap MAC
1930        memcpy(tmp, p, 6);
1931        memcpy(p, p + 6, 6);
1932        memcpy(p + 6, tmp, 6);
1933        p += 12;
1934    }
1935
1936    if ( ip_offset != ~0 ) {
1937        p = skb->data + ip_offset + 12;
1938        // swap IP
1939        memcpy(tmp, p, 4);
1940        memcpy(p, p + 4, 4);
1941        memcpy(p + 4, tmp, 4);
1942        p += 8;
1943    }
1944
1945    if ( p != NULL ) {
1946        dma_cache_wback((unsigned long)skb->data, (unsigned long)p - (unsigned long)skb->data);
1947    }
1948
1949    skb_push(skb, byteoff + TX_INBAND_HEADER_LENGTH);
1950}
1951#endif
1952
1953static INLINE void proc_file_create(void)
1954{
1955    struct proc_dir_entry *res;
1956
1957    g_atm_dir = proc_mkdir("driver/ifx_atm", NULL);
1958
1959    create_proc_read_entry("version",
1960                           0,
1961                           g_atm_dir,
1962                           proc_read_version,
1963                           NULL);
1964
1965    res = create_proc_entry("mib",
1966                            0,
1967                            g_atm_dir);
1968    if ( res != NULL ) {
1969       res->read_proc = proc_read_mib;
1970       res->write_proc = proc_write_mib;
1971    }
1972
1973#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
1974    res = create_proc_entry("retx_mib",
1975                            0,
1976                            g_atm_dir);
1977    if ( res != NULL ) {
1978       res->read_proc = proc_read_retx_mib;
1979       res->write_proc = proc_write_retx_mib;
1980    }
1981#endif
1982
1983#if defined(ENABLE_DBG_PROC) && ENABLE_DBG_PROC
1984    res = create_proc_entry("dbg",
1985                            0,
1986                            g_atm_dir);
1987    if ( res != NULL ) {
1988       res->read_proc = proc_read_dbg;
1989       res->write_proc = proc_write_dbg;
1990    }
1991
1992    res = create_proc_entry("mem",
1993                            0,
1994                            g_atm_dir);
1995    if ( res != NULL )
1996       res->write_proc = proc_write_mem;
1997
1998 #if defined(CONFIG_AR9) || defined(CONFIG_VR9) || defined(CONFIG_DANUBE) || defined(CONFIG_AMAZON_SE)
1999    res = create_proc_entry("pp32",
2000                            0,
2001                            g_atm_dir);
2002    if ( res != NULL ) {
2003       res->read_proc = proc_read_pp32;
2004       res->write_proc = proc_write_pp32;
2005    }
2006 #endif
2007#endif
2008
2009#if defined(ENABLE_FW_PROC) && ENABLE_FW_PROC
2010    create_proc_read_entry("htu",
2011                            0,
2012                            g_atm_dir,
2013                            proc_read_htu,
2014                            NULL);
2015
2016    create_proc_read_entry("txq",
2017                           0,
2018                           g_atm_dir,
2019                           proc_read_txq,
2020                           NULL);
2021
2022 #if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
2023    create_proc_read_entry("retx_fw",
2024                           0,
2025                           g_atm_dir,
2026                           proc_read_retx_fw,
2027                           NULL);
2028
2029    res = create_proc_entry("retx_stats",
2030                            0,
2031                            g_atm_dir);
2032    if ( res != NULL ) {
2033        res->read_proc = proc_read_retx_stats;
2034        res->write_proc = proc_write_retx_stats;
2035    }
2036
2037    res = create_proc_entry("retx_cfg",
2038                            0,
2039                            g_atm_dir);
2040    if ( res != NULL ) {
2041        res->read_proc = proc_read_retx_cfg;
2042        res->write_proc = proc_write_retx_cfg;
2043    }
2044
2045    create_proc_read_entry("retx_dsl_param",
2046                            0,
2047                            g_atm_dir,
2048                            proc_read_retx_dsl_param,
2049                            NULL);
2050 #endif
2051#endif
2052}
2053
2054static INLINE void proc_file_delete(void)
2055{
2056#if defined(ENABLE_FW_PROC) && ENABLE_FW_PROC
2057 #if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
2058    remove_proc_entry("retx_dsl_param", g_atm_dir);
2059
2060    remove_proc_entry("retx_cfg", g_atm_dir);
2061
2062    remove_proc_entry("retx_stats", g_atm_dir);
2063
2064    remove_proc_entry("retx_fw", g_atm_dir);
2065 #endif
2066
2067    remove_proc_entry("txq", g_atm_dir);
2068
2069    remove_proc_entry("htu", g_atm_dir);
2070#endif
2071
2072#if defined(ENABLE_DBG_PROC) && ENABLE_DBG_PROC
2073 #if defined(CONFIG_AR9) || defined(CONFIG_VR9) || defined(CONFIG_DANUBE) || defined(CONFIG_AMAZON_SE)
2074    remove_proc_entry("pp32", g_atm_dir);
2075 #endif
2076
2077    remove_proc_entry("mem", g_atm_dir);
2078
2079    remove_proc_entry("dbg", g_atm_dir);
2080#endif
2081
2082#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
2083    remove_proc_entry("retx_mib", g_atm_dir);
2084#endif
2085
2086    remove_proc_entry("mib", g_atm_dir);
2087
2088    remove_proc_entry("version", g_atm_dir);
2089
2090    remove_proc_entry("driver/ifx_atm", NULL);
2091}
2092
2093static int proc_read_version(char *buf, char **start, off_t offset, int count, int *eof, void *data)
2094{
2095    int len = 0;
2096
2097    len += ifx_atm_version(buf + len);
2098
2099    if ( offset >= len ) {
2100        *start = buf;
2101        *eof = 1;
2102        return 0;
2103    }
2104    *start = buf + offset;
2105    if ( (len -= offset) > count )
2106        return count;
2107    *eof = 1;
2108    return len;
2109}
2110
2111static int proc_read_mib(char *page, char **start, off_t off, int count, int *eof, void *data)
2112{
2113    int len = 0;
2114
2115    len += sprintf(page + off + len, "Firmware\n");
2116    len += sprintf(page + off + len, " wrx_drophtu_cell = %u\n", WAN_MIB_TABLE->wrx_drophtu_cell);
2117    len += sprintf(page + off + len, " wrx_dropdes_pdu = %u\n", WAN_MIB_TABLE->wrx_dropdes_pdu);
2118    len += sprintf(page + off + len, " wrx_correct_pdu = %u\n", WAN_MIB_TABLE->wrx_correct_pdu);
2119    len += sprintf(page + off + len, " wrx_err_pdu = %u\n", WAN_MIB_TABLE->wrx_err_pdu);
2120    len += sprintf(page + off + len, " wrx_dropdes_cell = %u\n", WAN_MIB_TABLE->wrx_dropdes_cell);
2121    len += sprintf(page + off + len, " wrx_correct_cell = %u\n", WAN_MIB_TABLE->wrx_correct_cell);
2122    len += sprintf(page + off + len, " wrx_err_cell = %u\n", WAN_MIB_TABLE->wrx_err_cell);
2123    len += sprintf(page + off + len, " wrx_total_byte = %u\n", WAN_MIB_TABLE->wrx_total_byte);
2124    len += sprintf(page + off + len, " wtx_total_pdu = %u\n", WAN_MIB_TABLE->wtx_total_pdu);
2125    len += sprintf(page + off + len, " wtx_total_cell = %u\n", WAN_MIB_TABLE->wtx_total_cell);
2126    len += sprintf(page + off + len, " wtx_total_byte = %u\n", WAN_MIB_TABLE->wtx_total_byte);
2127    len += sprintf(page + off + len, "Driver\n");
2128    len += sprintf(page + off + len, " wrx_pdu = %u\n", g_atm_priv_data.wrx_pdu);
2129    len += sprintf(page + off + len, " wrx_drop_pdu = %u\n", g_atm_priv_data.wrx_drop_pdu);
2130    len += sprintf(page + off + len, " wtx_pdu = %u\n", g_atm_priv_data.wtx_pdu);
2131    len += sprintf(page + off + len, " wtx_err_pdu = %u\n", g_atm_priv_data.wtx_err_pdu);
2132    len += sprintf(page + off + len, " wtx_drop_pdu = %u\n", g_atm_priv_data.wtx_drop_pdu);
2133
2134    *eof = 1;
2135
2136    return len;
2137}
2138
2139static int proc_write_mib(struct file *file, const char *buf, unsigned long count, void *data)
2140{
2141    char str[1024];
2142    char *p;
2143    int len, rlen;
2144
2145    len = count < sizeof(str) ? count : sizeof(str) - 1;
2146    rlen = len - copy_from_user(str, buf, len);
2147    while ( rlen && str[rlen - 1] <= ' ' )
2148        rlen--;
2149    str[rlen] = 0;
2150    for ( p = str; *p && *p <= ' '; p++, rlen-- );
2151    if ( !*p )
2152        return 0;
2153
2154    if ( stricmp(p, "clear") == 0 || stricmp(p, "clear all") == 0
2155        || stricmp(p, "clean") == 0 || stricmp(p, "clean all") == 0 ) {
2156        memset(WAN_MIB_TABLE, 0, sizeof(*WAN_MIB_TABLE));
2157        g_atm_priv_data.wrx_pdu = 0;
2158        g_atm_priv_data.wrx_drop_pdu = 0;
2159        g_atm_priv_data.wtx_pdu = 0;
2160        g_atm_priv_data.wtx_err_pdu = 0;
2161        g_atm_priv_data.wtx_drop_pdu = 0;
2162    }
2163
2164    return count;
2165}
2166
2167#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
2168
2169static int proc_read_retx_mib(char *page, char **start, off_t off, int count, int *eof, void *data)
2170{
2171    int len = 0;
2172
2173    printk("Retx FW DTU MIB :\n");
2174    printk(" rx_total_dtu = %u\n", *URETX_RX_TOTAL_DTU);
2175    printk(" rx_bad_dtu = %u\n", *URETX_RX_BAD_DTU);
2176    printk(" rx_good_dtu = %u\n", *URETX_RX_GOOD_DTU);
2177    printk(" rx_corrected_dtu = %u\n", *URETX_RX_CORRECTED_DTU);
2178    printk(" rx_outofdate_dtu = %u\n", *URETX_RX_OUTOFDATE_DTU);
2179    printk(" rx_duplicate_dtu = %u\n", *URETX_RX_DUPLICATE_DTU);
2180    printk(" rx_timeout_dtu = %u\n", *URETX_RX_TIMEOUT_DTU);
2181    printk(" RxDTURetransmittedCNT = %u\n", *RxDTURetransmittedCNT);
2182    printk("\n");
2183
2184    printk("Retx Standard DTU MIB:\n");
2185    printk(" RxLastEFB = %u\n", *RxLastEFBCNT);
2186    printk(" RxDTUCorrectedCNT = %u\n", *RxDTUCorrectedCNT);
2187    printk(" RxDTUCorruptedCNT = %u\n", *RxDTUCorruptedCNT);
2188    printk(" RxRetxDTUUncorrectedCNT = %u\n", *RxRetxDTUUncorrectedCNT);
2189    printk("\n");
2190
2191    printk("Retx FW Cell MIB :\n");
2192    printk(" bc0_total_cell = %u\n", *WRX_BC0_CELL_NUM);
2193    printk(" bc0_drop_cell = %u\n", *WRX_BC0_DROP_CELL_NUM);
2194    printk(" bc0_nonretx_cell = %u\n", *WRX_BC0_NONRETX_CELL_NUM);
2195    printk(" bc0_retx_cell = %u\n", *WRX_BC0_RETX_CELL_NUM);
2196    printk(" bc0_outofdate_cell = %u\n", *WRX_BC0_OUTOFDATE_CELL_NUM);
2197    printk(" bc0_directup_cell = %u\n", *WRX_BC0_DIRECTUP_NUM);
2198    printk(" bc0_to_pb_total_cell = %u\n", *WRX_BC0_PBW_TOTAL_NUM);
2199    printk(" bc0_to_pb_succ_cell = %u\n", *WRX_BC0_PBW_SUCC_NUM);
2200    printk(" bc0_to_pb_fail_cell = %u\n", *WRX_BC0_PBW_FAIL_NUM);
2201    printk(" bc1_total_cell = %u\n", *WRX_BC1_CELL_NUM);
2202
2203    printk("\n");
2204
2205    printk("ATM Rx AAL5/OAM MIB:\n");
2206    printk(" wrx_drophtu_cell = %u\n", WAN_MIB_TABLE->wrx_drophtu_cell);
2207    printk(" wrx_dropdes_pdu = %u\n", WAN_MIB_TABLE->wrx_dropdes_pdu);
2208
2209    printk(" wrx_correct_pdu = %-10u ", WAN_MIB_TABLE->wrx_correct_pdu);
2210    if ( WAN_MIB_TABLE->wrx_correct_pdu == 0 )
2211        printk("\n");
2212    else {
2213        int i = 0;
2214
2215        printk("[ ");
2216        for ( i = 0; i < 16; ++i ) {
2217            if ( WRX_PER_PVC_CORRECT_PDU_BASE[i] )
2218                printk("q%-2d = %-10u , ", i, WRX_PER_PVC_CORRECT_PDU_BASE[i]);
2219        }
2220        printk("]\n");
2221    }
2222
2223    printk(" wrx_err_pdu = %-10u ", WAN_MIB_TABLE->wrx_err_pdu);
2224    if ( WAN_MIB_TABLE->wrx_err_pdu == 0 )
2225        printk("\n");
2226    else {
2227        int i = 0;
2228
2229        printk("[ ");
2230        for ( i = 0; i < 16; ++i ) {
2231            if ( WRX_PER_PVC_ERROR_PDU_BASE[i] )
2232                printk("q%-2d = %-10u , ", i, WRX_PER_PVC_ERROR_PDU_BASE[i] );
2233        }
2234        printk("]\n");
2235    }
2236
2237    printk(" wrx_dropdes_cell = %u\n", WAN_MIB_TABLE->wrx_dropdes_cell);
2238    printk(" wrx_correct_cell = %u\n", WAN_MIB_TABLE->wrx_correct_cell);
2239    printk(" wrx_err_cell = %u\n", WAN_MIB_TABLE->wrx_err_cell);
2240    printk(" wrx_total_byte = %u\n", WAN_MIB_TABLE->wrx_total_byte);
2241    printk("\n");
2242
2243    printk("ATM Tx MIB:\n");
2244    printk(" wtx_total_pdu = %u\n", WAN_MIB_TABLE->wtx_total_pdu);
2245    printk(" wtx_total_cell = %u\n", WAN_MIB_TABLE->wtx_total_cell);
2246    printk(" wtx_total_byte = %u\n", WAN_MIB_TABLE->wtx_total_byte);
2247    printk("\n");
2248
2249    printk("Debugging Info:\n");
2250    printk(" Firmware version = %d.%d.%d.%d.%d.%d\n",
2251            (int)FW_VER_ID->family, (int)FW_VER_ID->fwtype, (int)FW_VER_ID->interface,
2252            (int)FW_VER_ID->fwmode, (int)FW_VER_ID->major, (int)FW_VER_ID->minor);
2253
2254    printk(" retx_alpha_switch_to_hunt_times = %u\n", *URETX_ALPHA_SWITCH_TO_HUNT_TIMES);
2255
2256    printk("\n");
2257
2258    *eof = 1;
2259
2260    return len;
2261}
2262
2263static int proc_write_retx_mib(struct file *file, const char *buf, unsigned long count, void *data)
2264{
2265    char str[2048];
2266    char *p;
2267    int len, rlen;
2268    int i;
2269
2270    len = count < sizeof(str) ? count : sizeof(str) - 1;
2271    rlen = len - copy_from_user(str, buf, len);
2272    while ( rlen && str[rlen - 1] <= ' ' )
2273        rlen--;
2274    str[rlen] = 0;
2275    for ( p = str; *p && *p <= ' '; p++, rlen-- );
2276    if ( !*p )
2277        return 0;
2278
2279    if ( stricmp(p, "clean") == 0 || stricmp(p, "clear") == 0 || stricmp(p, "clear_all") == 0) {
2280        *URETX_RX_TOTAL_DTU = 0;
2281        *URETX_RX_BAD_DTU = 0;
2282        *URETX_RX_GOOD_DTU = 0;
2283        *URETX_RX_CORRECTED_DTU = 0;
2284        *URETX_RX_OUTOFDATE_DTU = 0;
2285        *URETX_RX_DUPLICATE_DTU = 0;
2286        *URETX_RX_TIMEOUT_DTU = 0;
2287        *RxDTURetransmittedCNT = 0;
2288
2289        *WRX_BC0_CELL_NUM = 0;
2290        *WRX_BC0_DROP_CELL_NUM = 0;
2291        *WRX_BC0_NONRETX_CELL_NUM = 0;
2292        *WRX_BC0_RETX_CELL_NUM = 0;
2293        *WRX_BC0_OUTOFDATE_CELL_NUM = 0;
2294        *WRX_BC0_DIRECTUP_NUM = 0;
2295        *WRX_BC0_PBW_TOTAL_NUM = 0;
2296        *WRX_BC0_PBW_SUCC_NUM = 0;
2297        *WRX_BC0_PBW_FAIL_NUM = 0;
2298        *WRX_BC1_CELL_NUM = 0;
2299
2300        for ( i = 0; i < 16; ++i ) {
2301            WRX_PER_PVC_CORRECT_PDU_BASE[i] = 0;
2302            WRX_PER_PVC_ERROR_PDU_BASE[i] = 0;
2303        }
2304
2305        WAN_MIB_TABLE->wrx_drophtu_cell = 0;
2306        WAN_MIB_TABLE->wrx_dropdes_pdu = 0;
2307        WAN_MIB_TABLE->wrx_correct_pdu = 0;
2308        WAN_MIB_TABLE->wrx_err_pdu = 0;
2309        WAN_MIB_TABLE->wrx_dropdes_cell = 0;
2310        WAN_MIB_TABLE->wrx_correct_cell = 0;
2311        WAN_MIB_TABLE->wrx_err_cell = 0;
2312        WAN_MIB_TABLE->wrx_total_byte = 0;
2313
2314        WAN_MIB_TABLE->wtx_total_pdu = 0;
2315        WAN_MIB_TABLE->wtx_total_cell = 0;
2316        WAN_MIB_TABLE->wtx_total_byte = 0;
2317
2318        *URETX_ALPHA_SWITCH_TO_HUNT_TIMES = 0;
2319
2320        if (stricmp(p, "clear_all") == 0) {
2321            *RxLastEFBCNT = 0;
2322            *RxDTUCorrectedCNT = 0;
2323            *RxDTUCorruptedCNT = 0;
2324            *RxRetxDTUUncorrectedCNT = 0;
2325        }
2326    }
2327
2328    return count;
2329}
2330
2331#endif
2332
2333#if defined(ENABLE_DBG_PROC) && ENABLE_DBG_PROC
2334
2335static int proc_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data)
2336{
2337    int len = 0;
2338
2339    len += sprintf(page + off + len, "error print - %s\n", (ifx_atm_dbg_enable & DBG_ENABLE_MASK_ERR) ? "enabled" : "disabled");
2340    len += sprintf(page + off + len, "debug print - %s\n", (ifx_atm_dbg_enable & DBG_ENABLE_MASK_DEBUG_PRINT) ? "enabled" : "disabled");
2341    len += sprintf(page + off + len, "assert - %s\n", (ifx_atm_dbg_enable & DBG_ENABLE_MASK_ASSERT) ? "enabled" : "disabled");
2342    len += sprintf(page + off + len, "dump rx skb - %s\n", (ifx_atm_dbg_enable & DBG_ENABLE_MASK_DUMP_SKB_RX) ? "enabled" : "disabled");
2343    len += sprintf(page + off + len, "dump tx skb - %s\n", (ifx_atm_dbg_enable & DBG_ENABLE_MASK_DUMP_SKB_TX) ? "enabled" : "disabled");
2344    len += sprintf(page + off + len, "qos - %s\n", (ifx_atm_dbg_enable & DBG_ENABLE_MASK_DUMP_QOS) ? "enabled" : "disabled");
2345    len += sprintf(page + off + len, "dump init - %s\n", (ifx_atm_dbg_enable & DBG_ENABLE_MASK_DUMP_INIT) ? "enabled" : "disabled");
2346    len += sprintf(page + off + len, "mac swap - %s\n", (ifx_atm_dbg_enable & DBG_ENABLE_MASK_MAC_SWAP) ? "enabled" : "disabled");
2347
2348    *eof = 1;
2349
2350    return len;
2351}
2352
2353static int proc_write_dbg(struct file *file, const char *buf, unsigned long count, void *data)
2354{
2355    static const char *dbg_enable_mask_str[] = {
2356        " error print",
2357        " err",
2358        " debug print",
2359        " dbg",
2360        " assert",
2361        " assert",
2362        " dump rx skb",
2363        " rx",
2364        " dump tx skb",
2365        " tx",
2366        " dump qos",
2367        " qos",
2368        " dump init",
2369        " init",
2370        " mac swap",
2371        " swap",
2372        " all"
2373    };
2374    static const int dbg_enable_mask_str_len[] = {
2375        12, 4,
2376        12, 4,
2377        7, 7,
2378        12, 3,
2379        12, 3,
2380        9, 4,
2381        10, 5,
2382        9, 5,
2383        4
2384    };
2385    unsigned int dbg_enable_mask[] = {
2386        DBG_ENABLE_MASK_ERR,
2387        DBG_ENABLE_MASK_DEBUG_PRINT,
2388        DBG_ENABLE_MASK_ASSERT,
2389        DBG_ENABLE_MASK_DUMP_SKB_RX,
2390        DBG_ENABLE_MASK_DUMP_SKB_TX,
2391        DBG_ENABLE_MASK_DUMP_QOS,
2392        DBG_ENABLE_MASK_DUMP_INIT,
2393        DBG_ENABLE_MASK_MAC_SWAP,
2394        DBG_ENABLE_MASK_ALL
2395    };
2396
2397    char *str;
2398    int str_buff_len = 1024;
2399    char *p;
2400
2401    int len, rlen;
2402
2403    int f_enable = 0;
2404    int i;
2405    
2406    str = vmalloc(str_buff_len);
2407    if(!str){
2408        return 0;
2409    }
2410
2411    len = count < str_buff_len ? count : str_buff_len - 1;
2412    rlen = len - copy_from_user(str, buf, len);
2413    while ( rlen && str[rlen - 1] <= ' ' )
2414        rlen--;
2415    str[rlen] = 0;
2416    for ( p = str; *p && *p <= ' '; p++, rlen-- );
2417    if ( !*p ){
2418        vfree(str);
2419        return 0;
2420    }
2421
2422    if ( strincmp(p, "enable", 6) == 0 ) {
2423        p += 6;
2424        f_enable = 1;
2425    }
2426    else if ( strincmp(p, "disable", 7) == 0 ) {
2427        p += 7;
2428        f_enable = -1;
2429    }
2430    else if ( strincmp(p, "help", 4) == 0 || *p == '?' ) {
2431        printk("echo <enable/disable> [err/dbg/assert/rx/tx/init/all] > /proc/eth/dbg\n");
2432    }
2433
2434    if ( f_enable ) {
2435        if ( *p == 0 ) {
2436            if ( f_enable > 0 )
2437                ifx_atm_dbg_enable |= DBG_ENABLE_MASK_ALL & ~DBG_ENABLE_MASK_MAC_SWAP;
2438            else
2439                ifx_atm_dbg_enable &= ~DBG_ENABLE_MASK_ALL | DBG_ENABLE_MASK_MAC_SWAP;
2440        }
2441        else {
2442            do {
2443                for ( i = 0; i < NUM_ENTITY(dbg_enable_mask_str); i++ )
2444                    if ( strincmp(p, dbg_enable_mask_str[i], dbg_enable_mask_str_len[i]) == 0 ) {
2445                        if ( f_enable > 0 )
2446                            ifx_atm_dbg_enable |= dbg_enable_mask[i >> 1];
2447                        else
2448                            ifx_atm_dbg_enable &= ~dbg_enable_mask[i >> 1];
2449                        p += dbg_enable_mask_str_len[i];
2450                        break;
2451                    }
2452            } while ( i < NUM_ENTITY(dbg_enable_mask_str) );
2453        }
2454    }
2455
2456    vfree(str);
2457    return count;
2458}
2459
2460static inline unsigned long sb_addr_to_fpi_addr_convert(unsigned long sb_addr)
2461{
2462 #define PP32_SB_ADDR_END 0xFFFF
2463
2464    if ( sb_addr < PP32_SB_ADDR_END )
2465        return (unsigned long)SB_BUFFER(sb_addr);
2466    else
2467        return sb_addr;
2468}
2469
2470static int proc_write_mem(struct file *file, const char *buf, unsigned long count, void *data)
2471{
2472    char *p1, *p2;
2473    int len;
2474    int colon;
2475    unsigned long *p;
2476    int i, n, l;
2477    int local_buf_size = 1024;
2478    char *local_buf = NULL;
2479
2480    local_buf = vmalloc(local_buf_size);
2481    if ( !local_buf ){
2482        return 0;
2483    }
2484
2485    len = local_buf_size < count ? local_buf_size - 1 : count;
2486    len = len - copy_from_user(local_buf, buf, len);
2487    local_buf[len] = 0;
2488
2489    p1 = local_buf;
2490    colon = 1;
2491    while ( get_token(&p1, &p2, &len, &colon) ) {
2492        if ( stricmp(p1, "w") == 0 || stricmp(p1, "write") == 0 || stricmp(p1, "r") == 0 || stricmp(p1, "read") == 0 )
2493            break;
2494
2495        p1 = p2;
2496        colon = 1;
2497    }
2498
2499    if ( *p1 == 'w' ) {
2500        ignore_space(&p2, &len);
2501        p = (unsigned long *)get_number(&p2, &len, 1);
2502        p = (unsigned long *)sb_addr_to_fpi_addr_convert((unsigned long)p);
2503
2504        if ( (unsigned int)p >= KSEG0 )
2505            while ( 1 ) {
2506                ignore_space(&p2, &len);
2507                if ( !len || !((*p2 >= '0' && *p2 <= '9') || (*p2 >= 'a' && *p2 <= 'f') || (*p2 >= 'A' && *p2 <= 'F')) )
2508                    break;
2509
2510                *p++ = (unsigned int)get_number(&p2, &len, 1);
2511            }
2512    }
2513    else if ( *p1 == 'r' ) {
2514        ignore_space(&p2, &len);
2515        p = (unsigned long *)get_number(&p2, &len, 1);
2516        p = (unsigned long *)sb_addr_to_fpi_addr_convert((unsigned long)p);
2517
2518        if ( (unsigned int)p >= KSEG0 ) {
2519            ignore_space(&p2, &len);
2520            n = (int)get_number(&p2, &len, 0);
2521            if ( n ) {
2522                char str[32] = {0};
2523                char *pch = str;
2524                int k;
2525                unsigned int data;
2526                char c;
2527
2528                n += (l = ((int)p >> 2) & 0x03);
2529                p = (unsigned long *)((unsigned int)p & ~0x0F);
2530                for ( i = 0; i < n; i++ ) {
2531                    if ( (i & 0x03) == 0 ) {
2532                        printk("%08X:", (unsigned int)p);
2533                        pch = str;
2534                    }
2535                    if ( i < l ) {
2536                        printk(" ");
2537                        sprintf(pch, " ");
2538                    }
2539                    else {
2540                        data = (unsigned int)*p;
2541                        printk(" %08X", data);
2542                        for ( k = 0; k < 4; k++ ) {
2543                            c = ((char*)&data)[k];
2544                            pch[k] = c < ' ' ? '.' : c;
2545                        }
2546                    }
2547                    p++;
2548                    pch += 4;
2549                    if ( (i & 0x03) == 0x03 ) {
2550                        pch[0] = 0;
2551                        printk(" ; %s\n", str);
2552                    }
2553                }
2554                if ( (n & 0x03) != 0x00 ) {
2555                    for ( k = 4 - (n & 0x03); k > 0; k-- )
2556                        printk(" ");
2557                    pch[0] = 0;
2558                    printk(" ; %s\n", str);
2559                }
2560            }
2561        }
2562    }
2563
2564    vfree(local_buf);
2565    return count;
2566}
2567
2568 #if defined(CONFIG_AR9) || defined(CONFIG_VR9)
2569
2570static int proc_read_pp32(char *page, char **start, off_t off, int count, int *eof, void *data)
2571{
2572    static const char *stron = " on";
2573    static const char *stroff = "off";
2574
2575    int len = 0;
2576    int cur_context;
2577    int f_stopped;
2578    char str[256];
2579    char strlength;
2580    int i, j;
2581
2582    int pp32;
2583
2584    for ( pp32 = 0; pp32 < NUM_OF_PP32; pp32++ ) {
2585        f_stopped = 0;
2586
2587        len += sprintf(page + off + len, "===== pp32 core %d =====\n", pp32);
2588
2589  #ifdef CONFIG_VR9
2590        if ( (*PP32_FREEZE & (1 << (pp32 << 4))) != 0 ) {
2591            sprintf(str, "freezed");
2592            f_stopped = 1;
2593        }
2594  #else
2595        if ( 0 ) {
2596        }
2597  #endif
2598        else if ( PP32_CPU_USER_STOPPED(pp32) || PP32_CPU_USER_BREAKIN_RCV(pp32) || PP32_CPU_USER_BREAKPOINT_MET(pp32) ) {
2599            strlength = 0;
2600            if ( PP32_CPU_USER_STOPPED(pp32) )
2601                strlength += sprintf(str + strlength, "stopped");
2602            if ( PP32_CPU_USER_BREAKPOINT_MET(pp32) )
2603                strlength += sprintf(str + strlength, strlength ? " | breakpoint" : "breakpoint");
2604            if ( PP32_CPU_USER_BREAKIN_RCV(pp32) )
2605                strlength += sprintf(str + strlength, strlength ? " | breakin" : "breakin");
2606            f_stopped = 1;
2607        }
2608  #if 0
2609        else if ( PP32_CPU_CUR_PC(pp32) == PP32_CPU_CUR_PC(pp32) ) {
2610            sprintf(str, "hang");
2611            f_stopped = 1;
2612        }
2613  #endif
2614        else
2615            sprintf(str, "running");
2616        cur_context = PP32_BRK_CUR_CONTEXT(pp32);
2617        len += sprintf(page + off + len, "Context: %d, PC: 0x%04x, %s\n", cur_context, PP32_CPU_CUR_PC(pp32), str);
2618
2619        if ( PP32_CPU_USER_BREAKPOINT_MET(pp32) ) {
2620            strlength = 0;
2621            if ( PP32_BRK_PC_MET(pp32, 0) )
2622                strlength += sprintf(str + strlength, "pc0");
2623            if ( PP32_BRK_PC_MET(pp32, 1) )
2624                strlength += sprintf(str + strlength, strlength ? " | pc1" : "pc1");
2625            if ( PP32_BRK_DATA_ADDR_MET(pp32, 0) )
2626                strlength += sprintf(str + strlength, strlength ? " | daddr0" : "daddr0");
2627            if ( PP32_BRK_DATA_ADDR_MET(pp32, 1) )
2628                strlength += sprintf(str + strlength, strlength ? " | daddr1" : "daddr1");
2629            if ( PP32_BRK_DATA_VALUE_RD_MET(pp32, 0) ) {
2630                strlength += sprintf(str + strlength, strlength ? " | rdval0" : "rdval0");
2631                if ( PP32_BRK_DATA_VALUE_RD_LO_EQ(pp32, 0) ) {
2632                    if ( PP32_BRK_DATA_VALUE_RD_GT_EQ(pp32, 0) )
2633                        strlength += sprintf(str + strlength, " ==");
2634                    else
2635                        strlength += sprintf(str + strlength, " <=");
2636                }
2637                else if ( PP32_BRK_DATA_VALUE_RD_GT_EQ(pp32, 0) )
2638                    strlength += sprintf(str + strlength, " >=");
2639            }
2640            if ( PP32_BRK_DATA_VALUE_RD_MET(pp32, 1) ) {
2641                strlength += sprintf(str + strlength, strlength ? " | rdval1" : "rdval1");
2642                if ( PP32_BRK_DATA_VALUE_RD_LO_EQ(pp32, 1) ) {
2643                    if ( PP32_BRK_DATA_VALUE_RD_GT_EQ(pp32, 1) )
2644                        strlength += sprintf(str + strlength, " ==");
2645                    else
2646                        strlength += sprintf(str + strlength, " <=");
2647                }
2648                else if ( PP32_BRK_DATA_VALUE_RD_GT_EQ(pp32, 1) )
2649                    strlength += sprintf(str + strlength, " >=");
2650            }
2651            if ( PP32_BRK_DATA_VALUE_WR_MET(pp32, 0) ) {
2652                strlength += sprintf(str + strlength, strlength ? " | wtval0" : "wtval0");
2653                if ( PP32_BRK_DATA_VALUE_WR_LO_EQ(pp32, 0) ) {
2654                    if ( PP32_BRK_DATA_VALUE_WR_GT_EQ(pp32, 0) )
2655                        strlength += sprintf(str + strlength, " ==");
2656                    else
2657                        strlength += sprintf(str + strlength, " <=");
2658                }
2659                else if ( PP32_BRK_DATA_VALUE_WR_GT_EQ(pp32, 0) )
2660                    strlength += sprintf(str + strlength, " >=");
2661            }
2662            if ( PP32_BRK_DATA_VALUE_WR_MET(pp32, 1) ) {
2663                strlength += sprintf(str + strlength, strlength ? " | wtval1" : "wtval1");
2664                if ( PP32_BRK_DATA_VALUE_WR_LO_EQ(pp32, 1) ) {
2665                    if ( PP32_BRK_DATA_VALUE_WR_GT_EQ(pp32, 1) )
2666                        strlength += sprintf(str + strlength, " ==");
2667                    else
2668                        strlength += sprintf(str + strlength, " <=");
2669                }
2670                else if ( PP32_BRK_DATA_VALUE_WR_GT_EQ(pp32, 1) )
2671                    strlength += sprintf(str + strlength, " >=");
2672            }
2673            len += sprintf(page + off + len, "break reason: %s\n", str);
2674        }
2675
2676        if ( f_stopped )
2677        {
2678            len += sprintf(page + off + len, "General Purpose Register (Context %d):\n", cur_context);
2679            for ( i = 0; i < 4; i++ ) {
2680                for ( j = 0; j < 4; j++ )
2681                    len += sprintf(page + off + len, " %2d: %08x", i + j * 4, *PP32_GP_CONTEXTi_REGn(pp32, cur_context, i + j * 4));
2682                len += sprintf(page + off + len, "\n");
2683            }
2684        }
2685
2686        len += sprintf(page + off + len, "break out on: break in - %s, stop - %s\n",
2687                                            PP32_CTRL_OPT_BREAKOUT_ON_BREAKIN(pp32) ? stron : stroff,
2688                                            PP32_CTRL_OPT_BREAKOUT_ON_STOP(pp32) ? stron : stroff);
2689        len += sprintf(page + off + len, " stop on: break in - %s, break point - %s\n",
2690                                            PP32_CTRL_OPT_STOP_ON_BREAKIN(pp32) ? stron : stroff,
2691                                            PP32_CTRL_OPT_STOP_ON_BREAKPOINT(pp32) ? stron : stroff);
2692        len += sprintf(page + off + len, "breakpoint:\n");
2693        len += sprintf(page + off + len, " pc0: 0x%08x, %s\n", *PP32_BRK_PC(pp32, 0), PP32_BRK_GRPi_PCn(pp32, 0, 0) ? "group 0" : "off");
2694        len += sprintf(page + off + len, " pc1: 0x%08x, %s\n", *PP32_BRK_PC(pp32, 1), PP32_BRK_GRPi_PCn(pp32, 1, 1) ? "group 1" : "off");
2695        len += sprintf(page + off + len, " daddr0: 0x%08x, %s\n", *PP32_BRK_DATA_ADDR(pp32, 0), PP32_BRK_GRPi_DATA_ADDRn(pp32, 0, 0) ? "group 0" : "off");
2696        len += sprintf(page + off + len, " daddr1: 0x%08x, %s\n", *PP32_BRK_DATA_ADDR(pp32, 1), PP32_BRK_GRPi_DATA_ADDRn(pp32, 1, 1) ? "group 1" : "off");
2697        len += sprintf(page + off + len, " rdval0: 0x%08x\n", *PP32_BRK_DATA_VALUE_RD(pp32, 0));
2698        len += sprintf(page + off + len, " rdval1: 0x%08x\n", *PP32_BRK_DATA_VALUE_RD(pp32, 1));
2699        len += sprintf(page + off + len, " wrval0: 0x%08x\n", *PP32_BRK_DATA_VALUE_WR(pp32, 0));
2700        len += sprintf(page + off + len, " wrval1: 0x%08x\n", *PP32_BRK_DATA_VALUE_WR(pp32, 1));
2701    }
2702
2703    *eof = 1;
2704
2705    return len;
2706}
2707
2708static int proc_write_pp32(struct file *file, const char *buf, unsigned long count, void *data)
2709{
2710    char *str = NULL;
2711    char *p;
2712    unsigned int addr;
2713    int str_buff_len = 1024;
2714
2715    int len, rlen;
2716
2717    int pp32 = 0;
2718
2719    str = vmalloc(str_buff_len);
2720    if (!str) {
2721        return 0;
2722    }
2723
2724    len = count < str_buff_len ? count : str_buff_len - 1;
2725    rlen = len - copy_from_user(str, buf, len);
2726    while ( rlen && str[rlen - 1] <= ' ' )
2727        rlen--;
2728    str[rlen] = 0;
2729    for ( p = str; *p && *p <= ' '; p++, rlen-- );
2730    if ( !*p ){
2731        vfree(str);
2732        return 0;
2733    }
2734
2735    if ( strincmp(p, "pp32 ", 5) == 0 ) {
2736        p += 5;
2737        rlen -= 5;
2738
2739        while ( rlen > 0 && *p >= '0' && *p <= '9' ) {
2740            pp32 += *p - '0';
2741            p++;
2742            rlen--;
2743        }
2744        while ( rlen > 0 && *p && *p <= ' ' ) {
2745            p++;
2746            rlen--;
2747        }
2748
2749        if ( pp32 >= NUM_OF_PP32 ) {
2750            err("incorrect pp32 index - %d", pp32);
2751            vfree(str);
2752            return count;
2753        }
2754    }
2755
2756    if ( stricmp(p, "start") == 0 )
2757        *PP32_CTRL_CMD(pp32) = PP32_CTRL_CMD_RESTART;
2758    else if ( stricmp(p, "stop") == 0 )
2759        *PP32_CTRL_CMD(pp32) = PP32_CTRL_CMD_STOP;
2760    else if ( stricmp(p, "step") == 0 )
2761        *PP32_CTRL_CMD(pp32) = PP32_CTRL_CMD_STEP;
2762  #ifdef CONFIG_VR9
2763    else if ( stricmp(p, "restart") == 0 )
2764        *PP32_FREEZE &= ~(1 << (pp32 << 4));
2765    else if ( stricmp(p, "freeze") == 0 )
2766        *PP32_FREEZE |= 1 << (pp32 << 4);
2767  #endif
2768    else if ( strincmp(p, "pc0 ", 4) == 0 ) {
2769        p += 4;
2770        rlen -= 4;
2771        if ( stricmp(p, "off") == 0 ) {
2772            *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_PCn_OFF(0, 0);
2773            *PP32_BRK_PC_MASK(pp32, 0) = PP32_BRK_CONTEXT_MASK_EN;
2774            *PP32_BRK_PC(pp32, 0) = 0;
2775        }
2776        else {
2777            addr = get_number(&p, &rlen, 1);
2778            *PP32_BRK_PC(pp32, 0) = addr;
2779            *PP32_BRK_PC_MASK(pp32, 0) = PP32_BRK_CONTEXT_MASK_EN | PP32_BRK_CONTEXT_MASK(0) | PP32_BRK_CONTEXT_MASK(1) | PP32_BRK_CONTEXT_MASK(2) | PP32_BRK_CONTEXT_MASK(3);
2780            *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_PCn_ON(0, 0);
2781        }
2782    }
2783    else if ( strincmp(p, "pc1 ", 4) == 0 ) {
2784        p += 4;
2785        rlen -= 4;
2786        if ( stricmp(p, "off") == 0 ) {
2787            *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_PCn_OFF(1, 1);
2788            *PP32_BRK_PC_MASK(pp32, 1) = PP32_BRK_CONTEXT_MASK_EN;
2789            *PP32_BRK_PC(pp32, 1) = 0;
2790        }
2791        else {
2792            addr = get_number(&p, &rlen, 1);
2793            *PP32_BRK_PC(pp32, 1) = addr;
2794            *PP32_BRK_PC_MASK(pp32, 1) = PP32_BRK_CONTEXT_MASK_EN | PP32_BRK_CONTEXT_MASK(0) | PP32_BRK_CONTEXT_MASK(1) | PP32_BRK_CONTEXT_MASK(2) | PP32_BRK_CONTEXT_MASK(3);
2795            *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_PCn_ON(1, 1);
2796        }
2797    }
2798    else if ( strincmp(p, "daddr0 ", 7) == 0 ) {
2799        p += 7;
2800        rlen -= 7;
2801        if ( stricmp(p, "off") == 0 ) {
2802            *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_DATA_ADDRn_OFF(0, 0);
2803            *PP32_BRK_DATA_ADDR_MASK(pp32, 0) = PP32_BRK_CONTEXT_MASK_EN;
2804            *PP32_BRK_DATA_ADDR(pp32, 0) = 0;
2805        }
2806        else {
2807            addr = get_number(&p, &rlen, 1);
2808            *PP32_BRK_DATA_ADDR(pp32, 0) = addr;
2809            *PP32_BRK_DATA_ADDR_MASK(pp32, 0) = PP32_BRK_CONTEXT_MASK_EN | PP32_BRK_CONTEXT_MASK(0) | PP32_BRK_CONTEXT_MASK(1) | PP32_BRK_CONTEXT_MASK(2) | PP32_BRK_CONTEXT_MASK(3);
2810            *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_DATA_ADDRn_ON(0, 0);
2811        }
2812    }
2813    else if ( strincmp(p, "daddr1 ", 7) == 0 ) {
2814        p += 7;
2815        rlen -= 7;
2816        if ( stricmp(p, "off") == 0 ) {
2817            *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_DATA_ADDRn_OFF(1, 1);
2818            *PP32_BRK_DATA_ADDR_MASK(pp32, 1) = PP32_BRK_CONTEXT_MASK_EN;
2819            *PP32_BRK_DATA_ADDR(pp32, 1) = 0;
2820        }
2821        else {
2822            addr = get_number(&p, &rlen, 1);
2823            *PP32_BRK_DATA_ADDR(pp32, 1) = addr;
2824            *PP32_BRK_DATA_ADDR_MASK(pp32, 1) = PP32_BRK_CONTEXT_MASK_EN | PP32_BRK_CONTEXT_MASK(0) | PP32_BRK_CONTEXT_MASK(1) | PP32_BRK_CONTEXT_MASK(2) | PP32_BRK_CONTEXT_MASK(3);
2825            *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_DATA_ADDRn_ON(1, 1);
2826        }
2827    }
2828    else {
2829
2830        printk("echo \"<command>\" > /proc/driver/ifx_ptm/pp32\n");
2831        printk(" command:\n");
2832        printk(" start - run pp32\n");
2833        printk(" stop - stop pp32\n");
2834        printk(" step - run pp32 with one step only\n");
2835        printk(" pc0 - pc0 <addr>/off, set break point PC0\n");
2836        printk(" pc1 - pc1 <addr>/off, set break point PC1\n");
2837        printk(" daddr0 - daddr0 <addr>/off, set break point data address 0\n");
2838        printk(" daddr0 - daddr1 <addr>/off, set break point data address 1\n");
2839        printk(" help - print this screen\n");
2840    }
2841
2842    if ( *PP32_BRK_TRIG(pp32) )
2843        *PP32_CTRL_OPT(pp32) = PP32_CTRL_OPT_STOP_ON_BREAKPOINT_ON;
2844    else
2845        *PP32_CTRL_OPT(pp32) = PP32_CTRL_OPT_STOP_ON_BREAKPOINT_OFF;
2846    vfree(str);
2847    return count;
2848}
2849
2850#elif defined(CONFIG_DANUBE)
2851
2852static int proc_read_pp32(char *page, char **start, off_t off, int count, int *eof, void *data)
2853{
2854    static const char *halt_stat[] = {
2855        "reset",
2856        "break in line",
2857        "stop",
2858        "step",
2859        "code",
2860        "data0",
2861        "data1"
2862    };
2863    static const char *brk_src_data[] = {
2864        "off",
2865        "read",
2866        "write",
2867        "read/write",
2868        "write_equal",
2869        "N/A",
2870        "N/A",
2871        "N/A"
2872    };
2873    static const char *brk_src_code[] = {
2874        "off",
2875        "on"
2876    };
2877
2878    int len = 0;
2879    int i;
2880    int k;
2881    unsigned long bit;
2882    int tsk;
2883
2884    tsk = *PP32_DBG_TASK_NO & 0x03;
2885    len += sprintf(page + off + len, "Task No %d, PC %04x\n", tsk, *PP32_DBG_CUR_PC & 0xFFFF);
2886
2887    if ( !(*PP32_HALT_STAT & 0x01) )
2888        len += sprintf(page + off + len, " Halt State: Running\n");
2889    else {
2890        len += sprintf(page + off + len, " Halt State: Stopped");
2891        k = 0;
2892        for ( bit = 2, i = 0; bit <= (1 << 7); bit <<= 1, i++ )
2893            if ( (*PP32_HALT_STAT & bit) ) {
2894                if ( !k ) {
2895                    len += sprintf(page + off + len, ", ");
2896                    k++;
2897                }
2898                else
2899                    len += sprintf(page + off + len, " | ");
2900                len += sprintf(page + off + len, halt_stat[i]);
2901            }
2902
2903        len += sprintf(page + off + len, "\n");
2904
2905        len += sprintf(page + off + len, " Regs (Task %d):\n", tsk);
2906        for ( i = 0; i < 8; i++ )
2907            len += sprintf(page + off + len, " %2d. %08x %2d. %08x\n", i, *PP32_DBG_REG_BASE(tsk, i), i + 8, *PP32_DBG_REG_BASE(tsk, i + 8));
2908    }
2909
2910    len += sprintf(page + off + len, " Break Src: data1 - %s, data0 - %s, pc3 - %s, pc2 - %s, pc1 - %s, pc0 - %s\n",
2911                            brk_src_data[(*PP32_BRK_SRC >> 11) & 0x07],
2912                            brk_src_data[(*PP32_BRK_SRC >> 8) & 0x07],
2913                            brk_src_code[(*PP32_BRK_SRC >> 3) & 0x01],
2914                            brk_src_code[(*PP32_BRK_SRC >> 2) & 0x01],
2915                            brk_src_code[(*PP32_BRK_SRC >> 1) & 0x01],
2916                            brk_src_code[*PP32_BRK_SRC & 0x01]);
2917
2918    for ( i = 0; i < 4; i++ )
2919        len += sprintf(page + off + len, " pc%d: %04x - %04x\n", i, *PP32_DBG_PC_MIN(i), *PP32_DBG_PC_MAX(i));
2920
2921    for ( i = 0; i < 2; i++ )
2922        len += sprintf(page + off + len, " data%d: %04x - %04x (%08x)\n", i, *PP32_DBG_DATA_MIN(i), *PP32_DBG_DATA_MAX(i), *PP32_DBG_DATA_VAL(i));
2923
2924    *eof = 1;
2925
2926    return len;
2927}
2928
2929static int proc_write_pp32(struct file *file, const char *buf, unsigned long count, void *data)
2930{
2931    char *str;
2932    char *p;
2933
2934    int len, rlen;
2935    int str_buff_len = 2048;
2936    str = vmalloc(str_buff_len);
2937    if (!str){
2938        return 0;
2939    }
2940    len = count < str_buff_len ? count : str_buff_len - 1;
2941    rlen = len - copy_from_user(str, buf, len);
2942    while ( rlen && str[rlen - 1] <= ' ' )
2943        rlen--;
2944    str[rlen] = 0;
2945    for ( p = str; *p && *p <= ' '; p++, rlen-- );
2946    if ( !*p )
2947        vfree(str);
2948        return 0;
2949
2950    if ( stricmp(p, "start") == 0 )
2951        *PP32_DBG_CTRL = DBG_CTRL_START_SET(1);
2952    else if ( stricmp(p, "stop") == 0 )
2953        *PP32_DBG_CTRL = DBG_CTRL_STOP_SET(1);
2954    else if ( stricmp(p, "step") == 0 )
2955        *PP32_DBG_CTRL = DBG_CTRL_STEP_SET(1);
2956    else if ( strincmp(p, "pc", 2) == 0 && p[2] >= '0' && p[2] <= '3' && p[3] <= ' ' ) {
2957        int n = p[2] - '0';
2958        int on_off_flag = -1;
2959        int addr_min, addr_max;
2960
2961        p += 4;
2962        rlen -= 4;
2963        ignore_space(&p, &rlen);
2964
2965        if ( strincmp(p, "off", 3) == 0 && p[3] <= ' ' ) {
2966            p += 3;
2967            rlen -= 3;
2968            on_off_flag = 0;
2969        }
2970        else if ( strincmp(p, "on", 2) == 0 && p[2] <= ' ' ) {
2971            p += 2;
2972            rlen -= 2;
2973            on_off_flag = 1;
2974        }
2975        ignore_space(&p, &rlen);
2976
2977        if ( rlen ) {
2978            addr_min = get_number(&p, &rlen, 1);
2979            ignore_space(&p, &rlen);
2980            if ( rlen )
2981                addr_max = get_number(&p, &rlen, 1);
2982            else
2983                addr_max = addr_min;
2984
2985            *PP32_DBG_PC_MIN(n) = addr_min;
2986            *PP32_DBG_PC_MAX(n) = addr_max;
2987        }
2988
2989        if ( on_off_flag == 0 )
2990            *PP32_BRK_SRC &= ~(1 << n);
2991        else if ( on_off_flag > 0 )
2992            *PP32_BRK_SRC |= 1 << n;
2993    }
2994    else if ( strincmp(p, "data", 4) == 0 && p[4] >= '0' && p[4] <= '1' && p[5] <= ' ' ) {
2995        const static char *data_cmd_str[] = {"r", "w", "rw", "w=", "off", "min", "min addr", "max", "max addr", "val", "value"};
2996        const static int data_cmd_len[] = {1, 1, 2, 2, 3, 3, 8, 3, 8, 3, 5};
2997        const static int data_cmd_idx[] = {1, 2, 3, 4, 0, 5, 5, 6, 6, 7, 7};
2998        int n = p[4] - '0';
2999        int on_off_flag = -1, on_off_mask = 0;
3000        int addr_min = -1, addr_max = -1;
3001        int value = 0, f_got_value = 0;
3002        int stat = 0;
3003        int i;
3004        int tmp;
3005
3006        p += 6;
3007        rlen -= 6;
3008
3009        while ( 1 ) {
3010            ignore_space(&p, &rlen);
3011            if ( rlen <= 0 )
3012                break;
3013            for ( i = 0; i < NUM_ENTITY(data_cmd_str); i++ )
3014                if ( strincmp(p, data_cmd_str[i], data_cmd_len[i]) == 0 && p[data_cmd_len[i]] <= ' ' ) {
3015                    p += data_cmd_len[i];
3016                    rlen -= data_cmd_len[i];
3017                    stat = data_cmd_idx[i];
3018                    if ( stat <= 4 ) {
3019                        on_off_mask = 7;
3020                        on_off_flag = stat;
3021                    }
3022                    break;
3023                }
3024            if ( i == NUM_ENTITY(data_cmd_str) ) {
3025                if ( (*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F') ) {
3026                    tmp = get_number(&p, &rlen, 1);
3027                    if ( stat <= 5 ) {
3028                        addr_min = tmp;
3029                        stat = 6;
3030                    }
3031                    else if ( stat >= 7 ) {
3032                        value = tmp;
3033                        f_got_value = 1;
3034                    }
3035                    else {
3036                        addr_max = tmp;
3037                        stat = 7;
3038                    }
3039                }
3040                else
3041                    for ( ; rlen && *p > ' '; rlen--, p++ );
3042            }
3043        }
3044
3045        if ( addr_min >= 0 )
3046            *PP32_DBG_DATA_MIN(n) = *PP32_DBG_DATA_MAX(n) = addr_min;
3047        if ( addr_max >= 0 )
3048            *PP32_DBG_DATA_MAX(n) = addr_max;
3049        if ( f_got_value )
3050            *PP32_DBG_DATA_VAL(n) = value;
3051        if ( on_off_mask && on_off_flag >= 0 ) {
3052            on_off_flag <<= n ? 11 : 8;
3053            on_off_mask <<= n ? 11 : 8;
3054            *PP32_BRK_SRC = (*PP32_BRK_SRC & ~on_off_mask) | on_off_flag;
3055        }
3056    }
3057    else {
3058        printk("echo \"<command>\" > /proc/eth/etop\n");
3059        printk(" command:\n");
3060        printk(" start - run pp32\n");
3061        printk(" stop - stop pp32\n");
3062        printk(" step - run pp32 with one step only\n");
3063        printk(" pc - pc? [on/off] [min addr] [max addr], set PC break point\n");
3064        printk(" data - data? [r/w/rw/w=/off] [min <addr>] [max <addr>] [val <value>], set data break point\n");
3065        printk(" help - print this screen\n");
3066    }
3067
3068    vfree(str);
3069    return count;
3070}
3071
3072 #elif defined(CONFIG_AMAZON_SE)
3073
3074static int proc_read_pp32(char *page, char **start, off_t off, int count, int *eof, void *data)
3075{
3076    static const char *halt_stat[] = {
3077        "reset",
3078        "break in line",
3079        "stop",
3080        "step",
3081        "code",
3082        "data0",
3083        "data1"
3084    };
3085    static const char *brk_src_data[] = {
3086        "off",
3087        "read",
3088        "write",
3089        "read/write",
3090        "write_equal",
3091        "N/A",
3092        "N/A",
3093        "N/A"
3094    };
3095    static const char *brk_src_code[] = {
3096        "off",
3097        "on"
3098    };
3099
3100    int len = 0;
3101    int i;
3102    int k;
3103    unsigned long bit;
3104
3105    len += sprintf(page + off + len, "Task No %d, PC %04x\n", *PP32_DBG_TASK_NO & 0x03, *PP32_DBG_CUR_PC & 0xFFFF);
3106
3107    if ( !(*PP32_HALT_STAT & 0x01) )
3108        len += sprintf(page + off + len, " Halt State: Running\n");
3109    else
3110    {
3111        len += sprintf(page + off + len, " Halt State: Stopped");
3112        k = 0;
3113        for ( bit = 2, i = 0; bit <= (1 << 7); bit <<= 1, i++ )
3114            if ( (*PP32_HALT_STAT & bit) )
3115            {
3116                if ( !k )
3117                {
3118                    len += sprintf(page + off + len, ", ");
3119                    k++;
3120                }
3121                else
3122                    len += sprintf(page + off + len, " | ");
3123                len += sprintf(page + off + len, halt_stat[i]);
3124            }
3125
3126        len += sprintf(page + off + len, "\n");
3127    }
3128
3129    len += sprintf(page + off + len, " Break Src: data1 - %s, data0 - %s, pc3 - %s, pc2 - %s, pc1 - %s, pc0 - %s\n",
3130                                                    brk_src_data[(*PP32_BRK_SRC >> 11) & 0x07], brk_src_data[(*PP32_BRK_SRC >> 8) & 0x07], brk_src_code[(*PP32_BRK_SRC >> 3) & 0x01], brk_src_code[(*PP32_BRK_SRC >> 2) & 0x01], brk_src_code[(*PP32_BRK_SRC >> 1) & 0x01], brk_src_code[*PP32_BRK_SRC & 0x01]);
3131
3132// for ( i = 0; i < 4; i++ )
3133// len += sprintf(page + off + len, " pc%d: %04x - %04x\n", i, *PP32_DBG_PC_MIN(i), *PP32_DBG_PC_MAX(i));
3134
3135// for ( i = 0; i < 2; i++ )
3136// len += sprintf(page + off + len, " data%d: %04x - %04x (%08x)\n", i, *PP32_DBG_DATA_MIN(i), *PP32_DBG_DATA_MAX(i), *PP32_DBG_DATA_VAL(i));
3137
3138    *eof = 1;
3139
3140    return len;
3141}
3142
3143static int proc_write_pp32(struct file *file, const char *buf, unsigned long count, void *data)
3144{
3145    char str[2048];
3146    char *p;
3147
3148    int len, rlen;
3149
3150    len = count < sizeof(str) ? count : sizeof(str) - 1;
3151    rlen = len - copy_from_user(str, buf, len);
3152    while ( rlen && str[rlen - 1] <= ' ' )
3153        rlen--;
3154    str[rlen] = 0;
3155    for ( p = str; *p && *p <= ' '; p++, rlen-- );
3156    if ( !*p )
3157        return 0;
3158
3159    if ( stricmp(str, "start") == 0 )
3160        *PP32_DBG_CTRL = DBG_CTRL_RESTART;
3161    else if ( stricmp(str, "stop") == 0 )
3162        *PP32_DBG_CTRL = DBG_CTRL_STOP;
3163// else if ( stricmp(str, "step") == 0 )
3164// *PP32_DBG_CTRL = DBG_CTRL_STEP_SET(1);
3165    else
3166    {
3167        printk("echo \"<command>\" > /proc/eth/etop\n");
3168        printk(" command:\n");
3169        printk(" start - run pp32\n");
3170        printk(" stop - stop pp32\n");
3171// printk(" step - run pp32 with one step only\n");
3172        printk(" help - print this screen\n");
3173    }
3174
3175    return count;
3176}
3177
3178 #endif
3179
3180#endif
3181
3182#if defined(ENABLE_FW_PROC) && ENABLE_FW_PROC
3183
3184static INLINE int print_htu(char *buf, int i)
3185{
3186    int len = 0;
3187
3188    if ( HTU_ENTRY(i)->vld ) {
3189        len += sprintf(buf + len, "%2d. valid\n", i);
3190        len += sprintf(buf + len, " entry 0x%08x - pid %01x vpi %02x vci %04x pti %01x\n", *(unsigned int*)HTU_ENTRY(i), HTU_ENTRY(i)->pid, HTU_ENTRY(i)->vpi, HTU_ENTRY(i)->vci, HTU_ENTRY(i)->pti);
3191        len += sprintf(buf + len, " mask 0x%08x - pid %01x vpi %02x vci %04x pti %01x\n", *(unsigned int*)HTU_MASK(i), HTU_MASK(i)->pid_mask, HTU_MASK(i)->vpi_mask, HTU_MASK(i)->vci_mask, HTU_MASK(i)->pti_mask);
3192        len += sprintf(buf + len, " result 0x%08x - type: %s, qid: %d", *(unsigned int*)HTU_RESULT(i), HTU_RESULT(i)->type ? "cell" : "AAL5", HTU_RESULT(i)->qid);
3193        if ( HTU_RESULT(i)->type )
3194            len += sprintf(buf + len, ", cell id: %d, verification: %s", HTU_RESULT(i)->cellid, HTU_RESULT(i)->ven ? "on" : "off");
3195        len += sprintf(buf + len, "\n");
3196    }
3197    else
3198        len += sprintf(buf + len, "%2d. invalid\n", i);
3199
3200    return len;
3201}
3202
3203static int proc_read_htu(char *page, char **start, off_t off, int count, int *eof, void *data)
3204{
3205    int len = 0;
3206    int len_max = off + count;
3207    char *pstr;
3208    int llen;
3209    char *str;
3210    int htuts = *CFG_WRX_HTUTS;
3211    int i;
3212        
3213    str = vmalloc (1024);
3214    if (!str)
3215        return 0;
3216
3217    pstr = *start = page;
3218
3219    llen = sprintf(pstr, "HTU Table (Max %d):\n", htuts);
3220    pstr += llen;
3221    len += llen;
3222
3223    for ( i = 0; i < htuts; i++ ) {
3224        llen = print_htu(str, i);
3225        if ( len <= off && len + llen > off ) {
3226            memcpy(pstr, str + off - len, len + llen - off);
3227            pstr += len + llen - off;
3228        }
3229        else if ( len > off ) {
3230            memcpy(pstr, str, llen);
3231            pstr += llen;
3232        }
3233        len += llen;
3234        if ( len >= len_max )
3235            goto PROC_READ_HTU_OVERRUN_END;
3236    }
3237
3238    *eof = 1;
3239    vfree(str);
3240    return len - off;
3241
3242PROC_READ_HTU_OVERRUN_END:
3243
3244    return len - llen - off;
3245}
3246
3247static INLINE int print_tx_queue(char *buf, int i)
3248{
3249    int len = 0;
3250
3251    if ( (*WTX_DMACH_ON & (1 << i)) ) {
3252        len += sprintf(buf + len, "%2d. valid\n", i);
3253        len += sprintf(buf + len, " queue 0x%08x - sbid %u, qsb vcid %u, qsb %s\n", (unsigned int)WTX_QUEUE_CONFIG(i), (unsigned int)WTX_QUEUE_CONFIG(i)->sbid, (unsigned int)WTX_QUEUE_CONFIG(i)->qsb_vcid, WTX_QUEUE_CONFIG(i)->qsben ? "enable" : "disable");
3254        len += sprintf(buf + len, " dma 0x%08x - base %08x, len %u, vlddes %u\n", (unsigned int)WTX_DMA_CHANNEL_CONFIG(i), WTX_DMA_CHANNEL_CONFIG(i)->desba, WTX_DMA_CHANNEL_CONFIG(i)->deslen, WTX_DMA_CHANNEL_CONFIG(i)->vlddes);
3255    }
3256    else
3257        len += sprintf(buf + len, "%2d. invalid\n", i);
3258
3259    return len;
3260}
3261
3262static int proc_read_txq(char *page, char **start, off_t off, int count, int *eof, void *data)
3263{
3264    int len = 0;
3265    int len_max = off + count;
3266    char *pstr;
3267    int llen;
3268    int str_buff_len = 1024;
3269    char *str;
3270
3271    int i;
3272    
3273    str = vmalloc(str_buff_len);
3274    if (!str){
3275        return 0;
3276    }
3277    pstr = *start = page;
3278
3279    llen = sprintf(pstr, "TX Queue Config (Max %d):\n", *CFG_WTX_DCHNUM);
3280    pstr += llen;
3281    len += llen;
3282
3283    for ( i = 0; i < 16; i++ ) {
3284        llen = print_tx_queue(str, i);
3285        if ( len <= off && len + llen > off ) {
3286            memcpy(pstr, str + off - len, len + llen - off);
3287            pstr += len + llen - off;
3288        }
3289        else if ( len > off ) {
3290            memcpy(pstr, str, llen);
3291            pstr += llen;
3292        }
3293        len += llen;
3294        if ( len >= len_max )
3295            goto PROC_READ_HTU_OVERRUN_END;
3296    }
3297
3298
3299    *eof = 1;
3300
3301    vfree(str);
3302    return len - off;
3303
3304PROC_READ_HTU_OVERRUN_END:
3305
3306    return len - llen - off;
3307}
3308
3309 #if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
3310
3311static int proc_read_retx_fw(char *page, char **start, off_t off, int count, int *eof, void *data)
3312{
3313    int len = 0;
3314
3315    unsigned int next_dtu_sid_out, last_dtu_sid_in, next_cell_sid_out, isr_cell_id;
3316    unsigned int curr_time, sec_counter, curr_efb;
3317    struct Retx_adsl_ppe_intf adsl_ppe_intf;
3318
3319    adsl_ppe_intf = *RETX_ADSL_PPE_INTF;
3320    next_dtu_sid_out = *NEXT_DTU_SID_OUT;
3321    last_dtu_sid_in = *LAST_DTU_SID_IN;
3322    next_cell_sid_out = *NEXT_CELL_SID_OUT;
3323    isr_cell_id = *ISR_CELL_ID;
3324
3325    curr_time = *URetx_curr_time;
3326    sec_counter = *URetx_sec_counter;
3327    curr_efb = *RxCURR_EFB;
3328
3329
3330    len += sprintf(page + off + len, "Adsl-PPE Interface:\n");
3331    len += sprintf(page + off + len, " dtu_sid = 0x%02x [%3u]\n", adsl_ppe_intf.dtu_sid, adsl_ppe_intf.dtu_sid);
3332    len += sprintf(page + off + len, " dtu_timestamp = 0x%02x\n", adsl_ppe_intf.dtu_timestamp);
3333    len += sprintf(page + off + len, " local_time = 0x%02x\n", adsl_ppe_intf.local_time);
3334    len += sprintf(page + off + len, " is_last_cw = %u\n", adsl_ppe_intf.is_last_cw);
3335    len += sprintf(page + off + len, " reinit_flag = %u\n", adsl_ppe_intf.reinit_flag);
3336    len += sprintf(page + off + len, " is_bad_cw = %u\n", adsl_ppe_intf.is_bad_cw);
3337    len += sprintf(page + off + len, "\n");
3338
3339
3340    len += sprintf(page + off + len, "Retx Firmware Context:\n");
3341    len += sprintf(page + off + len, " next_dtu_sid_out (0x%08x) = 0x%02x [%3u]\n", (unsigned int )NEXT_DTU_SID_OUT, next_dtu_sid_out, next_dtu_sid_out);
3342    len += sprintf(page + off + len, " last_dtu_sid_in (0x%08x) = 0x%02x [%3u]\n", (unsigned int )LAST_DTU_SID_IN, last_dtu_sid_in, last_dtu_sid_in);
3343    len += sprintf(page + off + len, " next_cell_sid_out (0x%08x) = %u\n", (unsigned int )NEXT_CELL_SID_OUT, next_cell_sid_out);
3344    len += sprintf(page + off + len, " isr_cell_id (0x%08x) = %u\n", (unsigned int )ISR_CELL_ID, isr_cell_id);
3345    len += sprintf(page + off + len, " pb_cell_search_idx (0x%08x) = %u\n", (unsigned int )PB_CELL_SEARCH_IDX, *PB_CELL_SEARCH_IDX);
3346    len += sprintf(page + off + len, " pb_read_pend_flag (0x%08x) = %u\n", (unsigned int )PB_READ_PEND_FLAG, *PB_READ_PEND_FLAG);
3347    len += sprintf(page + off + len, " rfbi_first_cw (0x%08x) = %u\n", (unsigned int )RFBI_FIRST_CW, *RFBI_FIRST_CW);
3348    len += sprintf(page + off + len, " rfbi_bad_cw (0x%08x) = %u\n", (unsigned int )RFBI_BAD_CW, *RFBI_BAD_CW);
3349    len += sprintf(page + off + len, " rfbi_invalid_cw (0x%08x) = %u\n", (unsigned int )RFBI_INVALID_CW, *RFBI_INVALID_CW);
3350    len += sprintf(page + off + len, " rfbi_retx_cw (0x%08x) = %u\n", (unsigned int )RFBI_RETX_CW, *RFBI_RETX_CW);
3351    len += sprintf(page + off + len, " rfbi_chk_dtu_status (0x%08x) = %u\n", (unsigned int )RFBI_CHK_DTU_STATUS,*RFBI_CHK_DTU_STATUS);
3352    len += sprintf(page + off + len, "\n");
3353
3354
3355    len += sprintf(page + off + len, "SFSM Status: bc0 bc1 \n\n");
3356    len += sprintf(page + off + len, " state = %-22s , %s\n",
3357          (*__WRXCTXT_PortState(0) & 3) == 0 ? "Hunt" :
3358          (*__WRXCTXT_PortState(0) & 3) == 1 ? "Pre_sync" :
3359          (*__WRXCTXT_PortState(0) & 3) == 2 ? "Sync" :
3360                                               "Unknown(error)",
3361          (*__WRXCTXT_PortState(1) & 3) == 0 ? "Hunt" :
3362          (*__WRXCTXT_PortState(1) & 3) == 1 ? "Pre_sync" :
3363          (*__WRXCTXT_PortState(1) & 3) == 2 ? "Sync" :
3364                                               "Unknown(error)" );
3365    len += sprintf(page + off + len, " dbase = 0x%04x ( 0x%08x ) , 0x%04x ( 0x%08x )\n",
3366            SFSM_DBA(0)->dbase, (unsigned int)PPM_INT_UNIT_ADDR(SFSM_DBA(0)->dbase + 0x2000),
3367            SFSM_DBA(1)->dbase, (unsigned int)PPM_INT_UNIT_ADDR(SFSM_DBA(1)->dbase + 0x2000));
3368    len += sprintf(page + off + len, " cbase = 0x%04x ( 0x%08x ) , 0x%04x ( 0x%08x )\n",
3369            SFSM_CBA(0)->cbase, (unsigned int)PPM_INT_UNIT_ADDR(SFSM_CBA(0)->cbase + 0x2000),
3370            SFSM_CBA(1)->cbase, (unsigned int)PPM_INT_UNIT_ADDR(SFSM_CBA(1)->cbase + 0x2000));
3371    len += sprintf(page + off + len, " sen = %-22d , %d\n", SFSM_CFG(0)->sen, SFSM_CFG(1)->sen );
3372    len += sprintf(page + off + len, " idlekeep = %-22d , %d\n", SFSM_CFG(0)->idlekeep, SFSM_CFG(1)->idlekeep );
3373    len += sprintf(page + off + len, " pnum = %-22d , %d\n", SFSM_CFG(0)->pnum, SFSM_CFG(1)->pnum );
3374    len += sprintf(page + off + len, " pptr = %-22d , %d\n", SFSM_PGCNT(0)->pptr, SFSM_PGCNT(1)->pptr);
3375    len += sprintf(page + off + len, " upage = %-22d , %d\n", SFSM_PGCNT(0)->upage, SFSM_PGCNT(1)->upage);
3376    len += sprintf(page + off + len, " l2_rdptr = %-22d , %d\n", *__WRXCTXT_L2_RdPtr(0), *__WRXCTXT_L2_RdPtr(1) );
3377    len += sprintf(page + off + len, " l2_page = %-22d , %d\n", *__WRXCTXT_L2Pages(0), *__WRXCTXT_L2Pages(1) );
3378    len += sprintf(page + off + len, "\n");
3379
3380
3381    len += sprintf(page + off + len, "FFSM Status: bc0 bc1 \n\n");
3382    len += sprintf(page + off + len, " dbase = 0x%04x ( 0x%08x ) , 0x%04x ( 0x%08x )\n",
3383            FFSM_DBA(0)->dbase, (unsigned int)PPM_INT_UNIT_ADDR(FFSM_DBA(0)->dbase + 0x2000),
3384            FFSM_DBA(1)->dbase, (unsigned int)PPM_INT_UNIT_ADDR(FFSM_DBA(1)->dbase + 0x2000));
3385    len += sprintf(page + off + len, " pnum = %-22d , %d\n", FFSM_CFG(0)->pnum, FFSM_CFG(1)->pnum);
3386    len += sprintf(page + off + len, " vpage = %-22d , %d\n", FFSM_PGCNT(0)->vpage, FFSM_PGCNT(1)->vpage);
3387    len += sprintf(page + off + len, " ival = %-22d , %d\n", FFSM_PGCNT(0)->ival, FFSM_PGCNT(1)->ival);
3388    len += sprintf(page + off + len, " tc_wrptr = %-22d , %d\n", *__WTXCTXT_TC_WRPTR(0), *__WTXCTXT_TC_WRPTR(1));
3389    len += sprintf(page + off + len, "\n");
3390
3391
3392    len += sprintf(page + off + len, "Misc: \n\n");
3393    len += sprintf(page + off + len, " curr_time = %08x\n", curr_time );
3394    len += sprintf(page + off + len, " sec_counter = %d\n", sec_counter );
3395    len += sprintf(page + off + len, " curr_efb = %d\n", curr_efb );
3396    len += sprintf(page + off + len, "\n");
3397
3398    *eof = 1;
3399
3400    return len;
3401}
3402
3403static inline int is_valid(unsigned int * dtu_vld_stat, int dtu_sid)
3404{
3405    int dw_idx = (dtu_sid / 32) & 7;
3406    int bit_pos = dtu_sid % 32;
3407
3408    return dtu_vld_stat[dw_idx] & (0x80000000 >> bit_pos);
3409}
3410
3411static int proc_read_retx_stats(char *page, char **start, off_t off, int count, int *eof, void *data)
3412{
3413    int i;
3414    int len = 0;
3415    int len_max = off + count;
3416    char *pstr;
3417    char str[2048];
3418    int llen = 0;
3419
3420    unsigned int next_dtu_sid_out, last_dtu_sid_in, next_cell_sid_out;
3421    unsigned int dtu_vld_stat[8];
3422    struct DTU_stat_info dtu_stat_info[256];
3423    struct Retx_adsl_ppe_intf adsl_ppe_intf;
3424
3425    pstr = *start = page;
3426
3427    __sync();
3428
3429    // capture a snapshot of internal status
3430    next_dtu_sid_out = *NEXT_DTU_SID_OUT;
3431    last_dtu_sid_in = *LAST_DTU_SID_IN;
3432    next_cell_sid_out = *NEXT_CELL_SID_OUT;
3433    adsl_ppe_intf = *RETX_ADSL_PPE_INTF;
3434
3435    memcpy(&dtu_vld_stat, (void *)DTU_VLD_STAT, sizeof(dtu_vld_stat));
3436    memcpy(&dtu_stat_info, (void *)DTU_STAT_INFO, sizeof(dtu_stat_info));
3437
3438
3439    llen += sprintf(str + llen, "Adsl-PPE Interface:\n");
3440    llen += sprintf(str + llen, " dtu_sid = 0x%02x [%3u]\n", adsl_ppe_intf.dtu_sid, adsl_ppe_intf.dtu_sid);
3441    llen += sprintf(str + llen, " dtu_timestamp = 0x%02x\n", adsl_ppe_intf.dtu_timestamp);
3442    llen += sprintf(str + llen, " local_time = 0x%02x\n", adsl_ppe_intf.local_time);
3443    llen += sprintf(str + llen, " is_last_cw = %u\n", adsl_ppe_intf.is_last_cw);
3444    llen += sprintf(str + llen, " reinit_flag = %u\n", adsl_ppe_intf.reinit_flag);
3445    llen += sprintf(str + llen, " is_bad_cw = %u\n", adsl_ppe_intf.is_bad_cw);
3446    llen += sprintf(str + llen, "\n");
3447
3448    llen += sprintf(str + llen, "Retx Internal State:\n");
3449    llen += sprintf(str + llen, " next_dtu_sid_out (0x%08x) = 0x%02x [%3u]\n", (unsigned int )NEXT_DTU_SID_OUT, next_dtu_sid_out, next_dtu_sid_out);
3450    llen += sprintf(str + llen, " last_dtu_sid_in (0x%08x) = 0x%02x [%3u]\n", (unsigned int )LAST_DTU_SID_IN, last_dtu_sid_in, last_dtu_sid_in);
3451    llen += sprintf(str + llen, " next_cell_sid_out (0x%08x) = %u\n", (unsigned int )NEXT_CELL_SID_OUT, next_cell_sid_out);
3452    llen += sprintf(str + llen, " dtu_valid_stat (0x%08x)\n", (unsigned int )DTU_VLD_STAT);
3453    llen += sprintf(str + llen, " dtu_stat_info (0x%08x)\n", (unsigned int )DTU_STAT_INFO);
3454    llen += sprintf(str + llen, " pb_buffer_usage (0x%08x)\n", (unsigned int )PB_BUFFER_USAGE);
3455
3456    if ( len <= off && len + llen > off ) {
3457        memcpy(pstr, str + off - len, len + llen - off);
3458        pstr += len + llen - off;
3459    }
3460    else if ( len > off ) {
3461        memcpy(pstr, str, llen);
3462        pstr += llen;
3463    }
3464    len += llen;
3465    if ( len >= len_max )
3466        goto PROC_READ_RETX_STATS_OVERRUN_END;
3467    llen = 0;
3468
3469
3470    llen += sprintf(str + llen, "\n");
3471    llen += sprintf(str + llen, "DTU_VALID_STAT: [0x%08x]:\n", (unsigned int)DTU_VLD_STAT);
3472    llen += sprintf(str + llen, "%08X: %08X %08X %08X %08X %08X %08X %08X %08X\n",
3473                    (unsigned int)DTU_VLD_STAT,
3474                    dtu_vld_stat[0], dtu_vld_stat[1], dtu_vld_stat[2], dtu_vld_stat[3],
3475                    dtu_vld_stat[4], dtu_vld_stat[5], dtu_vld_stat[6], dtu_vld_stat[7]);
3476
3477    if ( len <= off && len + llen > off ) {
3478        memcpy(pstr, str + off - len, len + llen - off);
3479        pstr += len + llen - off;
3480    }
3481    else if ( len > off ) {
3482        memcpy(pstr, str, llen);
3483        pstr += llen;
3484    }
3485    len += llen;
3486    if ( len >= len_max )
3487        goto PROC_READ_RETX_STATS_OVERRUN_END;
3488    llen = 0;
3489
3490
3491    llen += sprintf(str + llen, "\n");
3492    llen += sprintf(str + llen, "DTU_STAT_INFO: [0x%08x]:\n", (unsigned int)DTU_STAT_INFO);
3493    llen += sprintf(str + llen, "dtu_id ts complete bad cell_cnt dtu_rd_ptr dtu_wr_ptr\n");
3494    llen += sprintf(str + llen, "---------------------------------------------------------------------\n");
3495    for ( i = 0; i < 256; i++ ) {
3496        if ( !is_valid(dtu_vld_stat, i) )
3497            continue;
3498
3499        llen += sprintf(str + llen, "0x%02x [%3u] 0x%02x %d %d %3d %5d %5d\n",
3500                        i, i,
3501                        DTU_STAT_INFO[i].time_stamp,
3502                        DTU_STAT_INFO[i].complete,
3503                        DTU_STAT_INFO[i].bad,
3504                        DTU_STAT_INFO[i].cell_cnt,
3505                        DTU_STAT_INFO[i].dtu_rd_ptr,
3506                        DTU_STAT_INFO[i].dtu_wr_ptr );
3507
3508        if ( len <= off && len + llen > off ) {
3509            memcpy(pstr, str + off - len, len + llen - off);
3510            pstr += len + llen - off;
3511        }
3512        else if ( len > off )
3513        {
3514            memcpy(pstr, str, llen);
3515            pstr += llen;
3516        }
3517        len += llen;
3518        if ( len >= len_max )
3519            goto PROC_READ_RETX_STATS_OVERRUN_END;
3520        llen = 0;
3521    }
3522
3523
3524    llen += sprintf(str + llen, "\n");
3525    llen += sprintf(str + llen, "Playout buffer status --- valid status [0x%08x]:\n", (unsigned int)PB_BUFFER_USAGE);
3526    for( i = 0; i < RETX_MODE_CFG->buff_size; i += 8 ) {
3527        llen += sprintf(str + llen, "%08X: %08X %08X %08X %08X %08X %08X %08X %08X\n",
3528                        (unsigned int)PB_BUFFER_USAGE + i * sizeof(unsigned int),
3529                        PB_BUFFER_USAGE[i], PB_BUFFER_USAGE[i+1], PB_BUFFER_USAGE[i+2], PB_BUFFER_USAGE[i+3],
3530                        PB_BUFFER_USAGE[i+4], PB_BUFFER_USAGE[i+5], PB_BUFFER_USAGE[i+6], PB_BUFFER_USAGE[i+7]);
3531    }
3532
3533    if ( len <= off && len + llen > off ) {
3534        memcpy(pstr, str + off - len, len + llen - off);
3535        pstr += len + llen - off;
3536    }
3537    else if ( len > off ) {
3538        memcpy(pstr, str, llen);
3539        pstr += llen;
3540    }
3541    len += llen;
3542    if ( len >= len_max )
3543        goto PROC_READ_RETX_STATS_OVERRUN_END;
3544    llen = 0;
3545
3546
3547    *eof = 1;
3548
3549    return len - off;
3550
3551PROC_READ_RETX_STATS_OVERRUN_END:
3552    return len - llen - off;
3553}
3554
3555static int proc_write_retx_stats(struct file *file, const char *buf, unsigned long count, void *data)
3556{
3557    char str[2048];
3558    char *p;
3559
3560    int len, rlen;
3561
3562    len = count < sizeof(str) ? count : sizeof(str) - 1;
3563    rlen = len - copy_from_user(str, buf, len);
3564    while ( rlen && str[rlen - 1] <= ' ' )
3565        rlen--;
3566    str[rlen] = 0;
3567    for ( p = str; *p && *p <= ' '; p++, rlen-- );
3568    if ( !*p )
3569        return 0;
3570
3571    if ( stricmp(p, "help") == 0 ) {
3572        printk("echo clear_pb > /proc/driver/ifx_atm/retx_stats \n");
3573        printk(" :clear context in playout buffer\n\n");
3574        printk("echo read_pb <pb_index> <cell_num> > /proc/driver/ifx_atm/retx_stats\n");
3575        printk(" : read playout buffer contents\n\n");
3576        printk("echo read_[r|t]x_cb > /proc/driver/ifx_atm/retx_stats\n");
3577        printk(" : read cell buffer\n\n");
3578        printk("echo clear_[r|t]x_cb > /proc/driver/ifx_atm/retx_stats\n");
3579        printk(" : clear cell buffer\n\n");
3580        printk("echo read_bad_dtu_intf_rec > /proc/driver/ifx_atm/retx_stats\n");
3581        printk(" : read bad dtu intrface information record\n\n");
3582        printk("echo clear_bad_dtu_intf_rec > /proc/driver/ifx_atm/retx_stats\n");
3583        printk(" : clear bad dtu interface information record\n\n");
3584        printk("echo read_wrx_context [i] > /proc/driver/ifx_atm/retx_stats\n");
3585        printk(" : clear bad dtu interface information record\n\n");
3586        printk("echo read_intf_rec > /proc/driver/ifx_atm/retx_stats\n");
3587        printk(" : read interface info record buffer\n\n");
3588        printk("echo reinit_intf_rec > /proc/driver/ifx_atm/retx_stats\n");
3589        printk(" : reinit intf record, must be called before showtime\n\n");
3590    }
3591    else if ( stricmp(p, "reinit_intf_rec") == 0 ) {
3592        int i = 0;
3593        struct Retx_adsl_ppe_intf_rec rec[16];
3594
3595        *DBG_DTU_INTF_WRPTR = 0;
3596        *DBG_INTF_FCW_DUP_CNT = 0;
3597        *DBG_INTF_SID_CHANGE_IN_DTU_CNT = 0;
3598        *DBG_INTF_LCW_DUP_CNT = 0;
3599
3600        *DBG_RFBI_DONE_INT_CNT = 0;
3601        *DBG_RFBI_INTV0 = 0;
3602        *DBG_RFBI_INTV1 = 0;
3603        *DBG_RFBI_BC0_INVALID_CNT = 0;
3604        *DBG_RFBI_LAST_T = 0;
3605        *DBG_DREG_BEG_END = 0;
3606
3607        memset((void *) DBG_INTF_INFO(0), 0, sizeof(rec));
3608        for( i = 0; i < 16; i++ )
3609            DBG_INTF_INFO(i)->res1_1 = 1;
3610        DBG_INTF_INFO(15)->dtu_sid = 255;
3611    }
3612    else if ( stricmp(p, "read_intf_rec") == 0 ) {
3613        int i, cnt;
3614        unsigned int dtu_intf_wrptr, fcw_dup_cnt, sid_change_in_dtu_cnt, lcw_dup_cnt ;
3615        unsigned int rfbi_done_int_cnt, rfbi_intv0, rfbi_intv1, rfbi_bc0_invalid_cnt, dreg_beg_end;
3616        struct Retx_adsl_ppe_intf_rec rec[16];
3617
3618        memcpy((void *) rec, (void *) DBG_INTF_INFO(0), sizeof(rec));
3619
3620        dtu_intf_wrptr = *DBG_DTU_INTF_WRPTR;
3621        fcw_dup_cnt = *DBG_INTF_FCW_DUP_CNT;
3622        sid_change_in_dtu_cnt = *DBG_INTF_SID_CHANGE_IN_DTU_CNT;
3623        lcw_dup_cnt = *DBG_INTF_LCW_DUP_CNT;
3624
3625        rfbi_done_int_cnt = *DBG_RFBI_DONE_INT_CNT;
3626        rfbi_intv0 = *DBG_RFBI_INTV0;
3627        rfbi_intv1 = *DBG_RFBI_INTV1;
3628        rfbi_bc0_invalid_cnt = *DBG_RFBI_BC0_INVALID_CNT;
3629        dreg_beg_end = *DBG_DREG_BEG_END;
3630
3631        printk("PPE-Adsl Interface recrod [addr 0x23F0]:\n\n");
3632
3633        printk(" rfbi_done_int_cnt = %d [0x%x] \n", rfbi_done_int_cnt, rfbi_done_int_cnt);
3634        printk(" rfbi_intv = 0x%08x 0x%08x [%d, %d, %d, %d, %d, %d, %d, %d]\n",
3635                    rfbi_intv0, rfbi_intv1,
3636                    rfbi_intv0 >> 24, (rfbi_intv0>>16) & 0xff, (rfbi_intv0>>8) & 0xff, rfbi_intv0 & 0xff,
3637                    rfbi_intv1 >> 24, (rfbi_intv1>>16) & 0xff, (rfbi_intv1>>8) & 0xff, rfbi_intv1 & 0xff
3638                    );
3639        printk(" rfbi_bc0_invld_cnt = %d\n", rfbi_bc0_invalid_cnt);
3640        printk(" dreg_beg_end = %d, %d\n\n", dreg_beg_end >> 16, dreg_beg_end & 0xffff);
3641
3642        printk(" wrptr = %d [0x%x] \n", dtu_intf_wrptr, dtu_intf_wrptr);
3643        printk(" fcw_dup_cnt = %d\n", fcw_dup_cnt);
3644        printk(" sid_chg_cnt = %d\n", sid_change_in_dtu_cnt);
3645        printk(" lcw_dup_cnt = %d\n\n", lcw_dup_cnt);
3646
3647
3648        printk(" idx itf_dw0 itf_dw1 dtu_sid timestamp local_time res1 last_cw bad_flag reinit\n");
3649        printk(" -------------------------------------------------------------------------------------\n");
3650        for ( i = (dtu_intf_wrptr + 1) % 16, cnt = 0; cnt < 16; cnt ++, i = (i + 1) % 16 ) {
3651            if(cnt < 15)
3652                printk(" ");
3653            else
3654                printk(" *");
3655            printk("%3d %04x %04x %3d[%02x] %3d[%02x] %3d[%02x] 0x%02x %d %d %d\n",
3656                i,
3657                (*(unsigned int *)&rec[i]) & 0xffff,
3658                (*(unsigned int *)&rec[i]) >> 16,
3659                rec[i].dtu_sid, rec[i].dtu_sid,
3660                rec[i].dtu_timestamp, rec[i].dtu_timestamp,
3661                rec[i].local_time, rec[i].local_time,
3662                rec[i].res1_1,
3663                rec[i].is_last_cw,
3664                rec[i].is_bad_cw,
3665                rec[i].reinit_flag );
3666        }
3667    }
3668    else if ( stricmp(p, "read_wrx_context") == 0 ) {
3669        int i = 0;
3670        int flag = 0;
3671        for( i = 0; i < 8; ++i ) {
3672            if ( !WRX_QUEUE_CONTEXT(i)->curr_des0 || !WRX_QUEUE_CONTEXT(i)->curr_des1 )
3673                continue;
3674
3675            flag = 1;
3676            printk("WRX queue context [ %d ]: \n", i);
3677            printk(" curr_len = %4d, mfs = %d, ec = %d, clp1 = %d, aal5dp = %d\n",
3678                    WRX_QUEUE_CONTEXT(i)->curr_len, WRX_QUEUE_CONTEXT(i)->mfs,
3679                    WRX_QUEUE_CONTEXT(i)->ec, WRX_QUEUE_CONTEXT(i)->clp1,
3680                    WRX_QUEUE_CONTEXT(i)->aal5dp);
3681            printk(" initcrc = %08x\n", WRX_QUEUE_CONTEXT(i)->intcrc);
3682            printk(" currdes = %08x %08x\n",
3683                    WRX_QUEUE_CONTEXT(i)->curr_des0, WRX_QUEUE_CONTEXT(i)->curr_des1);
3684            printk(" last_dw = %08x\n\n", WRX_QUEUE_CONTEXT(i)->last_dword);
3685            if( WRX_QUEUE_CONTEXT(i)->curr_len ) {
3686                int j = 0;
3687                unsigned char *p_char;
3688                struct rx_descriptor *desc = (struct rx_descriptor *)&(WRX_QUEUE_CONTEXT(i)->curr_des0);
3689                p_char = (unsigned char *)(((unsigned int)desc->dataptr << 2) | KSEG1);
3690                printk(" Data in SDRAM:\n ");
3691
3692                for ( j = 0 ; j < WRX_QUEUE_CONTEXT(i)->curr_len; ++j ) {
3693                    printk ("%02x", p_char[j]);
3694                    if ( j % 16 == 15 )
3695                        printk("\n ");
3696                    else if ( j % 4 == 3 )
3697                        printk (" ");
3698                }
3699                printk("\n\n");
3700            }
3701        }
3702        if ( !flag ) {
3703            printk("No active wrx queue context\n");
3704        }
3705    }
3706    else if ( stricmp(p, "clear_pb") == 0 ) {
3707        if ( g_retx_playout_buffer )
3708            memset((void *)g_retx_playout_buffer, 0, RETX_PLAYOUT_BUFFER_SIZE);
3709    }
3710    else if ( stricmp(p, "read_bad_dtu_intf_rec") == 0 ) {
3711        struct Retx_adsl_ppe_intf first_dtu_intf, last_dtu_intf;
3712        first_dtu_intf = *FIRST_BAD_REC_RETX_ADSL_PPE_INTF;
3713        last_dtu_intf = *BAD_REC_RETX_ADSL_PPE_INTF;
3714
3715        printk("\nAdsl-PPE Interface for first and last DTU of recent noise:\n\n");
3716        printk(" dtu_sid = 0x%02x [%3u], 0x%02x [%3u]\n",
3717                first_dtu_intf.dtu_sid, first_dtu_intf.dtu_sid,
3718                last_dtu_intf.dtu_sid, last_dtu_intf.dtu_sid);
3719        printk(" dtu_timestamp = 0x%02x , 0x%02x\n",
3720                first_dtu_intf.dtu_timestamp, last_dtu_intf.dtu_timestamp);
3721        printk(" local_time = 0x%02x , 0x%02x\n",
3722                first_dtu_intf.local_time, last_dtu_intf.local_time);
3723        printk(" is_last_cw = %u , %u\n",
3724                first_dtu_intf.is_last_cw, last_dtu_intf.is_last_cw);
3725        printk(" reinit_flag = %u , %u\n",
3726                first_dtu_intf.reinit_flag, last_dtu_intf.reinit_flag);
3727        printk(" is_bad_cw = %u , %u\n\n",
3728                first_dtu_intf.is_bad_cw, last_dtu_intf.is_bad_cw);
3729    }
3730    else if ( stricmp(p, "clear_bad_dtu_intf_rec") == 0 ) {
3731        memset((void *)BAD_REC_RETX_ADSL_PPE_INTF, 0, sizeof(struct Retx_adsl_ppe_intf));
3732        memset((void *)FIRST_BAD_REC_RETX_ADSL_PPE_INTF, 0, sizeof(struct Retx_adsl_ppe_intf));
3733    }
3734    else if ( stricmp(p, "clear_tx_cb") == 0 ) {
3735        unsigned int *dbase0;
3736        unsigned int pnum0;
3737
3738        dbase0 = (unsigned int *)PPM_INT_UNIT_ADDR( FFSM_DBA(0)->dbase + 0x2000);
3739        pnum0 = FFSM_CFG(0)->pnum;
3740        memset(dbase0, 0, 14 * sizeof(unsigned int ) * pnum0);
3741    }
3742    else if ( stricmp(p, "clear_rx_cb") == 0 ) {
3743        unsigned int *dbase0, *cbase0, *dbase1, *cbase1;
3744        unsigned int pnum0;
3745
3746        dbase0 = (unsigned int *)PPM_INT_UNIT_ADDR( SFSM_DBA(0)->dbase + 0x2000);
3747        cbase0 = (unsigned int *)PPM_INT_UNIT_ADDR( SFSM_CBA(0)->cbase + 0x2000);
3748
3749        dbase1 = (unsigned int *)PPM_INT_UNIT_ADDR( SFSM_DBA(1)->dbase + 0x2000);
3750        cbase1 = (unsigned int *)PPM_INT_UNIT_ADDR( SFSM_CBA(1)->cbase + 0x2000);
3751
3752        pnum0 = SFSM_CFG(0)->pnum;
3753
3754        memset(dbase0, 0, 14 * sizeof(unsigned int ) * pnum0);
3755        memset(cbase0, 0, sizeof(unsigned int ) * pnum0);
3756
3757        memset(dbase1, 0, 14 * sizeof(unsigned int ));
3758        memset(cbase1, 0, sizeof(unsigned int ));
3759    }
3760    else if ( strnicmp(p, "read_tx_cb", 10) == 0 ) {
3761        unsigned int *dbase0;
3762        unsigned int pnum0, i;
3763        unsigned int * cell;
3764
3765        dbase0 = (unsigned int *)PPM_INT_UNIT_ADDR( FFSM_DBA(0)->dbase + 0x2000);
3766        pnum0 = FFSM_CFG(0)->pnum;
3767
3768        printk("ATM TX BC 0 CELL data/ctrl buffer:\n\n");
3769        for(i = 0; i < pnum0 ; ++ i) {
3770            cell = dbase0 + i * 14;
3771            printk("cell %2d: %08x %08x\n", i, cell[0], cell[1]);
3772            printk(" %08x %08x %08x %08x\n", cell[2], cell[3], cell[4], cell[5]);
3773            printk(" %08x %08x %08x %08x\n", cell[6], cell[7], cell[8], cell[9]);
3774            printk(" %08x %08x %08x %08x\n", cell[10], cell[11], cell[12], cell[13]);
3775        }
3776    }
3777    else if ( strnicmp(p, "read_rx_cb", 10) == 0 ) {
3778        unsigned int *dbase0, *cbase0, *dbase1, *cbase1;
3779        unsigned int pnum0, i;
3780        unsigned int * cell;
3781
3782        dbase0 = (unsigned int *)PPM_INT_UNIT_ADDR( SFSM_DBA(0)->dbase + 0x2000);
3783        cbase0 = (unsigned int *)PPM_INT_UNIT_ADDR( SFSM_CBA(0)->cbase + 0x2000);
3784
3785        dbase1 = (unsigned int *)PPM_INT_UNIT_ADDR( SFSM_DBA(1)->dbase + 0x2000);
3786        cbase1 = (unsigned int *)PPM_INT_UNIT_ADDR( SFSM_CBA(1)->cbase + 0x2000);
3787
3788        pnum0 = SFSM_CFG(0)->pnum;
3789
3790        printk("ATM RX BC 0 CELL data/ctrl buffer:\n\n");
3791        for(i = 0; i < pnum0 ; ++ i) {
3792            struct Retx_ctrl_field * p_ctrl;
3793
3794            cell = dbase0 + i * 14;
3795            p_ctrl = (struct Retx_ctrl_field *) ( &cbase0[i]);
3796            printk("cell %2d: %08x %08x -- [%08x]:", i, cell[0], cell[1], cbase0[i]);
3797
3798            printk("l2_drop: %d, retx: %d", p_ctrl->l2_drop, p_ctrl->retx);
3799            if ( p_ctrl->retx ) {
3800                printk(", dtu_sid = %u, cell_sid = %u", p_ctrl->dtu_sid, p_ctrl->cell_sid);
3801            }
3802
3803            printk("\n");
3804
3805            printk(" %08x %08x %08x %08x\n", cell[2], cell[3], cell[4], cell[5]);
3806            printk(" %08x %08x %08x %08x\n", cell[6], cell[7], cell[8], cell[9]);
3807            printk(" %08x %08x %08x %08x\n", cell[10], cell[11], cell[12], cell[13]);
3808        }
3809
3810        printk("\n");
3811        printk("ATM RX BC 1 CELL data/ctrl buffer:\n\n");
3812        cell = dbase1;
3813        printk("cell %2d: %08x %08x -- [%08x]: dtu_sid:%3d, cell_sid:%3d, next_ptr: %4d\n",
3814                0, cell[0], cell[1], cbase0[i], ( cell[1] >> 16) & 0xff, (cell[1] >> 24) & 0xff, cell[1] & 0xffff );
3815        printk(" %08x %08x %08x %08x\n", cell[2], cell[3], cell[4], cell[5]);
3816        printk(" %08x %08x %08x %08x\n", cell[6], cell[7], cell[8], cell[9]);
3817        printk(" %08x %08x %08x %08x\n", cell[10], cell[11], cell[12], cell[13]);
3818    }
3819    else if ( strnicmp(p, "read_pb ", 8) == 0 )
3820    {
3821        int start_cell_idx = 0;
3822        int cell_num = 0;
3823        unsigned int *cell;
3824        unsigned int pb_buff_size = RETX_MODE_CFG->buff_size * 32;
3825
3826        p += 8;
3827        rlen -= 8;
3828        ignore_space(&p, &rlen);
3829
3830        start_cell_idx = get_number(&p, &rlen, 0);
3831        ignore_space(&p, &rlen);
3832        cell_num = get_number(&p, &rlen, 0);
3833
3834        if ( start_cell_idx >= pb_buff_size ) {
3835            printk(" Invalid cell index\n");
3836        }
3837        else {
3838            int i;
3839            if ( cell_num < 0 )
3840                cell_num = 1;
3841
3842            if ( cell_num + start_cell_idx > pb_buff_size )
3843                cell_num = pb_buff_size - start_cell_idx;
3844
3845            for ( i = 0; i < cell_num ; ++i ) {
3846                cell = (unsigned int *)((unsigned int *)g_retx_playout_buffer + (14 * (start_cell_idx + i)));
3847                printk("cell %4d: %08x %08x [next_ptr = %4u, dtu_sid = %3u, cell_sid = %3u]\n",
3848                        start_cell_idx + i, cell[0], cell[1], cell[1] & 0xffff, (cell[1] >> 16) & 0xff, (cell[1] >> 24) & 0xff);
3849                printk(" %08x %08x %08x %08x\n", cell[2], cell[3], cell[4], cell[5]);
3850                printk(" %08x %08x %08x %08x\n", cell[6], cell[7], cell[8], cell[9]);
3851                printk(" %08x %08x %08x %08x\n", cell[10], cell[11], cell[12], cell[13]);
3852            }
3853        }
3854    }
3855
3856    return count;
3857}
3858
3859static int proc_read_retx_cfg(char *page, char **start, off_t off, int count, int *eof, void *data)
3860{
3861    int len = 0;
3862
3863    len += sprintf(page + off + len, "ReTX FW Config:\n");
3864    len += sprintf(page + off + len, " RETX_MODE_CFG = 0x%08x, invld_range=%u, buff_size=%u, retx=%u\n", *(volatile unsigned int *)RETX_MODE_CFG, (unsigned int)RETX_MODE_CFG->invld_range, (unsigned int)RETX_MODE_CFG->buff_size * 32, (unsigned int)RETX_MODE_CFG->retx_en);
3865    len += sprintf(page + off + len, " RETX_TSYNC_CFG = 0x%08x, fw_alpha=%u, sync_inp=%u\n", *(volatile unsigned int *)RETX_TSYNC_CFG, (unsigned int)RETX_TSYNC_CFG->fw_alpha, (unsigned int)RETX_TSYNC_CFG->sync_inp);
3866    len += sprintf(page + off + len, " RETX_TD_CFG = 0x%08x, td_max=%u, td_min=%u\n", *(volatile unsigned int *)RETX_TD_CFG, (unsigned int)RETX_TD_CFG->td_max, (unsigned int)RETX_TD_CFG->td_min);
3867    len += sprintf(page + off + len, " RETX_PLAYOUT_BUFFER_BASE = 0x%08x\n", *RETX_PLAYOUT_BUFFER_BASE);
3868    len += sprintf(page + off + len, " RETX_SERVICE_HEADER_CFG = 0x%08x\n", *RETX_SERVICE_HEADER_CFG);
3869    len += sprintf(page + off + len, " RETX_MASK_HEADER_CFG = 0x%08x\n", *RETX_MASK_HEADER_CFG);
3870    len += sprintf(page + off + len, " RETX_MIB_TIMER_CFG = 0x%08x, tick_cycle = %d, ticks_per_sec = %d\n",
3871                    *(unsigned int *)RETX_MIB_TIMER_CFG, RETX_MIB_TIMER_CFG->tick_cycle, RETX_MIB_TIMER_CFG->ticks_per_sec);
3872
3873    *eof = 1;
3874
3875    return len;
3876}
3877
3878static int proc_write_retx_cfg(struct file *file, const char *buf, unsigned long count, void *data)
3879{
3880    char *p1, *p2;
3881    int len;
3882    int colon;
3883    char local_buf[1024];
3884    char *tokens[4] = {0};
3885    unsigned int token_num = 0;
3886
3887    len = sizeof(local_buf) < count ? sizeof(local_buf) - 1 : count;
3888    len = len - copy_from_user(local_buf, buf, len);
3889    local_buf[len] = 0;
3890
3891    p1 = local_buf;
3892    colon = 0;
3893    while ( token_num < NUM_ENTITY(tokens) && get_token(&p1, &p2, &len, &colon) ) {
3894        tokens[token_num++] = p1;
3895
3896        p1 = p2;
3897    }
3898
3899    if ( token_num > 0 ) {
3900        if ( stricmp(tokens[0], "help") == 0 ) {
3901            printk("echo help > /proc/driver/ifx_atm/retx_cfg ==> \n\tprint this help message\n\n");
3902
3903            printk("echo set retx <enable|disable|0|1|on|off> > /proc/driver/ifx_atm/retx_cfg\n");
3904            printk("\t:enable or disable retx feature\n\n");
3905
3906            printk("echo set <td_max|td_min|fw_alpha|sync_inp|invld_range|buff_size> <number> > /proc/driver/ifx_atm/retx_cfg\n");
3907            printk("\t: set td_max, td_min, fw_alpha, sync_inp, invalid_range, buff_size\n\n");
3908
3909            printk("echo set <service_header|service_mask> <hex_number> /proc/driver/ifx_atm/retx_cfg \n");
3910            printk("\t: set service_header, service_mask\n\n");
3911        }
3912        else if ( stricmp(tokens[0], "set") == 0 && token_num >= 3 ) {
3913
3914            if ( stricmp(tokens[1], "retx") == 0 ) {
3915                if ( stricmp(tokens[2], "enable") == 0 ||
3916                     stricmp(tokens[2], "on") == 0 ||
3917                     stricmp(tokens[2], "1") == 0 )
3918                    RETX_MODE_CFG->retx_en = 1;
3919                else if ( stricmp(tokens[2], "disable") == 0 ||
3920                     stricmp(tokens[2], "off") == 0 ||
3921                     stricmp(tokens[2], "0") == 0 )
3922                    RETX_MODE_CFG->retx_en = 0;
3923                printk("RETX_MODE_CFG->retx_en - %d\n", RETX_MODE_CFG->retx_en);
3924            }
3925            else {
3926                unsigned int dec_val, hex_val;
3927
3928                p1 = tokens[2];
3929                dec_val = (unsigned int)get_number(&p1, NULL, 0);
3930                p2 = tokens[2];
3931                hex_val = (unsigned int)get_number(&p2, NULL, 1);
3932
3933                if ( *p2 == 0 ) {
3934                    if ( stricmp(tokens[1], "service_header") == 0 ) {
3935                        *RETX_SERVICE_HEADER_CFG = hex_val;
3936                        printk("RETX_SERVICE_HEADER_CFG - 0x%08x\n", *RETX_SERVICE_HEADER_CFG);
3937                    }
3938                    else if ( stricmp(tokens[1], "service_mask") == 0 ) {
3939                        *RETX_MASK_HEADER_CFG = hex_val;
3940                        printk("RETX_MASK_HEADER_CFG - 0x%08x\n", *RETX_MASK_HEADER_CFG);
3941                    }
3942                }
3943                if ( *p1 == 0 ) {
3944                    if ( stricmp(tokens[1], "td_max") == 0 ) {
3945                        (unsigned int)RETX_TD_CFG->td_max = (dec_val >= 0xff ? 0Xff : dec_val);
3946                        printk("RETX_TD_CFG->td_max - %d\n", RETX_TD_CFG->td_max);
3947                    }
3948                    else if ( stricmp(tokens[1], "td_min") == 0 ) {
3949                        (unsigned int)RETX_TD_CFG->td_min = (dec_val >= 0xff ? 0Xff : dec_val);
3950                        printk("RETX_TD_CFG->td_min - %d\n", RETX_TD_CFG->td_min);
3951                    }
3952                    else if ( stricmp(tokens[1], "fw_alpha") == 0 ) {
3953                        RETX_TSYNC_CFG->fw_alpha = dec_val >= 0x7FFE ? 0X7EEE : dec_val;
3954                        printk("RETX_TSYNC_CFG->fw_alpha - %d\n", RETX_TSYNC_CFG->fw_alpha);
3955                    }
3956                    else if ( stricmp(tokens[1], "sync_inp") == 0 ) {
3957                        RETX_TSYNC_CFG->sync_inp = dec_val >= 0x7FFE ? 0X7EEE : dec_val;
3958                        printk("RETX_TSYNC_CFG->sync_inp - %d\n", RETX_TSYNC_CFG->sync_inp);
3959                    }
3960                    else if ( stricmp(tokens[1], "invld_range") == 0 ) {
3961                        RETX_MODE_CFG->invld_range = dec_val >= 250 ? 250 : dec_val;
3962                        printk("RETX_MODE_CFG->invld_range - %d\n", RETX_MODE_CFG->invld_range);
3963                    }
3964                    else if ( stricmp(tokens[1], "buff_size") == 0 ) {
3965                        dec_val = (dec_val + 31) / 32;
3966                        RETX_MODE_CFG->buff_size = dec_val >= 4096 / 32 ? 4096 / 32 : dec_val;
3967                        printk("RETX_MODE_CFG->buff_size - %d\n", RETX_MODE_CFG->buff_size);
3968                    }
3969                }
3970            }
3971
3972        }
3973    }
3974
3975    return count;
3976}
3977
3978static int proc_read_retx_dsl_param(char *page, char **start, off_t off, int count, int *eof, void *data)
3979{
3980    int len = 0;
3981
3982    len += sprintf(page + off + len, "DSL Param [timestamp %ld.%ld]:\n", g_retx_polling_start.tv_sec, g_retx_polling_start.tv_usec);
3983
3984    if ( g_xdata_addr == NULL )
3985        len += sprintf(page + off + len, " DSL parameters not available !\n");
3986    else {
3987        volatile struct dsl_param *p_dsl_param = (volatile struct dsl_param *)g_xdata_addr;
3988
3989        len += sprintf(page + off + len, " update_flag = %u\n", p_dsl_param->update_flag);
3990        len += sprintf(page + off + len, " MinDelayrt = %u\n", p_dsl_param->MinDelayrt);
3991        len += sprintf(page + off + len, " MaxDelayrt = %u\n", p_dsl_param->MaxDelayrt);
3992        len += sprintf(page + off + len, " RetxEnable = %u\n", p_dsl_param->RetxEnable);
3993        len += sprintf(page + off + len, " ServiceSpecificReTx = %u\n", p_dsl_param->ServiceSpecificReTx);
3994        len += sprintf(page + off + len, " ReTxPVC = 0x%08x\n", p_dsl_param->ReTxPVC);
3995        len += sprintf(page + off + len, " RxDtuCorruptedCNT = %u\n", p_dsl_param->RxDtuCorruptedCNT);
3996        len += sprintf(page + off + len, " RxRetxDtuUnCorrectedCNT = %u\n", p_dsl_param->RxRetxDtuUnCorrectedCNT);
3997        len += sprintf(page + off + len, " RxLastEFB = %u\n", p_dsl_param->RxLastEFB);
3998        len += sprintf(page + off + len, " RxDtuCorrectedCNT = %u\n", p_dsl_param->RxDtuCorrectedCNT);
3999    }
4000    if ( g_retx_polling_end.tv_sec != 0 || g_retx_polling_end.tv_usec != 0 ) {
4001        unsigned long polling_time_usec;
4002
4003        polling_time_usec = (g_retx_polling_end.tv_sec - g_retx_polling_start.tv_sec) * 1000000 + (g_retx_polling_end.tv_usec - g_retx_polling_start.tv_usec);
4004        len += sprintf(page + off + len, "DSL Param Update Time: %lu.%03lums\n", polling_time_usec / 1000, polling_time_usec % 1000);
4005    }
4006
4007    return len;
4008}
4009
4010 #endif
4011
4012#endif
4013
4014static int stricmp(const char *p1, const char *p2)
4015{
4016    int c1, c2;
4017
4018    while ( *p1 && *p2 ) {
4019        c1 = *p1 >= 'A' && *p1 <= 'Z' ? *p1 + 'a' - 'A' : *p1;
4020        c2 = *p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2;
4021        if ( (c1 -= c2) )
4022            return c1;
4023        p1++;
4024        p2++;
4025    }
4026
4027    return *p1 - *p2;
4028}
4029
4030#if defined(ENABLE_DBG_PROC) && ENABLE_DBG_PROC
4031
4032static int strincmp(const char *p1, const char *p2, int n)
4033{
4034    int c1 = 0, c2;
4035
4036    while ( n && *p1 && *p2 ) {
4037        c1 = *p1 >= 'A' && *p1 <= 'Z' ? *p1 + 'a' - 'A' : *p1;
4038        c2 = *p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2;
4039        if ( (c1 -= c2) )
4040            return c1;
4041        p1++;
4042        p2++;
4043        n--;
4044    }
4045
4046    return n ? *p1 - *p2 : c1;
4047}
4048
4049static int get_token(char **p1, char **p2, int *len, int *colon)
4050{
4051    int tlen = 0;
4052
4053    while ( *len && !((**p1 >= 'A' && **p1 <= 'Z') || (**p1 >= 'a' && **p1<= 'z') || (**p1 >= '0' && **p1<= '9')) )
4054    {
4055        (*p1)++;
4056        (*len)--;
4057    }
4058    if ( !*len )
4059        return 0;
4060
4061    if ( *colon )
4062    {
4063        *colon = 0;
4064        *p2 = *p1;
4065        while ( *len && **p2 > ' ' && **p2 != ',' )
4066        {
4067            if ( **p2 == ':' )
4068            {
4069                *colon = 1;
4070                break;
4071            }
4072            (*p2)++;
4073            (*len)--;
4074            tlen++;
4075        }
4076        **p2 = 0;
4077    }
4078    else
4079    {
4080        *p2 = *p1;
4081        while ( *len && **p2 > ' ' && **p2 != ',' )
4082        {
4083            (*p2)++;
4084            (*len)--;
4085            tlen++;
4086        }
4087        **p2 = 0;
4088    }
4089
4090    return tlen;
4091}
4092
4093static unsigned int get_number(char **p, int *len, int is_hex)
4094{
4095    unsigned int ret = 0;
4096    unsigned int n = 0;
4097
4098    if ( (*p)[0] == '0' && (*p)[1] == 'x' )
4099    {
4100        is_hex = 1;
4101        (*p) += 2;
4102        if ( len )
4103            (*len) -= 2;
4104    }
4105
4106    if ( is_hex )
4107    {
4108        while ( (!len || *len) && ((**p >= '0' && **p <= '9') || (**p >= 'a' && **p <= 'f') || (**p >= 'A' && **p <= 'F')) )
4109        {
4110            if ( **p >= '0' && **p <= '9' )
4111                n = **p - '0';
4112            else if ( **p >= 'a' && **p <= 'f' )
4113               n = **p - 'a' + 10;
4114            else if ( **p >= 'A' && **p <= 'F' )
4115                n = **p - 'A' + 10;
4116            ret = (ret << 4) | n;
4117            (*p)++;
4118            if ( len )
4119                (*len)--;
4120        }
4121    }
4122    else
4123    {
4124        while ( (!len || *len) && **p >= '0' && **p <= '9' )
4125        {
4126            n = **p - '0';
4127            ret = ret * 10 + n;
4128            (*p)++;
4129            if ( len )
4130                (*len)--;
4131        }
4132    }
4133
4134    return ret;
4135}
4136
4137static void ignore_space(char **p, int *len)
4138{
4139    while ( *len && (**p <= ' ' || **p == ':' || **p == '.' || **p == ',') )
4140    {
4141        (*p)++;
4142        (*len)--;
4143    }
4144}
4145
4146#endif
4147
4148static INLINE int ifx_atm_version(char *buf)
4149{
4150    int len = 0;
4151    unsigned int major, minor;
4152
4153    ifx_atm_get_fw_ver(&major, &minor);
4154
4155    len += sprintf(buf + len, " ATM (A1) firmware version %d.%d.%d\n", IFX_ATM_VER_MAJOR, IFX_ATM_VER_MID,IFX_ATM_VER_MINOR);
4156
4157    return len;
4158}
4159
4160static INLINE void check_parameters(void)
4161{
4162    /* Please refer to Amazon spec 15.4 for setting these values. */
4163    if ( qsb_tau < 1 )
4164        qsb_tau = 1;
4165    if ( qsb_tstep < 1 )
4166        qsb_tstep = 1;
4167    else if ( qsb_tstep > 4 )
4168        qsb_tstep = 4;
4169    else if ( qsb_tstep == 3 )
4170        qsb_tstep = 2;
4171
4172    /* There is a delay between PPE write descriptor and descriptor is */
4173    /* really stored in memory. Host also has this delay when writing */
4174    /* descriptor. So PPE will use this value to determine if the write */
4175    /* operation makes effect. */
4176    if ( write_descriptor_delay < 0 )
4177        write_descriptor_delay = 0;
4178
4179    if ( aal5_fill_pattern < 0 )
4180        aal5_fill_pattern = 0;
4181    else
4182        aal5_fill_pattern &= 0xFF;
4183
4184    /* Because of the limitation of length field in descriptors, the packet */
4185    /* size could not be larger than 64K minus overhead size. */
4186    if ( aal5r_max_packet_size < 0 )
4187        aal5r_max_packet_size = 0;
4188    else if ( aal5r_max_packet_size >= 65535 - MAX_RX_FRAME_EXTRA_BYTES )
4189        aal5r_max_packet_size = 65535 - MAX_RX_FRAME_EXTRA_BYTES;
4190    if ( aal5r_min_packet_size < 0 )
4191        aal5r_min_packet_size = 0;
4192    else if ( aal5r_min_packet_size > aal5r_max_packet_size )
4193        aal5r_min_packet_size = aal5r_max_packet_size;
4194    if ( aal5s_max_packet_size < 0 )
4195        aal5s_max_packet_size = 0;
4196    else if ( aal5s_max_packet_size >= 65535 - MAX_TX_FRAME_EXTRA_BYTES )
4197        aal5s_max_packet_size = 65535 - MAX_TX_FRAME_EXTRA_BYTES;
4198    if ( aal5s_min_packet_size < 0 )
4199        aal5s_min_packet_size = 0;
4200    else if ( aal5s_min_packet_size > aal5s_max_packet_size )
4201        aal5s_min_packet_size = aal5s_max_packet_size;
4202
4203    if ( dma_rx_descriptor_length < 2 )
4204        dma_rx_descriptor_length = 2;
4205    if ( dma_tx_descriptor_length < 2 )
4206        dma_tx_descriptor_length = 2;
4207    if ( dma_rx_clp1_descriptor_threshold < 0 )
4208        dma_rx_clp1_descriptor_threshold = 0;
4209    else if ( dma_rx_clp1_descriptor_threshold > dma_rx_descriptor_length )
4210        dma_rx_clp1_descriptor_threshold = dma_rx_descriptor_length;
4211
4212    if ( dma_tx_descriptor_length < 2 )
4213        dma_tx_descriptor_length = 2;
4214}
4215
4216static INLINE int init_priv_data(void)
4217{
4218    void *p;
4219    int i;
4220    struct rx_descriptor rx_desc = {0};
4221    struct sk_buff *skb;
4222    volatile struct tx_descriptor *p_tx_desc;
4223    struct sk_buff **ppskb;
4224
4225    // clear atm private data structure
4226    memset(&g_atm_priv_data, 0, sizeof(g_atm_priv_data));
4227
4228    // allocate memory for RX (AAL) descriptors
4229    p = kzalloc(dma_rx_descriptor_length * sizeof(struct rx_descriptor) + DESC_ALIGNMENT, GFP_KERNEL);
4230    if ( p == NULL )
4231        return IFX_ERROR;
4232    dma_cache_wback_inv((unsigned long)p, dma_rx_descriptor_length * sizeof(struct rx_descriptor) + DESC_ALIGNMENT);
4233    g_atm_priv_data.aal_desc_base = p;
4234    p = (void *)((((unsigned int)p + DESC_ALIGNMENT - 1) & ~(DESC_ALIGNMENT - 1)) | KSEG1);
4235    g_atm_priv_data.aal_desc = (volatile struct rx_descriptor *)p;
4236
4237    // allocate memory for RX (OAM) descriptors
4238    p = kzalloc(RX_DMA_CH_OAM_DESC_LEN * sizeof(struct rx_descriptor) + DESC_ALIGNMENT, GFP_KERNEL);
4239    if ( p == NULL )
4240        return IFX_ERROR;
4241    dma_cache_wback_inv((unsigned long)p, RX_DMA_CH_OAM_DESC_LEN * sizeof(struct rx_descriptor) + DESC_ALIGNMENT);
4242    g_atm_priv_data.oam_desc_base = p;
4243    p = (void *)((((unsigned int)p + DESC_ALIGNMENT - 1) & ~(DESC_ALIGNMENT - 1)) | KSEG1);
4244    g_atm_priv_data.oam_desc = (volatile struct rx_descriptor *)p;
4245
4246    // allocate memory for RX (OAM) buffer
4247    p = kzalloc(RX_DMA_CH_OAM_DESC_LEN * RX_DMA_CH_OAM_BUF_SIZE + DATA_BUFFER_ALIGNMENT, GFP_KERNEL);
4248    if ( p == NULL )
4249        return IFX_ERROR;
4250    dma_cache_wback_inv((unsigned long)p, RX_DMA_CH_OAM_DESC_LEN * RX_DMA_CH_OAM_BUF_SIZE + DATA_BUFFER_ALIGNMENT);
4251    g_atm_priv_data.oam_buf_base = p;
4252    p = (void *)(((unsigned int)p + DATA_BUFFER_ALIGNMENT - 1) & ~(DATA_BUFFER_ALIGNMENT - 1));
4253    g_atm_priv_data.oam_buf = p;
4254
4255    // allocate memory for TX descriptors
4256    p = kzalloc(MAX_PVC_NUMBER * dma_tx_descriptor_length * sizeof(struct tx_descriptor) + DESC_ALIGNMENT, GFP_KERNEL);
4257    if ( p == NULL )
4258        return IFX_ERROR;
4259    dma_cache_wback_inv((unsigned long)p, MAX_PVC_NUMBER * dma_tx_descriptor_length * sizeof(struct tx_descriptor) + DESC_ALIGNMENT);
4260    g_atm_priv_data.tx_desc_base = p;
4261
4262    // allocate memory for TX skb pointers
4263    p = kzalloc(MAX_PVC_NUMBER * dma_tx_descriptor_length * sizeof(struct sk_buff *) + 4, GFP_KERNEL);
4264    if ( p == NULL )
4265        return IFX_ERROR;
4266    dma_cache_wback_inv((unsigned long)p, MAX_PVC_NUMBER * dma_tx_descriptor_length * sizeof(struct sk_buff *) + 4);
4267    g_atm_priv_data.tx_skb_base = p;
4268
4269    // setup RX (AAL) descriptors
4270    rx_desc.own = 1;
4271    rx_desc.c = 0;
4272    rx_desc.sop = 1;
4273    rx_desc.eop = 1;
4274    rx_desc.byteoff = 0;
4275    rx_desc.id = 0;
4276    rx_desc.err = 0;
4277    rx_desc.datalen = RX_DMA_CH_AAL_BUF_SIZE;
4278    for ( i = 0; i < dma_rx_descriptor_length; i++ ) {
4279        skb = alloc_skb_rx();
4280        if ( skb == NULL )
4281            return IFX_ERROR;
4282        rx_desc.dataptr = ((unsigned int)skb->data >> 2) & 0x0FFFFFFF;
4283        g_atm_priv_data.aal_desc[i] = rx_desc;
4284    }
4285
4286    // setup RX (OAM) descriptors
4287    p = (void *)((unsigned int)g_atm_priv_data.oam_buf | KSEG1);
4288    rx_desc.own = 1;
4289    rx_desc.c = 0;
4290    rx_desc.sop = 1;
4291    rx_desc.eop = 1;
4292    rx_desc.byteoff = 0;
4293    rx_desc.id = 0;
4294    rx_desc.err = 0;
4295    rx_desc.datalen = RX_DMA_CH_OAM_BUF_SIZE;
4296    for ( i = 0; i < RX_DMA_CH_OAM_DESC_LEN; i++ ) {
4297        rx_desc.dataptr = ((unsigned int)p >> 2) & 0x0FFFFFFF;
4298        g_atm_priv_data.oam_desc[i] = rx_desc;
4299        p = (void *)((unsigned int)p + RX_DMA_CH_OAM_BUF_SIZE);
4300    }
4301
4302    // setup TX descriptors and skb pointers
4303    p_tx_desc = (volatile struct tx_descriptor *)((((unsigned int)g_atm_priv_data.tx_desc_base + DESC_ALIGNMENT - 1) & ~(DESC_ALIGNMENT - 1)) | KSEG1);
4304    ppskb = (struct sk_buff **)(((unsigned int)g_atm_priv_data.tx_skb_base + 3) & ~3);
4305    for ( i = 0; i < MAX_PVC_NUMBER; i++ ) {
4306        g_atm_priv_data.conn[i].tx_desc = &p_tx_desc[i * dma_tx_descriptor_length];
4307        g_atm_priv_data.conn[i].tx_skb = &ppskb[i * dma_tx_descriptor_length];
4308    }
4309
4310    for ( i = 0; i < ATM_PORT_NUMBER; i++ )
4311        g_atm_priv_data.port[i].tx_max_cell_rate = DEFAULT_TX_LINK_RATE;
4312
4313    return IFX_SUCCESS;
4314}
4315
4316static INLINE void clear_priv_data(void)
4317{
4318    int i, j;
4319    struct sk_buff *skb;
4320
4321    for ( i = 0; i < MAX_PVC_NUMBER; i++ ) {
4322        if ( g_atm_priv_data.conn[i].tx_skb != NULL ) {
4323            for ( j = 0; j < dma_tx_descriptor_length; j++ )
4324                if ( g_atm_priv_data.conn[i].tx_skb[j] != NULL )
4325                    dev_kfree_skb_any(g_atm_priv_data.conn[i].tx_skb[j]);
4326        }
4327    }
4328
4329    if ( g_atm_priv_data.tx_skb_base != NULL )
4330        kfree(g_atm_priv_data.tx_skb_base);
4331
4332    if ( g_atm_priv_data.tx_desc_base != NULL )
4333        kfree(g_atm_priv_data.tx_desc_base);
4334
4335    if ( g_atm_priv_data.oam_buf_base != NULL )
4336        kfree(g_atm_priv_data.oam_buf_base);
4337
4338    if ( g_atm_priv_data.oam_desc_base != NULL )
4339        kfree(g_atm_priv_data.oam_desc_base);
4340
4341    if ( g_atm_priv_data.aal_desc_base != NULL ) {
4342        for ( i = 0; i < dma_rx_descriptor_length; i++ ) {
4343            if ( g_atm_priv_data.aal_desc[i].sop || g_atm_priv_data.aal_desc[i].eop ) { // descriptor initialized
4344                skb = get_skb_rx_pointer(g_atm_priv_data.aal_desc[i].dataptr);
4345                dev_kfree_skb_any(skb);
4346            }
4347        }
4348        kfree(g_atm_priv_data.aal_desc_base);
4349    }
4350}
4351
4352static INLINE void init_rx_tables(void)
4353{
4354    int i;
4355    struct wrx_queue_config wrx_queue_config = {0};
4356    struct wrx_dma_channel_config wrx_dma_channel_config = {0};
4357    struct htu_entry htu_entry = {0};
4358    struct htu_result htu_result = {0};
4359    struct htu_mask htu_mask = { set: 0x01,
4360                                    clp: 0x01,
4361                                    pid_mask: 0x00,
4362                                    vpi_mask: 0x00,
4363                                    vci_mask: 0x00,
4364                                    pti_mask: 0x00,
4365                                    clear: 0x00};
4366
4367    /*
4368     * General Registers
4369     */
4370    *CFG_WRX_HTUTS = MAX_PVC_NUMBER + OAM_HTU_ENTRY_NUMBER;
4371#ifndef CONFIG_AMAZON_SE
4372    *CFG_WRX_QNUM = MAX_QUEUE_NUMBER;
4373#endif
4374    *CFG_WRX_DCHNUM = RX_DMA_CH_TOTAL;
4375    *WRX_DMACH_ON = (1 << RX_DMA_CH_TOTAL) - 1;
4376    *WRX_HUNT_BITTH = DEFAULT_RX_HUNT_BITTH;
4377
4378    /*
4379     * WRX Queue Configuration Table
4380     */
4381    wrx_queue_config.uumask = 0;
4382    wrx_queue_config.cpimask = 0;
4383    wrx_queue_config.uuexp = 0;
4384    wrx_queue_config.cpiexp = 0;
4385    wrx_queue_config.mfs = aal5r_max_packet_size;
4386    wrx_queue_config.oversize = aal5r_max_packet_size;
4387    wrx_queue_config.undersize = aal5r_min_packet_size;
4388    wrx_queue_config.errdp = aal5r_drop_error_packet;
4389    wrx_queue_config.dmach = RX_DMA_CH_AAL;
4390    for ( i = 0; i < MAX_QUEUE_NUMBER; i++ )
4391        *WRX_QUEUE_CONFIG(i) = wrx_queue_config;
4392    WRX_QUEUE_CONFIG(OAM_RX_QUEUE)->dmach = RX_DMA_CH_OAM;
4393
4394    /*
4395     * WRX DMA Channel Configuration Table
4396     */
4397    wrx_dma_channel_config.chrl = 0;
4398    wrx_dma_channel_config.clp1th = dma_rx_clp1_descriptor_threshold;
4399    wrx_dma_channel_config.mode = 0;
4400    wrx_dma_channel_config.rlcfg = 0;
4401
4402    wrx_dma_channel_config.deslen = RX_DMA_CH_OAM_DESC_LEN;
4403    wrx_dma_channel_config.desba = ((unsigned int)g_atm_priv_data.oam_desc >> 2) & 0x0FFFFFFF;
4404    *WRX_DMA_CHANNEL_CONFIG(RX_DMA_CH_OAM) = wrx_dma_channel_config;
4405
4406    wrx_dma_channel_config.deslen = dma_rx_descriptor_length;
4407    wrx_dma_channel_config.desba = ((unsigned int)g_atm_priv_data.aal_desc >> 2) & 0x0FFFFFFF;
4408    *WRX_DMA_CHANNEL_CONFIG(RX_DMA_CH_AAL) = wrx_dma_channel_config;
4409
4410    /*
4411     * HTU Tables
4412     */
4413    for ( i = 0; i < MAX_PVC_NUMBER; i++ )
4414    {
4415        htu_result.qid = (unsigned int)i;
4416
4417        *HTU_ENTRY(i + OAM_HTU_ENTRY_NUMBER) = htu_entry;
4418        *HTU_MASK(i + OAM_HTU_ENTRY_NUMBER) = htu_mask;
4419        *HTU_RESULT(i + OAM_HTU_ENTRY_NUMBER) = htu_result;
4420    }
4421    /* OAM HTU Entry */
4422    htu_entry.vci = 0x03;
4423    htu_mask.pid_mask = 0x03;
4424    htu_mask.vpi_mask = 0xFF;
4425    htu_mask.vci_mask = 0x0000;
4426    htu_mask.pti_mask = 0x07;
4427    htu_result.cellid = OAM_RX_QUEUE;
4428    htu_result.type = 1;
4429    htu_result.ven = 1;
4430    htu_result.qid = OAM_RX_QUEUE;
4431    *HTU_RESULT(OAM_F4_SEG_HTU_ENTRY) = htu_result;
4432    *HTU_MASK(OAM_F4_SEG_HTU_ENTRY) = htu_mask;
4433    *HTU_ENTRY(OAM_F4_SEG_HTU_ENTRY) = htu_entry;
4434    htu_entry.vci = 0x04;
4435    htu_result.cellid = OAM_RX_QUEUE;
4436    htu_result.type = 1;
4437    htu_result.ven = 1;
4438    htu_result.qid = OAM_RX_QUEUE;
4439    *HTU_RESULT(OAM_F4_TOT_HTU_ENTRY) = htu_result;
4440    *HTU_MASK(OAM_F4_TOT_HTU_ENTRY) = htu_mask;
4441    *HTU_ENTRY(OAM_F4_TOT_HTU_ENTRY) = htu_entry;
4442    htu_entry.vci = 0x00;
4443    htu_entry.pti = 0x04;
4444    htu_mask.vci_mask = 0xFFFF;
4445    htu_mask.pti_mask = 0x01;
4446    htu_result.cellid = OAM_RX_QUEUE;
4447    htu_result.type = 1;
4448    htu_result.ven = 1;
4449    htu_result.qid = OAM_RX_QUEUE;
4450    *HTU_RESULT(OAM_F5_HTU_ENTRY) = htu_result;
4451    *HTU_MASK(OAM_F5_HTU_ENTRY) = htu_mask;
4452    *HTU_ENTRY(OAM_F5_HTU_ENTRY) = htu_entry;
4453#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
4454    htu_entry.pid = 0x0;
4455    htu_entry.vpi = 0x01;
4456    htu_entry.vci = 0x0001;
4457    htu_entry.pti = 0x00;
4458    htu_mask.pid_mask = 0x0;
4459    htu_mask.vpi_mask = 0x00;
4460    htu_mask.vci_mask = 0x0000;
4461    htu_mask.pti_mask = 0x3;
4462    htu_result.cellid = OAM_RX_QUEUE;
4463    htu_result.type = 1;
4464    htu_result.ven = 1;
4465    htu_result.qid = OAM_RX_QUEUE;
4466    *HTU_RESULT(OAM_ARQ_HTU_ENTRY) = htu_result;
4467    *HTU_MASK(OAM_ARQ_HTU_ENTRY) = htu_mask;
4468    *HTU_ENTRY(OAM_ARQ_HTU_ENTRY) = htu_entry;
4469#endif
4470}
4471
4472static INLINE void init_tx_tables(void)
4473{
4474    int i;
4475    struct wtx_queue_config wtx_queue_config = {0};
4476    struct wtx_dma_channel_config wtx_dma_channel_config = {0};
4477    struct wtx_port_config wtx_port_config = { res1: 0,
4478                                                qid: 0,
4479                                                qsben: 1};
4480
4481    /*
4482     * General Registers
4483     */
4484    *CFG_WTX_DCHNUM = MAX_TX_DMA_CHANNEL_NUMBER;
4485    *WTX_DMACH_ON = ((1 << MAX_TX_DMA_CHANNEL_NUMBER) - 1) ^ ((1 << FIRST_QSB_QID) - 1);
4486    *CFG_WRDES_DELAY = write_descriptor_delay;
4487
4488    /*
4489     * WTX Port Configuration Table
4490     */
4491    for ( i = 0; i < ATM_PORT_NUMBER; i++ )
4492        *WTX_PORT_CONFIG(i) = wtx_port_config;
4493
4494    /*
4495     * WTX Queue Configuration Table
4496     */
4497    wtx_queue_config.qsben = 1;
4498    wtx_queue_config.sbid = 0;
4499    for ( i = 0; i < MAX_TX_DMA_CHANNEL_NUMBER; i++ ) {
4500        wtx_queue_config.qsb_vcid = i;
4501        *WTX_QUEUE_CONFIG(i) = wtx_queue_config;
4502    }
4503
4504    /*
4505     * WTX DMA Channel Configuration Table
4506     */
4507    wtx_dma_channel_config.mode = 0;
4508    wtx_dma_channel_config.deslen = 0;
4509    wtx_dma_channel_config.desba = 0;
4510    for ( i = 0; i < FIRST_QSB_QID; i++ )
4511        *WTX_DMA_CHANNEL_CONFIG(i) = wtx_dma_channel_config;
4512    /* normal connection */
4513    wtx_dma_channel_config.deslen = dma_tx_descriptor_length;
4514    for ( ; i < MAX_TX_DMA_CHANNEL_NUMBER ; i++ ) {
4515        wtx_dma_channel_config.desba = ((unsigned int)g_atm_priv_data.conn[i - FIRST_QSB_QID].tx_desc >> 2) & 0x0FFFFFFF;
4516        *WTX_DMA_CHANNEL_CONFIG(i) = wtx_dma_channel_config;
4517    }
4518}
4519
4520
4521
4522/*
4523 * ####################################
4524 * Global Function
4525 * ####################################
4526 */
4527
4528static int atm_showtime_enter(struct port_cell_info *port_cell, void *xdata_addr)
4529{
4530    int i, j;
4531
4532    ASSERT(port_cell != NULL, "port_cell is NULL");
4533    ASSERT(xdata_addr != NULL, "xdata_addr is NULL");
4534
4535    for ( j = 0; j < ATM_PORT_NUMBER && j < port_cell->port_num; j++ )
4536        if ( port_cell->tx_link_rate[j] > 0 )
4537            break;
4538    for ( i = 0; i < ATM_PORT_NUMBER && i < port_cell->port_num; i++ )
4539        g_atm_priv_data.port[i].tx_max_cell_rate = port_cell->tx_link_rate[i] > 0 ? port_cell->tx_link_rate[i] : port_cell->tx_link_rate[j];
4540
4541    qsb_global_set();
4542
4543    for ( i = 0; i < MAX_PVC_NUMBER; i++ )
4544        if ( g_atm_priv_data.conn[i].vcc != NULL )
4545            set_qsb(g_atm_priv_data.conn[i].vcc, &g_atm_priv_data.conn[i].vcc->qos, i);
4546
4547    // TODO: ReTX set xdata_addr
4548    g_xdata_addr = xdata_addr;
4549
4550    g_showtime = 1;
4551
4552#if defined(CONFIG_VR9)
4553    IFX_REG_W32(0x0F, UTP_CFG);
4554#endif
4555
4556#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
4557    if ( !timer_pending(&g_retx_polling_timer) ) {
4558        g_retx_polling_cnt = HZ;
4559        g_retx_polling_timer.expires = jiffies + RETX_POLLING_INTERVAL;
4560        add_timer(&g_retx_polling_timer);
4561    }
4562#endif
4563
4564    //printk("enter showtime, cell rate: 0 - %d, 1 - %d, xdata addr: 0x%08x\n", g_atm_priv_data.port[0].tx_max_cell_rate, g_atm_priv_data.port[1].tx_max_cell_rate, (unsigned int)g_xdata_addr);
4565
4566    return IFX_SUCCESS;
4567}
4568
4569static int atm_showtime_exit(void)
4570{
4571    if ( !g_showtime )
4572        return IFX_ERROR;
4573
4574#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
4575    RETX_MODE_CFG->retx_en = 0; // disable ReTX
4576    del_timer(&g_retx_polling_timer);
4577#endif
4578
4579#if defined(CONFIG_VR9)
4580    IFX_REG_W32(0x00, UTP_CFG);
4581#endif
4582
4583    g_showtime = 0;
4584
4585    // TODO: ReTX clean state
4586    g_xdata_addr = NULL;
4587
4588    printk("leave showtime\n");
4589
4590    return IFX_SUCCESS;
4591}
4592
4593
4594
4595/*
4596 * ####################################
4597 * Init/Cleanup API
4598 * ####################################
4599 */
4600
4601/*
4602 * Description:
4603 * Initialize global variables, PP32, comunication structures, register IRQ
4604 * and register device.
4605 * Input:
4606 * none
4607 * Output:
4608 * 0 --- successful
4609 * else --- failure, usually it is negative value of error code
4610 */
4611static int __devinit ifx_atm_init(void)
4612{
4613    int ret;
4614    int port_num;
4615    struct port_cell_info port_cell = {0};
4616    int i, j;
4617    char ver_str[256];
4618
4619    check_parameters();
4620
4621    ret = init_priv_data();
4622    if ( ret != IFX_SUCCESS ) {
4623        err("INIT_PRIV_DATA_FAIL");
4624        goto INIT_PRIV_DATA_FAIL;
4625    }
4626
4627    ifx_atm_init_chip();
4628    init_rx_tables();
4629    init_tx_tables();
4630
4631    /* create devices */
4632    for ( port_num = 0; port_num < ATM_PORT_NUMBER; port_num++ ) {
4633#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
4634    g_atm_priv_data.port[port_num].dev = atm_dev_register("ifxmips_atm", &g_ifx_atm_ops, -1, NULL);
4635#else
4636    g_atm_priv_data.port[port_num].dev = atm_dev_register("ifxmips_atm", NULL, &g_ifx_atm_ops, -1, NULL);
4637#endif
4638
4639        if ( !g_atm_priv_data.port[port_num].dev ) {
4640            err("failed to register atm device %d!", port_num);
4641            ret = -EIO;
4642            goto ATM_DEV_REGISTER_FAIL;
4643        }
4644        else {
4645            g_atm_priv_data.port[port_num].dev->ci_range.vpi_bits = 8;
4646            g_atm_priv_data.port[port_num].dev->ci_range.vci_bits = 16;
4647            g_atm_priv_data.port[port_num].dev->link_rate = g_atm_priv_data.port[port_num].tx_max_cell_rate;
4648            g_atm_priv_data.port[port_num].dev->dev_data = (void*)port_num;
4649        }
4650    }
4651
4652    /* register interrupt handler */
4653    ret = request_irq(PPE_MAILBOX_IGU1_INT, mailbox_irq_handler, IRQF_DISABLED, "atm_mailbox_isr", &g_atm_priv_data);
4654    if ( ret ) {
4655        if ( ret == -EBUSY ) {
4656            err("IRQ may be occupied by other driver, please reconfig to disable it.");
4657        }
4658        else {
4659            err("request_irq fail");
4660        }
4661        goto REQUEST_IRQ_PPE_MAILBOX_IGU1_INT_FAIL;
4662    }
4663    disable_irq(PPE_MAILBOX_IGU1_INT);
4664
4665#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
4666    init_atm_tc_retrans_param();
4667
4668    init_timer(&g_retx_polling_timer);
4669    g_retx_polling_timer.function = retx_polling_func;
4670#endif
4671
4672    ret = ifx_pp32_start(0);
4673    if ( ret ) {
4674        err("ifx_pp32_start fail!");
4675        goto PP32_START_FAIL;
4676    }
4677
4678    port_cell.port_num = ATM_PORT_NUMBER;
4679    if( !IS_ERR(&ifx_mei_atm_showtime_check) && &ifx_mei_atm_showtime_check)
4680        ifx_mei_atm_showtime_check(&g_showtime, &port_cell, &g_xdata_addr);
4681    if ( g_showtime ) {
4682        for ( i = 0; i < ATM_PORT_NUMBER; i++ )
4683            if ( port_cell.tx_link_rate[i] != 0 )
4684                break;
4685        for ( j = 0; j < ATM_PORT_NUMBER; j++ )
4686            g_atm_priv_data.port[j].tx_max_cell_rate = port_cell.tx_link_rate[j] != 0 ? port_cell.tx_link_rate[j] : port_cell.tx_link_rate[i];
4687    }
4688
4689    qsb_global_set();
4690    validate_oam_htu_entry();
4691
4692#if 0 /*defined(ENABLE_LED_FRAMEWORK) && ENABLE_LED_FRAMEWORK*/
4693    ifx_led_trigger_register("dsl_data", &g_data_led_trigger);
4694#endif
4695
4696    /* create proc file */
4697    proc_file_create();
4698
4699    if( !IS_ERR(&ifx_mei_atm_showtime_enter) && &ifx_mei_atm_showtime_enter )
4700        ifx_mei_atm_showtime_enter = atm_showtime_enter;
4701
4702    if( !IS_ERR(&ifx_mei_atm_showtime_exit) && !ifx_mei_atm_showtime_exit )
4703        ifx_mei_atm_showtime_exit = atm_showtime_exit;
4704
4705    ifx_atm_version(ver_str);
4706    printk(KERN_INFO "%s", ver_str);
4707
4708    printk("ifxmips_atm: ATM init succeed\n");
4709
4710    return IFX_SUCCESS;
4711
4712PP32_START_FAIL:
4713    free_irq(PPE_MAILBOX_IGU1_INT, &g_atm_priv_data);
4714REQUEST_IRQ_PPE_MAILBOX_IGU1_INT_FAIL:
4715ATM_DEV_REGISTER_FAIL:
4716    while ( port_num-- > 0 )
4717        atm_dev_deregister(g_atm_priv_data.port[port_num].dev);
4718INIT_PRIV_DATA_FAIL:
4719    clear_priv_data();
4720    printk("ifxmips_atm: ATM init failed\n");
4721    return ret;
4722}
4723
4724/*
4725 * Description:
4726 * Release memory, free IRQ, and deregister device.
4727 * Input:
4728 * none
4729 * Output:
4730 * none
4731 */
4732static void __exit ifx_atm_exit(void)
4733{
4734    int port_num;
4735
4736    if( !IS_ERR(&ifx_mei_atm_showtime_enter) && &ifx_mei_atm_showtime_enter )
4737        ifx_mei_atm_showtime_enter = NULL;
4738    if( !IS_ERR(&ifx_mei_atm_showtime_exit) && !ifx_mei_atm_showtime_exit )
4739        ifx_mei_atm_showtime_exit = NULL;
4740
4741    proc_file_delete();
4742
4743#if 0 /*defined(ENABLE_LED_FRAMEWORK) && ENABLE_LED_FRAMEWORK*/
4744    ifx_led_trigger_deregister(g_data_led_trigger);
4745    g_data_led_trigger = NULL;
4746#endif
4747
4748    invalidate_oam_htu_entry();
4749
4750    ifx_pp32_stop(0);
4751
4752#if defined(ENABLE_ATM_RETX) && ENABLE_ATM_RETX
4753    del_timer(&g_retx_polling_timer);
4754    clear_atm_tc_retrans_param();
4755#endif
4756
4757    free_irq(PPE_MAILBOX_IGU1_INT, &g_atm_priv_data);
4758
4759    for ( port_num = 0; port_num < ATM_PORT_NUMBER; port_num++ )
4760        atm_dev_deregister(g_atm_priv_data.port[port_num].dev);
4761
4762    ifx_atm_uninit_chip();
4763
4764    clear_priv_data();
4765}
4766
4767module_init(ifx_atm_init);
4768module_exit(ifx_atm_exit);
4769MODULE_LICENSE("Dual BSD/GPL");
4770

Archive Download this file



interactive