lantiq: ltq-ptm: set carrier status
[librecmc/librecmc.git] / package / kernel / lantiq / ltq-ptm / src / ifxmips_ptm_vdsl.c
1 /******************************************************************************
2 **
3 ** FILE NAME    : ifxmips_ptm_vdsl.c
4 ** PROJECT      : UEIP
5 ** MODULES      : PTM
6 **
7 ** DATE         : 7 Jul 2009
8 ** AUTHOR       : Xu Liang
9 ** DESCRIPTION  : PTM driver common source file (core functions for VR9)
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 #include <linux/version.h>
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/types.h>
28 #include <linux/ctype.h>
29 #include <linux/errno.h>
30 #include <linux/proc_fs.h>
31 #include <linux/init.h>
32 #include <linux/ioctl.h>
33 #include <linux/etherdevice.h>
34 #include <linux/interrupt.h>
35 #include <linux/netdevice.h>
36
37 #include "ifxmips_ptm_vdsl.h"
38 #include <lantiq_soc.h>
39
40 #define MODULE_PARM_ARRAY(a, b)   module_param_array(a, int, NULL, 0)
41 #define MODULE_PARM(a, b)         module_param(a, int, 0)
42
43 static int wanqos_en = 0;
44 static int queue_gamma_map[4] = {0xFE, 0x01, 0x00, 0x00};
45
46 MODULE_PARM(wanqos_en, "i");
47 MODULE_PARM_DESC(wanqos_en, "WAN QoS support, 1 - enabled, 0 - disabled.");
48
49 MODULE_PARM_ARRAY(queue_gamma_map, "4-4i");
50 MODULE_PARM_DESC(queue_gamma_map, "TX QoS queues mapping to 4 TX Gamma interfaces.");
51
52 extern int (*ifx_mei_atm_showtime_enter)(struct port_cell_info *, void *);
53 extern int (*ifx_mei_atm_showtime_exit)(void);
54 extern int ifx_mei_atm_showtime_check(int *is_showtime, struct port_cell_info *port_cell, void **xdata_addr);
55
56 static int g_showtime = 0;
57 static void *g_xdata_addr = NULL;
58
59
60 #define ENABLE_TMP_DBG                          0
61
62 unsigned long cgu_get_pp32_clock(void)
63 {
64         struct clk *c = clk_get_ppe();
65         unsigned long rate = clk_get_rate(c);
66         clk_put(c);
67         return rate;
68 }
69
70 static void ptm_setup(struct net_device *, int);
71 static struct net_device_stats *ptm_get_stats(struct net_device *);
72 static int ptm_open(struct net_device *);
73 static int ptm_stop(struct net_device *);
74   static unsigned int ptm_poll(int, unsigned int);
75   static int ptm_napi_poll(struct napi_struct *, int);
76 static int ptm_hard_start_xmit(struct sk_buff *, struct net_device *);
77 static int ptm_ioctl(struct net_device *, struct ifreq *, int);
78 static void ptm_tx_timeout(struct net_device *);
79
80 static inline struct sk_buff* alloc_skb_rx(void);
81 static inline struct sk_buff* alloc_skb_tx(unsigned int);
82 static inline struct sk_buff *get_skb_pointer(unsigned int);
83 static inline int get_tx_desc(unsigned int, unsigned int *);
84
85 /*
86  *  Mailbox handler and signal function
87  */
88 static irqreturn_t mailbox_irq_handler(int, void *);
89
90 /*
91  *  Tasklet to Handle Swap Descriptors
92  */
93 static void do_swap_desc_tasklet(unsigned long);
94
95
96 /*
97  *  Init & clean-up functions
98  */
99 static inline int init_priv_data(void);
100 static inline void clear_priv_data(void);
101 static inline int init_tables(void);
102 static inline void clear_tables(void);
103
104 static int g_wanqos_en = 0;
105
106 static int g_queue_gamma_map[4];
107
108 static struct ptm_priv_data g_ptm_priv_data;
109
110 static struct net_device_ops g_ptm_netdev_ops = {
111     .ndo_get_stats       = ptm_get_stats,
112     .ndo_open            = ptm_open,
113     .ndo_stop            = ptm_stop,
114     .ndo_start_xmit      = ptm_hard_start_xmit,
115     .ndo_validate_addr   = eth_validate_addr,
116     .ndo_set_mac_address = eth_mac_addr,
117     .ndo_change_mtu      = eth_change_mtu,
118     .ndo_do_ioctl        = ptm_ioctl,
119     .ndo_tx_timeout      = ptm_tx_timeout,
120 };
121
122 static struct net_device *g_net_dev[1] = {0};
123 static char *g_net_dev_name[1] = {"ptm0"};
124
125 static int g_ptm_prio_queue_map[8];
126
127 static DECLARE_TASKLET(g_swap_desc_tasklet, do_swap_desc_tasklet, 0);
128
129
130 unsigned int ifx_ptm_dbg_enable = DBG_ENABLE_MASK_ERR;
131
132 /*
133  * ####################################
134  *            Local Function
135  * ####################################
136  */
137
138 static void ptm_setup(struct net_device *dev, int ndev)
139 {
140     netif_carrier_off(dev);
141
142     dev->netdev_ops      = &g_ptm_netdev_ops;
143     netif_napi_add(dev, &g_ptm_priv_data.itf[ndev].napi, ptm_napi_poll, 16);
144     dev->watchdog_timeo  = ETH_WATCHDOG_TIMEOUT;
145
146     dev->dev_addr[0] = 0x00;
147     dev->dev_addr[1] = 0x20;
148         dev->dev_addr[2] = 0xda;
149         dev->dev_addr[3] = 0x86;
150         dev->dev_addr[4] = 0x23;
151         dev->dev_addr[5] = 0x75 + ndev;
152 }
153
154 static struct net_device_stats *ptm_get_stats(struct net_device *dev)
155 {
156    struct net_device_stats *s;
157   
158     if ( dev != g_net_dev[0] )
159         return NULL;
160 s = &g_ptm_priv_data.itf[0].stats;
161
162     return s;
163 }
164
165 static int ptm_open(struct net_device *dev)
166 {
167     ASSERT(dev == g_net_dev[0], "incorrect device");
168
169     napi_enable(&g_ptm_priv_data.itf[0].napi);
170
171     IFX_REG_W32_MASK(0, 1, MBOX_IGU1_IER);
172
173     netif_start_queue(dev);
174
175     return 0;
176 }
177
178 static int ptm_stop(struct net_device *dev)
179 {
180     ASSERT(dev == g_net_dev[0], "incorrect device");
181
182     IFX_REG_W32_MASK(1 | (1 << 17), 0, MBOX_IGU1_IER);
183
184     napi_disable(&g_ptm_priv_data.itf[0].napi);
185
186     netif_stop_queue(dev);
187
188     return 0;
189 }
190
191 static unsigned int ptm_poll(int ndev, unsigned int work_to_do)
192 {
193     unsigned int work_done = 0;
194     volatile struct rx_descriptor *desc;
195     struct rx_descriptor reg_desc;
196     struct sk_buff *skb, *new_skb;
197
198     ASSERT(ndev >= 0 && ndev < ARRAY_SIZE(g_net_dev), "ndev = %d (wrong value)", ndev);
199
200     while ( work_done < work_to_do ) {
201         desc = &WAN_RX_DESC_BASE[g_ptm_priv_data.itf[0].rx_desc_pos];
202         if ( desc->own /* || !desc->c */ )  //  if PP32 hold descriptor or descriptor not completed
203             break;
204         if ( ++g_ptm_priv_data.itf[0].rx_desc_pos == WAN_RX_DESC_NUM )
205             g_ptm_priv_data.itf[0].rx_desc_pos = 0;
206
207         reg_desc = *desc;
208         skb = get_skb_pointer(reg_desc.dataptr);
209         ASSERT(skb != NULL, "invalid pointer skb == NULL");
210
211         new_skb = alloc_skb_rx();
212         if ( new_skb != NULL ) {
213             skb_reserve(skb, reg_desc.byteoff);
214             skb_put(skb, reg_desc.datalen);
215
216             //  parse protocol header
217             skb->dev = g_net_dev[0];
218             skb->protocol = eth_type_trans(skb, skb->dev);
219
220             g_net_dev[0]->last_rx = jiffies;
221
222             netif_receive_skb(skb);
223
224             g_ptm_priv_data.itf[0].stats.rx_packets++;
225             g_ptm_priv_data.itf[0].stats.rx_bytes += reg_desc.datalen;
226
227             reg_desc.dataptr = (unsigned int)new_skb->data & 0x0FFFFFFF;
228             reg_desc.byteoff = RX_HEAD_MAC_ADDR_ALIGNMENT;
229         }
230
231         reg_desc.datalen = RX_MAX_BUFFER_SIZE - RX_HEAD_MAC_ADDR_ALIGNMENT;
232         reg_desc.own     = 1;
233         reg_desc.c       = 0;
234
235         /*  write discriptor to memory  */
236         *((volatile unsigned int *)desc + 1) = *((unsigned int *)&reg_desc + 1);
237         wmb();
238         *(volatile unsigned int *)desc = *(unsigned int *)&reg_desc;
239
240         work_done++;
241     }
242
243     return work_done;
244 }
245
246 static int ptm_napi_poll(struct napi_struct *napi, int budget)
247 {
248     int ndev = 0;
249     unsigned int work_done;
250
251     work_done = ptm_poll(ndev, budget);
252
253     //  interface down
254     if ( !netif_running(napi->dev) ) {
255         napi_complete(napi);
256         return work_done;
257     }
258
259     //  clear interrupt
260     IFX_REG_W32_MASK(0, 1, MBOX_IGU1_ISRC);
261     //  no more traffic
262     if (work_done < budget) {
263         napi_complete(napi);
264         IFX_REG_W32_MASK(0, 1, MBOX_IGU1_IER);
265         return work_done;
266     }
267
268     //  next round
269     return work_done;
270 }
271
272 static int ptm_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
273 {
274     unsigned int f_full;
275     int desc_base;
276     volatile struct tx_descriptor *desc;
277     struct tx_descriptor reg_desc = {0};
278     struct sk_buff *skb_to_free;
279     unsigned int byteoff;
280
281     ASSERT(dev == g_net_dev[0], "incorrect device");
282
283     if ( !g_showtime ) {
284         err("not in showtime");
285         goto PTM_HARD_START_XMIT_FAIL;
286     }
287
288     /*  allocate descriptor */
289     desc_base = get_tx_desc(0, &f_full);
290     if ( f_full ) {
291         dev->trans_start = jiffies;
292         netif_stop_queue(dev);
293
294         IFX_REG_W32_MASK(0, 1 << 17, MBOX_IGU1_ISRC);
295         IFX_REG_W32_MASK(0, 1 << 17, MBOX_IGU1_IER);
296     }
297     if ( desc_base < 0 )
298         goto PTM_HARD_START_XMIT_FAIL;
299     desc = &CPU_TO_WAN_TX_DESC_BASE[desc_base];
300
301     byteoff = (unsigned int)skb->data & (DATA_BUFFER_ALIGNMENT - 1);
302     if ( skb_headroom(skb) < sizeof(struct sk_buff *) + byteoff || skb_cloned(skb) ) {
303         struct sk_buff *new_skb;
304
305         ASSERT(skb_headroom(skb) >= sizeof(struct sk_buff *) + byteoff, "skb_headroom(skb) < sizeof(struct sk_buff *) + byteoff");
306         ASSERT(!skb_cloned(skb), "skb is cloned");
307
308         new_skb = alloc_skb_tx(skb->len);
309         if ( new_skb == NULL ) {
310             dbg("no memory");
311             goto ALLOC_SKB_TX_FAIL;
312         }
313         skb_put(new_skb, skb->len);
314         memcpy(new_skb->data, skb->data, skb->len);
315         dev_kfree_skb_any(skb);
316         skb = new_skb;
317         byteoff = (unsigned int)skb->data & (DATA_BUFFER_ALIGNMENT - 1);
318         /*  write back to physical memory   */
319         dma_cache_wback((unsigned long)skb->data, skb->len);
320     }
321
322     *(struct sk_buff **)((unsigned int)skb->data - byteoff - sizeof(struct sk_buff *)) = skb;
323     /*  write back to physical memory   */
324     dma_cache_wback((unsigned long)skb->data - byteoff - sizeof(struct sk_buff *), skb->len + byteoff + sizeof(struct sk_buff *));
325
326     /*  free previous skb   */
327     skb_to_free = get_skb_pointer(desc->dataptr);
328     if ( skb_to_free != NULL )
329         dev_kfree_skb_any(skb_to_free);
330
331     /*  update descriptor   */
332     reg_desc.small   = 0;
333     reg_desc.dataptr = (unsigned int)skb->data & (0x0FFFFFFF ^ (DATA_BUFFER_ALIGNMENT - 1));
334     reg_desc.datalen = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
335     reg_desc.qid     = g_ptm_prio_queue_map[skb->priority > 7 ? 7 : skb->priority];
336     reg_desc.byteoff = byteoff;
337     reg_desc.own     = 1;
338     reg_desc.c       = 1;
339     reg_desc.sop = reg_desc.eop = 1;
340
341     /*  update MIB  */
342     g_ptm_priv_data.itf[0].stats.tx_packets++;
343     g_ptm_priv_data.itf[0].stats.tx_bytes += reg_desc.datalen;
344
345     /*  write discriptor to memory  */
346     *((volatile unsigned int *)desc + 1) = *((unsigned int *)&reg_desc + 1);
347     wmb();
348     *(volatile unsigned int *)desc = *(unsigned int *)&reg_desc;
349
350     dev->trans_start = jiffies;
351
352     return 0;
353
354 ALLOC_SKB_TX_FAIL:
355 PTM_HARD_START_XMIT_FAIL:
356     dev_kfree_skb_any(skb);
357     g_ptm_priv_data.itf[0].stats.tx_dropped++;
358     return 0;
359 }
360
361 static int ptm_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
362 {
363     ASSERT(dev == g_net_dev[0], "incorrect device");
364
365     switch ( cmd )
366     {
367     case IFX_PTM_MIB_CW_GET:
368         ((PTM_CW_IF_ENTRY_T *)ifr->ifr_data)->ifRxNoIdleCodewords   = IFX_REG_R32(DREG_AR_CELL0) + IFX_REG_R32(DREG_AR_CELL1);
369         ((PTM_CW_IF_ENTRY_T *)ifr->ifr_data)->ifRxIdleCodewords     = IFX_REG_R32(DREG_AR_IDLE_CNT0) + IFX_REG_R32(DREG_AR_IDLE_CNT1);
370         ((PTM_CW_IF_ENTRY_T *)ifr->ifr_data)->ifRxCodingViolation   = IFX_REG_R32(DREG_AR_CVN_CNT0) + IFX_REG_R32(DREG_AR_CVN_CNT1) + IFX_REG_R32(DREG_AR_CVNP_CNT0) + IFX_REG_R32(DREG_AR_CVNP_CNT1);
371         ((PTM_CW_IF_ENTRY_T *)ifr->ifr_data)->ifTxNoIdleCodewords   = IFX_REG_R32(DREG_AT_CELL0) + IFX_REG_R32(DREG_AT_CELL1);
372         ((PTM_CW_IF_ENTRY_T *)ifr->ifr_data)->ifTxIdleCodewords     = IFX_REG_R32(DREG_AT_IDLE_CNT0) + IFX_REG_R32(DREG_AT_IDLE_CNT1);
373         break;
374     case IFX_PTM_MIB_FRAME_GET:
375         {
376             PTM_FRAME_MIB_T data = {0};
377             int i;
378
379             data.RxCorrect = IFX_REG_R32(DREG_AR_HEC_CNT0) + IFX_REG_R32(DREG_AR_HEC_CNT1) + IFX_REG_R32(DREG_AR_AIIDLE_CNT0) + IFX_REG_R32(DREG_AR_AIIDLE_CNT1);
380             for ( i = 0; i < 4; i++ )
381                 data.RxDropped += WAN_RX_MIB_TABLE(i)->wrx_dropdes_pdu;
382             for ( i = 0; i < 8; i++ )
383                 data.TxSend    += WAN_TX_MIB_TABLE(i)->wtx_total_pdu;
384
385             *((PTM_FRAME_MIB_T *)ifr->ifr_data) = data;
386         }
387         break;
388     case IFX_PTM_CFG_GET:
389         //  use bear channel 0 preemption gamma interface settings
390         ((IFX_PTM_CFG_T *)ifr->ifr_data)->RxEthCrcPresent = 1;
391         ((IFX_PTM_CFG_T *)ifr->ifr_data)->RxEthCrcCheck   = RX_GAMMA_ITF_CFG(0)->rx_eth_fcs_ver_dis == 0 ? 1 : 0;
392         ((IFX_PTM_CFG_T *)ifr->ifr_data)->RxTcCrcCheck    = RX_GAMMA_ITF_CFG(0)->rx_tc_crc_ver_dis == 0 ? 1 : 0;;
393         ((IFX_PTM_CFG_T *)ifr->ifr_data)->RxTcCrcLen      = RX_GAMMA_ITF_CFG(0)->rx_tc_crc_size == 0 ? 0 : (RX_GAMMA_ITF_CFG(0)->rx_tc_crc_size * 16);
394         ((IFX_PTM_CFG_T *)ifr->ifr_data)->TxEthCrcGen     = TX_GAMMA_ITF_CFG(0)->tx_eth_fcs_gen_dis == 0 ? 1 : 0;
395         ((IFX_PTM_CFG_T *)ifr->ifr_data)->TxTcCrcGen      = TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size == 0 ? 0 : 1;
396         ((IFX_PTM_CFG_T *)ifr->ifr_data)->TxTcCrcLen      = TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size == 0 ? 0 : (TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size * 16);
397         break;
398     case IFX_PTM_CFG_SET:
399         {
400             int i;
401
402             for ( i = 0; i < 4; i++ ) {
403                 RX_GAMMA_ITF_CFG(i)->rx_eth_fcs_ver_dis = ((IFX_PTM_CFG_T *)ifr->ifr_data)->RxEthCrcCheck ? 0 : 1;
404
405                 RX_GAMMA_ITF_CFG(0)->rx_tc_crc_ver_dis = ((IFX_PTM_CFG_T *)ifr->ifr_data)->RxTcCrcCheck ? 0 : 1;
406
407                 switch ( ((IFX_PTM_CFG_T *)ifr->ifr_data)->RxTcCrcLen ) {
408                     case 16: RX_GAMMA_ITF_CFG(0)->rx_tc_crc_size = 1; break;
409                     case 32: RX_GAMMA_ITF_CFG(0)->rx_tc_crc_size = 2; break;
410                     default: RX_GAMMA_ITF_CFG(0)->rx_tc_crc_size = 0;
411                 }
412
413                 TX_GAMMA_ITF_CFG(0)->tx_eth_fcs_gen_dis = ((IFX_PTM_CFG_T *)ifr->ifr_data)->TxEthCrcGen ? 0 : 1;
414
415                 if ( ((IFX_PTM_CFG_T *)ifr->ifr_data)->TxTcCrcGen ) {
416                     switch ( ((IFX_PTM_CFG_T *)ifr->ifr_data)->TxTcCrcLen ) {
417                         case 16: TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size = 1; break;
418                         case 32: TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size = 2; break;
419                         default: TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size = 0;
420                     }
421                 }
422                 else
423                     TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size = 0;
424             }
425         }
426         break;
427     case IFX_PTM_MAP_PKT_PRIO_TO_Q:
428         {
429             struct ppe_prio_q_map cmd;
430
431             if ( copy_from_user(&cmd, ifr->ifr_data, sizeof(cmd)) )
432                 return -EFAULT;
433
434             if ( cmd.pkt_prio < 0 || cmd.pkt_prio >= ARRAY_SIZE(g_ptm_prio_queue_map) )
435                 return -EINVAL;
436
437             if ( cmd.qid < 0 || cmd.qid >= g_wanqos_en )
438                 return -EINVAL;
439
440             g_ptm_prio_queue_map[cmd.pkt_prio] = cmd.qid;
441         }
442         break;
443     default:
444         return -EOPNOTSUPP;
445     }
446
447     return 0;
448 }
449
450 static void ptm_tx_timeout(struct net_device *dev)
451 {
452     ASSERT(dev == g_net_dev[0], "incorrect device");
453
454     /*  disable TX irq, release skb when sending new packet */
455     IFX_REG_W32_MASK(1 << 17, 0, MBOX_IGU1_IER);
456
457     /*  wake up TX queue    */
458     netif_wake_queue(dev);
459
460     return;
461 }
462
463 static inline struct sk_buff* alloc_skb_rx(void)
464 {
465     struct sk_buff *skb;
466
467     /*  allocate memroy including trailer and padding   */
468     skb = dev_alloc_skb(RX_MAX_BUFFER_SIZE + DATA_BUFFER_ALIGNMENT);
469     if ( skb != NULL ) {
470         /*  must be burst length alignment and reserve two more bytes for MAC address alignment  */
471         if ( ((unsigned int)skb->data & (DATA_BUFFER_ALIGNMENT - 1)) != 0 )
472             skb_reserve(skb, ~((unsigned int)skb->data + (DATA_BUFFER_ALIGNMENT - 1)) & (DATA_BUFFER_ALIGNMENT - 1));
473         /*  pub skb in reserved area "skb->data - 4"    */
474         *((struct sk_buff **)skb->data - 1) = skb;
475         wmb();
476         /*  write back and invalidate cache    */
477         dma_cache_wback_inv((unsigned long)skb->data - sizeof(skb), sizeof(skb));
478         /*  invalidate cache    */
479         dma_cache_inv((unsigned long)skb->data, (unsigned int)skb->end - (unsigned int)skb->data);
480     }
481
482     return skb;
483 }
484
485 static inline struct sk_buff* alloc_skb_tx(unsigned int size)
486 {
487     struct sk_buff *skb;
488
489     /*  allocate memory including padding   */
490     size = RX_MAX_BUFFER_SIZE;
491     size = (size + DATA_BUFFER_ALIGNMENT - 1) & ~(DATA_BUFFER_ALIGNMENT - 1);
492     skb = dev_alloc_skb(size + DATA_BUFFER_ALIGNMENT);
493     /*  must be burst length alignment  */
494     if ( skb != NULL )
495         skb_reserve(skb, ~((unsigned int)skb->data + (DATA_BUFFER_ALIGNMENT - 1)) & (DATA_BUFFER_ALIGNMENT - 1));
496     return skb;
497 }
498
499 static inline struct sk_buff *get_skb_pointer(unsigned int dataptr)
500 {
501     unsigned int skb_dataptr;
502     struct sk_buff *skb;
503
504     //  usually, CPE memory is less than 256M bytes
505     //  so NULL means invalid pointer
506     if ( dataptr == 0 ) {
507         dbg("dataptr is 0, it's supposed to be invalid pointer");
508         return NULL;
509     }
510
511     skb_dataptr = (dataptr - 4) | KSEG1;
512     skb = *(struct sk_buff **)skb_dataptr;
513
514     ASSERT((unsigned int)skb >= KSEG0, "invalid skb - skb = %#08x, dataptr = %#08x", (unsigned int)skb, dataptr);
515     ASSERT((((unsigned int)skb->data & (0x0FFFFFFF ^ (DATA_BUFFER_ALIGNMENT - 1))) | KSEG1) == (dataptr | KSEG1), "invalid skb - skb = %#08x, skb->data = %#08x, dataptr = %#08x", (unsigned int)skb, (unsigned int)skb->data, dataptr);
516
517     return skb;
518 }
519
520 static inline int get_tx_desc(unsigned int itf, unsigned int *f_full)
521 {
522     int desc_base = -1;
523     struct ptm_itf *p_itf = &g_ptm_priv_data.itf[0];
524
525     //  assume TX is serial operation
526     //  no protection provided
527
528     *f_full = 1;
529
530     if ( CPU_TO_WAN_TX_DESC_BASE[p_itf->tx_desc_pos].own == 0 ) {
531         desc_base = p_itf->tx_desc_pos;
532         if ( ++(p_itf->tx_desc_pos) == CPU_TO_WAN_TX_DESC_NUM )
533             p_itf->tx_desc_pos = 0;
534         if ( CPU_TO_WAN_TX_DESC_BASE[p_itf->tx_desc_pos].own == 0 )
535             *f_full = 0;
536     }
537
538     return desc_base;
539 }
540
541 static irqreturn_t mailbox_irq_handler(int irq, void *dev_id)
542 {
543     unsigned int isr;
544     int i;
545
546     isr = IFX_REG_R32(MBOX_IGU1_ISR);
547     IFX_REG_W32(isr, MBOX_IGU1_ISRC);
548     isr &= IFX_REG_R32(MBOX_IGU1_IER);
549
550             if (isr & BIT(0)) {
551                 IFX_REG_W32_MASK(1, 0, MBOX_IGU1_IER);
552                 napi_schedule(&g_ptm_priv_data.itf[0].napi);
553 #if defined(ENABLE_TMP_DBG) && ENABLE_TMP_DBG
554                 {
555                     volatile struct rx_descriptor *desc = &WAN_RX_DESC_BASE[g_ptm_priv_data.itf[0].rx_desc_pos];
556
557                     if ( desc->own ) {  //  PP32 hold
558                         err("invalid interrupt");
559                     }
560                 }
561 #endif
562             }
563            if (isr & BIT(16)) {
564                 IFX_REG_W32_MASK(1 << 16, 0, MBOX_IGU1_IER);
565                 tasklet_hi_schedule(&g_swap_desc_tasklet);
566             }
567             if (isr & BIT(17)) {
568                 IFX_REG_W32_MASK(1 << 17, 0, MBOX_IGU1_IER);
569                 netif_wake_queue(g_net_dev[0]);
570                 }
571
572     return IRQ_HANDLED;
573 }
574
575 static void do_swap_desc_tasklet(unsigned long arg)
576 {
577     int budget = 32;
578     volatile struct tx_descriptor *desc;
579     struct sk_buff *skb;
580     unsigned int byteoff;
581
582     while ( budget-- > 0 ) {
583         if ( WAN_SWAP_DESC_BASE[g_ptm_priv_data.itf[0].tx_swap_desc_pos].own )  //  if PP32 hold descriptor
584             break;
585
586         desc = &WAN_SWAP_DESC_BASE[g_ptm_priv_data.itf[0].tx_swap_desc_pos];
587         if ( ++g_ptm_priv_data.itf[0].tx_swap_desc_pos == WAN_SWAP_DESC_NUM )
588             g_ptm_priv_data.itf[0].tx_swap_desc_pos = 0;
589
590         skb = get_skb_pointer(desc->dataptr);
591         if ( skb != NULL )
592             dev_kfree_skb_any(skb);
593
594         skb = alloc_skb_tx(RX_MAX_BUFFER_SIZE);
595         if ( skb == NULL )
596             panic("can't allocate swap buffer for PPE firmware use\n");
597         byteoff = (unsigned int)skb->data & (DATA_BUFFER_ALIGNMENT - 1);
598         *(struct sk_buff **)((unsigned int)skb->data - byteoff - sizeof(struct sk_buff *)) = skb;
599
600         desc->dataptr = (unsigned int)skb->data & 0x0FFFFFFF;
601         desc->own = 1;
602     }
603
604     //  clear interrupt
605     IFX_REG_W32_MASK(0, 16, MBOX_IGU1_ISRC);
606     //  no more skb to be replaced
607     if ( WAN_SWAP_DESC_BASE[g_ptm_priv_data.itf[0].tx_swap_desc_pos].own ) {    //  if PP32 hold descriptor
608         IFX_REG_W32_MASK(0, 1 << 16, MBOX_IGU1_IER);
609         return;
610     }
611
612     tasklet_hi_schedule(&g_swap_desc_tasklet);
613     return;
614 }
615
616
617 static inline int ifx_ptm_version(char *buf)
618 {
619     int len = 0;
620     unsigned int major, minor;
621
622     ifx_ptm_get_fw_ver(&major, &minor);
623
624     len += sprintf(buf + len, "PTM %d.%d.%d", IFX_PTM_VER_MAJOR, IFX_PTM_VER_MID, IFX_PTM_VER_MINOR);
625     len += sprintf(buf + len, "    PTM (E1) firmware version %d.%d\n", major, minor);
626
627     return len;
628 }
629
630 static inline int init_priv_data(void)
631 {
632     int i, j;
633
634     g_wanqos_en = wanqos_en ? wanqos_en : 8;
635     if ( g_wanqos_en > 8 )
636         g_wanqos_en = 8;
637
638     for ( i = 0; i < ARRAY_SIZE(g_queue_gamma_map); i++ )
639     {
640         g_queue_gamma_map[i] = queue_gamma_map[i] & ((1 << g_wanqos_en) - 1);
641         for ( j = 0; j < i; j++ )
642             g_queue_gamma_map[i] &= ~g_queue_gamma_map[j];
643     }
644
645     memset(&g_ptm_priv_data, 0, sizeof(g_ptm_priv_data));
646
647     {
648         int max_packet_priority = ARRAY_SIZE(g_ptm_prio_queue_map);
649         int tx_num_q;
650         int q_step, q_accum, p_step;
651
652         tx_num_q = __ETH_WAN_TX_QUEUE_NUM;
653         q_step = tx_num_q - 1;
654         p_step = max_packet_priority - 1;
655         for ( j = 0, q_accum = 0; j < max_packet_priority; j++, q_accum += q_step )
656             g_ptm_prio_queue_map[j] = q_step - (q_accum + (p_step >> 1)) / p_step;
657     }
658
659     return 0;
660 }
661
662 static inline void clear_priv_data(void)
663 {
664 }
665
666 static inline int init_tables(void)
667 {
668     struct sk_buff *skb_pool[WAN_RX_DESC_NUM] = {0};
669     struct cfg_std_data_len cfg_std_data_len = {0};
670     struct tx_qos_cfg tx_qos_cfg = {0};
671     struct psave_cfg psave_cfg = {0};
672     struct eg_bwctrl_cfg eg_bwctrl_cfg = {0};
673     struct test_mode test_mode = {0};
674     struct rx_bc_cfg rx_bc_cfg = {0};
675     struct tx_bc_cfg tx_bc_cfg = {0};
676     struct gpio_mode gpio_mode = {0};
677     struct gpio_wm_cfg gpio_wm_cfg = {0};
678     struct rx_gamma_itf_cfg rx_gamma_itf_cfg = {0};
679     struct tx_gamma_itf_cfg tx_gamma_itf_cfg = {0};
680     struct wtx_qos_q_desc_cfg wtx_qos_q_desc_cfg = {0};
681     struct rx_descriptor rx_desc = {0};
682     struct tx_descriptor tx_desc = {0};
683     int i;
684
685     for ( i = 0; i < WAN_RX_DESC_NUM; i++ ) {
686         skb_pool[i] = alloc_skb_rx();
687         if ( skb_pool[i] == NULL )
688             goto ALLOC_SKB_RX_FAIL;
689     }
690
691     cfg_std_data_len.byte_off = RX_HEAD_MAC_ADDR_ALIGNMENT; //  this field replaces byte_off in rx descriptor of VDSL ingress
692     cfg_std_data_len.data_len = 1600;
693     *CFG_STD_DATA_LEN = cfg_std_data_len;
694
695     tx_qos_cfg.time_tick    = cgu_get_pp32_clock() / 62500; //  16 * (cgu_get_pp32_clock() / 1000000)
696     tx_qos_cfg.overhd_bytes = 0;
697     tx_qos_cfg.eth1_eg_qnum = __ETH_WAN_TX_QUEUE_NUM;
698     tx_qos_cfg.eth1_burst_chk = 1;
699     tx_qos_cfg.eth1_qss     = 0;
700     tx_qos_cfg.shape_en     = 0;    //  disable
701     tx_qos_cfg.wfq_en       = 0;    //  strict priority
702     *TX_QOS_CFG = tx_qos_cfg;
703
704     psave_cfg.start_state   = 0;
705     psave_cfg.sleep_en      = 1;    //  enable sleep mode
706     *PSAVE_CFG = psave_cfg;
707
708     eg_bwctrl_cfg.fdesc_wm  = 16;
709     eg_bwctrl_cfg.class_len = 128;
710     *EG_BWCTRL_CFG = eg_bwctrl_cfg;
711
712     //*GPIO_ADDR = (unsigned int)IFX_GPIO_P0_OUT;
713     *GPIO_ADDR = (unsigned int)0x00000000;  //  disabled by default
714
715     gpio_mode.gpio_bit_bc1 = 2;
716     gpio_mode.gpio_bit_bc0 = 1;
717     gpio_mode.gpio_bc1_en  = 0;
718     gpio_mode.gpio_bc0_en  = 0;
719     *GPIO_MODE = gpio_mode;
720
721     gpio_wm_cfg.stop_wm_bc1  = 2;
722     gpio_wm_cfg.start_wm_bc1 = 4;
723     gpio_wm_cfg.stop_wm_bc0  = 2;
724     gpio_wm_cfg.start_wm_bc0 = 4;
725     *GPIO_WM_CFG = gpio_wm_cfg;
726
727     test_mode.mib_clear_mode    = 0;
728     test_mode.test_mode         = 0;
729     *TEST_MODE = test_mode;
730
731     rx_bc_cfg.local_state   = 0;
732     rx_bc_cfg.remote_state  = 0;
733     rx_bc_cfg.to_false_th   = 7;
734     rx_bc_cfg.to_looking_th = 3;
735     *RX_BC_CFG(0) = rx_bc_cfg;
736     *RX_BC_CFG(1) = rx_bc_cfg;
737
738     tx_bc_cfg.fill_wm   = 2;
739     tx_bc_cfg.uflw_wm   = 2;
740     *TX_BC_CFG(0) = tx_bc_cfg;
741     *TX_BC_CFG(1) = tx_bc_cfg;
742
743     rx_gamma_itf_cfg.receive_state      = 0;
744     rx_gamma_itf_cfg.rx_min_len         = 60;
745     rx_gamma_itf_cfg.rx_pad_en          = 1;
746     rx_gamma_itf_cfg.rx_eth_fcs_ver_dis = 0;
747     rx_gamma_itf_cfg.rx_rm_eth_fcs      = 1;
748     rx_gamma_itf_cfg.rx_tc_crc_ver_dis  = 0;
749     rx_gamma_itf_cfg.rx_tc_crc_size     = 1;
750     rx_gamma_itf_cfg.rx_eth_fcs_result  = 0xC704DD7B;
751     rx_gamma_itf_cfg.rx_tc_crc_result   = 0x1D0F1D0F;
752     rx_gamma_itf_cfg.rx_crc_cfg         = 0x2500;
753     rx_gamma_itf_cfg.rx_eth_fcs_init_value  = 0xFFFFFFFF;
754     rx_gamma_itf_cfg.rx_tc_crc_init_value   = 0x0000FFFF;
755     rx_gamma_itf_cfg.rx_max_len_sel     = 0;
756     rx_gamma_itf_cfg.rx_edit_num2       = 0;
757     rx_gamma_itf_cfg.rx_edit_pos2       = 0;
758     rx_gamma_itf_cfg.rx_edit_type2      = 0;
759     rx_gamma_itf_cfg.rx_edit_en2        = 0;
760     rx_gamma_itf_cfg.rx_edit_num1       = 0;
761     rx_gamma_itf_cfg.rx_edit_pos1       = 0;
762     rx_gamma_itf_cfg.rx_edit_type1      = 0;
763     rx_gamma_itf_cfg.rx_edit_en1        = 0;
764     rx_gamma_itf_cfg.rx_inserted_bytes_1l   = 0;
765     rx_gamma_itf_cfg.rx_inserted_bytes_1h   = 0;
766     rx_gamma_itf_cfg.rx_inserted_bytes_2l   = 0;
767     rx_gamma_itf_cfg.rx_inserted_bytes_2h   = 0;
768     rx_gamma_itf_cfg.rx_len_adj         = -6;
769     for ( i = 0; i < 4; i++ )
770         *RX_GAMMA_ITF_CFG(i) = rx_gamma_itf_cfg;
771
772     tx_gamma_itf_cfg.tx_len_adj         = 6;
773     tx_gamma_itf_cfg.tx_crc_off_adj     = 6;
774     tx_gamma_itf_cfg.tx_min_len         = 0;
775     tx_gamma_itf_cfg.tx_eth_fcs_gen_dis = 0;
776     tx_gamma_itf_cfg.tx_tc_crc_size     = 1;
777     tx_gamma_itf_cfg.tx_crc_cfg         = 0x2F00;
778     tx_gamma_itf_cfg.tx_eth_fcs_init_value  = 0xFFFFFFFF;
779     tx_gamma_itf_cfg.tx_tc_crc_init_value   = 0x0000FFFF;
780     for ( i = 0; i < ARRAY_SIZE(g_queue_gamma_map); i++ ) {
781         tx_gamma_itf_cfg.queue_mapping = g_queue_gamma_map[i];
782         *TX_GAMMA_ITF_CFG(i) = tx_gamma_itf_cfg;
783     }
784
785     for ( i = 0; i < __ETH_WAN_TX_QUEUE_NUM; i++ ) {
786         wtx_qos_q_desc_cfg.length = WAN_TX_DESC_NUM;
787         wtx_qos_q_desc_cfg.addr   = __ETH_WAN_TX_DESC_BASE(i);
788         *WTX_QOS_Q_DESC_CFG(i) = wtx_qos_q_desc_cfg;
789     }
790
791     //  default TX queue QoS config is all ZERO
792
793     //  TX Ctrl K Table
794     IFX_REG_W32(0x90111293, TX_CTRL_K_TABLE(0));
795     IFX_REG_W32(0x14959617, TX_CTRL_K_TABLE(1));
796     IFX_REG_W32(0x18999A1B, TX_CTRL_K_TABLE(2));
797     IFX_REG_W32(0x9C1D1E9F, TX_CTRL_K_TABLE(3));
798     IFX_REG_W32(0xA02122A3, TX_CTRL_K_TABLE(4));
799     IFX_REG_W32(0x24A5A627, TX_CTRL_K_TABLE(5));
800     IFX_REG_W32(0x28A9AA2B, TX_CTRL_K_TABLE(6));
801     IFX_REG_W32(0xAC2D2EAF, TX_CTRL_K_TABLE(7));
802     IFX_REG_W32(0x30B1B233, TX_CTRL_K_TABLE(8));
803     IFX_REG_W32(0xB43536B7, TX_CTRL_K_TABLE(9));
804     IFX_REG_W32(0xB8393ABB, TX_CTRL_K_TABLE(10));
805     IFX_REG_W32(0x3CBDBE3F, TX_CTRL_K_TABLE(11));
806     IFX_REG_W32(0xC04142C3, TX_CTRL_K_TABLE(12));
807     IFX_REG_W32(0x44C5C647, TX_CTRL_K_TABLE(13));
808     IFX_REG_W32(0x48C9CA4B, TX_CTRL_K_TABLE(14));
809     IFX_REG_W32(0xCC4D4ECF, TX_CTRL_K_TABLE(15));
810
811     //  init RX descriptor
812     rx_desc.own     = 1;
813     rx_desc.c       = 0;
814     rx_desc.sop     = 1;
815     rx_desc.eop     = 1;
816     rx_desc.byteoff = RX_HEAD_MAC_ADDR_ALIGNMENT;
817     rx_desc.datalen = RX_MAX_BUFFER_SIZE - RX_HEAD_MAC_ADDR_ALIGNMENT;
818     for ( i = 0; i < WAN_RX_DESC_NUM; i++ ) {
819         rx_desc.dataptr = (unsigned int)skb_pool[i]->data & 0x0FFFFFFF;
820         WAN_RX_DESC_BASE[i] = rx_desc;
821     }
822
823     //  init TX descriptor
824     tx_desc.own     = 0;
825     tx_desc.c       = 0;
826     tx_desc.sop     = 1;
827     tx_desc.eop     = 1;
828     tx_desc.byteoff = 0;
829     tx_desc.qid     = 0;
830     tx_desc.datalen = 0;
831     tx_desc.small   = 0;
832     tx_desc.dataptr = 0;
833     for ( i = 0; i < CPU_TO_WAN_TX_DESC_NUM; i++ )
834         CPU_TO_WAN_TX_DESC_BASE[i] = tx_desc;
835     for ( i = 0; i < WAN_TX_DESC_NUM_TOTAL; i++ )
836         WAN_TX_DESC_BASE(0)[i] = tx_desc;
837
838     //  init Swap descriptor
839     for ( i = 0; i < WAN_SWAP_DESC_NUM; i++ )
840         WAN_SWAP_DESC_BASE[i] = tx_desc;
841
842     //  init fastpath TX descriptor
843     tx_desc.own     = 1;
844     for ( i = 0; i < FASTPATH_TO_WAN_TX_DESC_NUM; i++ )
845         FASTPATH_TO_WAN_TX_DESC_BASE[i] = tx_desc;
846
847     return 0;
848
849 ALLOC_SKB_RX_FAIL:
850     while ( i-- > 0 )
851         dev_kfree_skb_any(skb_pool[i]);
852     return -1;
853 }
854
855 static inline void clear_tables(void)
856 {
857     struct sk_buff *skb;
858     int i, j;
859
860     for ( i = 0; i < WAN_RX_DESC_NUM; i++ ) {
861         skb = get_skb_pointer(WAN_RX_DESC_BASE[i].dataptr);
862         if ( skb != NULL )
863             dev_kfree_skb_any(skb);
864     }
865
866     for ( i = 0; i < CPU_TO_WAN_TX_DESC_NUM; i++ ) {
867         skb = get_skb_pointer(CPU_TO_WAN_TX_DESC_BASE[i].dataptr);
868         if ( skb != NULL )
869             dev_kfree_skb_any(skb);
870     }
871
872     for ( j = 0; j < 8; j++ )
873         for ( i = 0; i < WAN_TX_DESC_NUM; i++ ) {
874             skb = get_skb_pointer(WAN_TX_DESC_BASE(j)[i].dataptr);
875             if ( skb != NULL )
876                 dev_kfree_skb_any(skb);
877         }
878
879     for ( i = 0; i < WAN_SWAP_DESC_NUM; i++ ) {
880         skb = get_skb_pointer(WAN_SWAP_DESC_BASE[i].dataptr);
881         if ( skb != NULL )
882             dev_kfree_skb_any(skb);
883     }
884
885     for ( i = 0; i < FASTPATH_TO_WAN_TX_DESC_NUM; i++ ) {
886         skb = get_skb_pointer(FASTPATH_TO_WAN_TX_DESC_BASE[i].dataptr);
887         if ( skb != NULL )
888             dev_kfree_skb_any(skb);
889     }
890 }
891
892 static int ptm_showtime_enter(struct port_cell_info *port_cell, void *xdata_addr)
893 {
894         int i;
895
896         ASSERT(port_cell != NULL, "port_cell is NULL");
897         ASSERT(xdata_addr != NULL, "xdata_addr is NULL");
898
899         //  TODO: ReTX set xdata_addr
900         g_xdata_addr = xdata_addr;
901
902         g_showtime = 1;
903
904         for ( i = 0; i < ARRAY_SIZE(g_net_dev); i++ )
905                 netif_carrier_on(g_net_dev[i]);
906
907         IFX_REG_W32(0x0F, UTP_CFG);
908
909         //#ifdef CONFIG_VR9
910         //    IFX_REG_W32_MASK(1 << 17, 0, FFSM_CFG0);
911         //#endif
912
913         printk("enter showtime\n");
914
915         return 0;
916 }
917
918 static int ptm_showtime_exit(void)
919 {
920         int i;
921
922         if ( !g_showtime )
923                 return -1;
924
925         //#ifdef CONFIG_VR9
926         //    IFX_REG_W32_MASK(0, 1 << 17, FFSM_CFG0);
927         //#endif
928
929         IFX_REG_W32(0x00, UTP_CFG);
930
931         for ( i = 0; i < ARRAY_SIZE(g_net_dev); i++ )
932                 netif_carrier_off(g_net_dev[i]);
933
934         g_showtime = 0;
935
936         //  TODO: ReTX clean state
937         g_xdata_addr = NULL;
938
939         printk("leave showtime\n");
940
941         return 0;
942 }
943
944
945
946 static int ifx_ptm_init(void)
947 {
948     int ret;
949     int i;
950     char ver_str[128];
951     struct port_cell_info port_cell = {0};
952
953     ret = init_priv_data();
954     if ( ret != 0 ) {
955         err("INIT_PRIV_DATA_FAIL");
956         goto INIT_PRIV_DATA_FAIL;
957     }
958
959     ifx_ptm_init_chip();
960     ret = init_tables();
961     if ( ret != 0 ) {
962         err("INIT_TABLES_FAIL");
963         goto INIT_TABLES_FAIL;
964     }
965
966     for ( i = 0; i < ARRAY_SIZE(g_net_dev); i++ ) {
967         g_net_dev[i] = alloc_netdev(0, g_net_dev_name[i], NET_NAME_UNKNOWN, ether_setup);
968         if ( g_net_dev[i] == NULL )
969             goto ALLOC_NETDEV_FAIL;
970         ptm_setup(g_net_dev[i], i);
971     }
972
973     for ( i = 0; i < ARRAY_SIZE(g_net_dev); i++ ) {
974         ret = register_netdev(g_net_dev[i]);
975         if ( ret != 0 )
976             goto REGISTER_NETDEV_FAIL;
977     }
978
979     /*  register interrupt handler  */
980 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
981     ret = request_irq(PPE_MAILBOX_IGU1_INT, mailbox_irq_handler, 0, "ptm_mailbox_isr", &g_ptm_priv_data);
982 #else
983     ret = request_irq(PPE_MAILBOX_IGU1_INT, mailbox_irq_handler, IRQF_DISABLED, "ptm_mailbox_isr", &g_ptm_priv_data);
984 #endif
985     if ( ret ) {
986         if ( ret == -EBUSY ) {
987             err("IRQ may be occupied by other driver, please reconfig to disable it.");
988         }
989         else {
990             err("request_irq fail");
991         }
992         goto REQUEST_IRQ_PPE_MAILBOX_IGU1_INT_FAIL;
993     }
994     disable_irq(PPE_MAILBOX_IGU1_INT);
995
996     ret = ifx_pp32_start(0);
997     if ( ret ) {
998         err("ifx_pp32_start fail!");
999         goto PP32_START_FAIL;
1000     }
1001     IFX_REG_W32(1 << 16, MBOX_IGU1_IER);    //  enable SWAP interrupt
1002     IFX_REG_W32(~0, MBOX_IGU1_ISRC);
1003
1004     enable_irq(PPE_MAILBOX_IGU1_INT);
1005
1006     ifx_mei_atm_showtime_check(&g_showtime, &port_cell, &g_xdata_addr);
1007     
1008     ifx_mei_atm_showtime_enter = ptm_showtime_enter;
1009     ifx_mei_atm_showtime_exit  = ptm_showtime_exit;
1010
1011     ifx_ptm_version(ver_str);
1012     printk(KERN_INFO "%s", ver_str);
1013
1014     printk("ifxmips_ptm: PTM init succeed\n");
1015
1016     return 0;
1017
1018 PP32_START_FAIL:
1019     free_irq(PPE_MAILBOX_IGU1_INT, &g_ptm_priv_data);
1020 REQUEST_IRQ_PPE_MAILBOX_IGU1_INT_FAIL:
1021     i = ARRAY_SIZE(g_net_dev);
1022 REGISTER_NETDEV_FAIL:
1023     while ( i-- )
1024         unregister_netdev(g_net_dev[i]);
1025     i = ARRAY_SIZE(g_net_dev);
1026 ALLOC_NETDEV_FAIL:
1027     while ( i-- ) {
1028         free_netdev(g_net_dev[i]);
1029         g_net_dev[i] = NULL;
1030     }
1031 INIT_TABLES_FAIL:
1032 INIT_PRIV_DATA_FAIL:
1033     clear_priv_data();
1034     printk("ifxmips_ptm: PTM init failed\n");
1035     return ret;
1036 }
1037
1038 static void __exit ifx_ptm_exit(void)
1039 {
1040     int i;
1041         ifx_mei_atm_showtime_enter = NULL;
1042         ifx_mei_atm_showtime_exit  = NULL;
1043
1044
1045     ifx_pp32_stop(0);
1046
1047     free_irq(PPE_MAILBOX_IGU1_INT, &g_ptm_priv_data);
1048
1049     for ( i = 0; i < ARRAY_SIZE(g_net_dev); i++ )
1050         unregister_netdev(g_net_dev[i]);
1051
1052     for ( i = 0; i < ARRAY_SIZE(g_net_dev); i++ ) {
1053         free_netdev(g_net_dev[i]);
1054         g_net_dev[i] = NULL;
1055     }
1056
1057     clear_tables();
1058
1059     ifx_ptm_uninit_chip();
1060
1061     clear_priv_data();
1062 }
1063
1064 #ifndef MODULE
1065 static int __init wanqos_en_setup(char *line)
1066 {
1067     wanqos_en = simple_strtoul(line, NULL, 0);
1068
1069     if ( wanqos_en < 1 || wanqos_en > 8 )
1070         wanqos_en = 0;
1071
1072     return 0;
1073 }
1074
1075 static int __init queue_gamma_map_setup(char *line)
1076 {
1077     char *p;
1078     int i;
1079
1080     for ( i = 0, p = line; i < ARRAY_SIZE(queue_gamma_map) && isxdigit(*p); i++ )
1081     {
1082         queue_gamma_map[i] = simple_strtoul(p, &p, 0);
1083         if ( *p == ',' || *p == ';' || *p == ':' )
1084             p++;
1085     }
1086
1087     return 0;
1088 }
1089 #endif
1090 module_init(ifx_ptm_init);
1091 module_exit(ifx_ptm_exit);
1092 #ifndef MODULE
1093   __setup("wanqos_en=", wanqos_en_setup);
1094   __setup("queue_gamma_map=", queue_gamma_map_setup);
1095 #endif
1096
1097 MODULE_LICENSE("GPL");