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

Archive Download this file



interactive