2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
16 //-----------------------------------------------------------------------
19 * Driver for Infineon Amazon TPE
21 //-----------------------------------------------------------------------
22 /* Author: peng.liu@infineon.com
23 * Created: 12-April-2004
25 //-----------------------------------------------------------------------
27 * Last changed on: 13 Oct. 2004
28 * Last changed by: peng.liu@infineon.com
29 * Last changed on: 28 Jan. 2004
30 * Last changed by: peng.liu@infineon.com
31 * Last changed Reason:
32 * - AAL5R may send more bytes than expected in MFL (so far, confirmed as 64 bytes)
34 // 507261:tc.chen 2005/07/26 re-organize code address map to improve performance.
35 // 507281:tc.chen 2005/07/28 fix f4 segment isssue
36 /* 511045:linmars 2005/11/04 from Liu.Peng: change NRT_VBR bandwidth calculation based on scr instead of pcr */
45 /*TPE level loopback, bypass AWARE DFE */
48 /* enable debug options */
49 #undef AMAZON_ATM_DEBUG
51 /* enable rx error packet analysis */
52 #undef AMAZON_ATM_DEBUG_RX
54 /* test AAL5 Interrupt */
55 #undef AMAZON_TPE_TEST_AAL5_INT
58 #undef AMAZON_TPE_DUMP
60 /* read ARC register*/
61 /* this register is located in side DFE module*/
62 #undef AMAZON_TPE_READ_ARC
64 /* software controlled reassembly */
67 /* recovery from AAL5 bug */
68 #undef AMAZON_TPE_AAL5_RECOVERY
70 #if defined(AMAZON_TPE_READ_ARC) || defined(AMAZON_TPE_AAL5_RECOVERY)
71 #define ALPHAEUS_BASE_ADDR 0x31c00
72 #define A_CFG_ADDR (ALPHAEUS_BASE_ADDR+0x04)
73 #define AR_CB0_STATUS_ADDR (ALPHAEUS_BASE_ADDR+0x2c)
74 #define AR_CB1_STATUS_ADDR (ALPHAEUS_BASE_ADDR+0x30)
75 #define AT_CELL0_ADDR (ALPHAEUS_BASE_ADDR+0x90)
76 #define AR_CELL0_ADDR (ALPHAEUS_BASE_ADDR+0x1a0)
77 #define AR_CD_CNT0_ADDR (ALPHAEUS_BASE_ADDR+0x1c8)
80 #include <linux/module.h>
81 #include <linux/config.h>
82 #include <linux/init.h>
83 #include <linux/kernel.h>
84 #include <linux/slab.h>
86 #include <linux/types.h>
87 #include <linux/errno.h>
88 #include <linux/time.h>
89 #include <linux/atm.h>
90 #include <linux/atmdev.h>
91 #include <linux/netdevice.h>
92 #include <asm/byteorder.h>
94 #include <asm/uaccess.h>
95 #include <asm/system.h>
96 #include <asm/atomic.h>
97 #include <asm/bitops.h>
98 #include <asm/system.h>
100 #include <asm/amazon/amazon.h>
101 #include <asm/amazon/irq.h>
103 #include <linux/in.h>
104 #include <linux/netdevice.h>
105 #include <linux/etherdevice.h>
106 #include <linux/ip.h>
107 #include <linux/tcp.h>
108 #include <linux/skbuff.h>
109 #include <linux/in6.h>
110 #include <linux/delay.h>
111 #include <asm/amazon/atm_defines.h>
112 #include <asm/amazon/amazon_dma.h>
113 #include <asm/amazon/amazon_tpe.h>
115 #if defined(AMAZON_TPE_READ_ARC) || defined(AMAZON_TPE_AAL5_RECOVERY)
116 #include <asm/amazon/amazon_mei.h>
117 #include <asm/amazon/amazon_mei_app.h>
120 #define AMAZON_TPE_EMSG(fmt, args...) printk( KERN_ERR "%s: " fmt,__FUNCTION__, ## args)
122 /***************************************** External Functions *******************************************/
123 extern unsigned int amazon_get_fpi_hz(void);
124 extern void mask_and_ack_amazon_irq(unsigned int irq_nr
);
125 extern void amz_push_oam(unsigned char *);
128 #if defined(AMAZON_TPE_READ_ARC) || defined(AMAZON_TPE_AAL5_RECOVERY)
129 extern MEI_ERROR
meiDebugRead(u32 srcaddr
, u32
*databuff
, u32 databuffsize
);
130 extern MEI_ERROR
meiDebugWrite(u32 destaddr
, u32
*databuff
, u32 databuffsize
);
133 /***************************************** Internal Functions *******************************************/
134 int amazon_atm_read_procmem(char *buf
, char **start
, off_t offset
,int count
, int *eof
, void *data
);
135 /***************************************** Global Data *******************************************/
136 amazon_atm_dev_t g_atm_dev
; //device data
137 static struct tq_struct swex_start_task
; //BH task
138 static struct tq_struct swex_complete_task
; //BH task
139 #ifdef AMAZON_TPE_SCR
140 static struct tq_struct a5r_task
; //BH task
142 static struct dma_device_info g_dma_dev
; //for DMA
143 static struct atm_dev
* amazon_atm_devs
[AMAZON_ATM_PORT_NUM
];
144 static struct oam_last_activity g_oam_time_stamp
[AMAZON_ATM_MAX_VCC_NUM
];
145 static u8 g_oam_cell
[AMAZON_AAL0_SDU
+4]; //for OAM cells
146 #ifdef AMAZON_CHECK_LINK
147 static int adsl_link_status
; //ADSL link status, 0:down, 1:up
148 #endif //AMAZON_CHECK_LINK
149 /***************************************** Module Parameters *************************************/
150 // Parameter Definition for module
151 static int port_enable0
= 1; // Variable for parameter port_enable0
152 static int port_enable1
= 0; // Variable for parameter port_enable1
153 static int port_max_conn0
= 15; // Variable for parameter port_max_conn0
154 static int port_max_conn1
= 0; // Variable for parameter port_max_conn1
155 static int port_cell_rate_up0
= 7500; // Variable for parameter port_cell_rate_up0
156 static int port_cell_rate_up1
= 7500; // Variable for parameter port_cell_rate_up1
159 static int qsb_tau
= 1; // Variable for parameter qsb_tau
160 static int qsb_srvm
= 0xf; // Variable for parameter qsb_srvm
161 static int qsb_tstep
= 4 ; // Variable for parameter qsb_tstep
163 static int cbm_nrt
= 3900; // Variable for parameter cbm_nrt
164 static int cbm_clp0
=3500; // Variable for parameter cbm_clp0
165 static int cbm_clp1
=3200; // Variable for parameter cbm_clp1
166 static int cbm_free_cell_no
= AMAZON_ATM_FREE_CELLS
; // Variable for parameter cbm_free_cell_no
168 static int a5_fill_pattern
= 0x7e; // Variable for parameter a5_fill_pattern '~'
169 static int a5s_mtu
= 0x700; // mtu for tx
170 static int a5r_mtu
= 0x700; // mtu for rx
172 static int oam_q_threshold
= 64; // oam queue threshold, minium value 64
173 static int rx_q_threshold
= 1000; // rx queue threshold, minium value 64
174 static int tx_q_threshold
= 800; // tx queue threshold, minium value 64
176 MODULE_PARM(port_max_conn0
, "i");
177 MODULE_PARM_DESC(port_max_conn0
, "Maximum atm connection for port #0");
178 MODULE_PARM(port_max_conn1
, "i");
179 MODULE_PARM_DESC(port_max_conn1
, "Maximum atm connection for port #1");
180 MODULE_PARM(port_enable0
, "i");
181 MODULE_PARM_DESC(port_enable0
, "0 -> port disabled, 1->port enabled");
182 MODULE_PARM(port_enable1
, "i");
183 MODULE_PARM_DESC(port_enable1
, "0 -> port disabled, 1->port enabled");
184 MODULE_PARM(port_cell_rate_up0
, "i");
185 MODULE_PARM_DESC(port_cell_rate_up0
, "ATM port upstream rate in cells/s");
186 MODULE_PARM(port_cell_rate_up1
, "i");
187 MODULE_PARM_DESC(port_cell_rate_up1
, "ATM port upstream rate in cells/s");
189 MODULE_PARM(qsb_tau
,"i");
190 MODULE_PARM_DESC(qsb_tau
, "Cell delay variation. value must be > 0");
191 MODULE_PARM(qsb_srvm
, "i");
192 MODULE_PARM_DESC(qsb_srvm
, "Maximum burst size");
193 MODULE_PARM(qsb_tstep
, "i");
194 MODULE_PARM_DESC(qsb_tstep
, "n*32 cycles per sbs cycles n=1,2,4");
196 MODULE_PARM(cbm_nrt
, "i");
197 MODULE_PARM_DESC(cbm_nrt
, "Non real time threshold for cell buffer");
198 MODULE_PARM(cbm_clp0
, "i");
199 MODULE_PARM_DESC(cbm_clp0
, "Threshold for cells with cell loss priority 0");
200 MODULE_PARM(cbm_clp1
, "i");
201 MODULE_PARM_DESC(cbm_clp1
, "Threshold for cells with cell loss priority 1");
202 MODULE_PARM(cbm_free_cell_no
, "i");
203 MODULE_PARM_DESC(cbm_free_cell_no
, "Number of cells in the cell buffer manager");
205 MODULE_PARM(a5_fill_pattern
, "i");
206 MODULE_PARM_DESC(a5_fill_pattern
, "filling pattern (PAD) for aal5 frames");
207 MODULE_PARM(a5s_mtu
, "i");
208 MODULE_PARM_DESC(a5s_mtu
, "max. SDU for upstream");
209 MODULE_PARM(a5r_mtu
, "i");
210 MODULE_PARM_DESC(a5r_mtu
, "max. SDU for downstream");
212 MODULE_PARM(oam_q_threshold
, "i");
213 MODULE_PARM_DESC(oam_q_threshold
, "oam queue threshold");
215 MODULE_PARM(rx_q_threshold
, "i");
216 MODULE_PARM_DESC(rx_q_threshold
, "downstream/rx queue threshold");
218 MODULE_PARM(tx_q_threshold
, "i");
219 MODULE_PARM_DESC(tx_q_threshold
, "upstream/tx queue threshold");
221 /***************************************** local functions *************************************/
226 static inline int valid_qid(int qid
)
228 return ( (qid
>0) && (qid
<AMAZON_ATM_MAX_QUEUE_NUM
));
232 * Brief: align to 16 bytes boundary
236 * use skb_reserve to adjust the data pointer
237 * don't change head pointer
238 * pls allocate extrac 16 bytes before call this function
240 static void inline alloc_align_16(struct sk_buff
* skb
)
242 if ( ( ((u32
) (skb
->data
)) & 15) != 0){
243 AMAZON_TPE_DMSG("need to adjust the alignment manually\n");
244 skb_reserve(skb
, 16 - (((u32
) (skb
->data
)) & 15) );
250 * Brief: initialize the device according to the module paramters
251 * Return: not NULL - ok
253 * Description: arrange load parameters and call the hardware initialization routines
255 static void atm_init_parameters(amazon_atm_dev_t
*dev
)
258 dev
->ports
[0].enable
= port_enable0
;
259 dev
->ports
[0].max_conn
= port_max_conn0
;
260 dev
->ports
[0].tx_max_cr
= port_cell_rate_up0
;
262 dev
->ports
[1].enable
= port_enable1
;
263 dev
->ports
[1].max_conn
= port_max_conn1
;
264 dev
->ports
[1].tx_max_cr
= port_cell_rate_up1
;
268 dev
->aal5
.padding_byte
= a5_fill_pattern
;
269 dev
->aal5
.tx_max_sdu
= a5s_mtu
;
270 dev
->aal5
.rx_max_sdu
= a5r_mtu
;
273 dev
->cbm
.nrt_thr
= cbm_nrt
;
274 dev
->cbm
.clp0_thr
= cbm_clp0
;
275 dev
->cbm
.clp1_thr
= cbm_clp1
;
276 dev
->cbm
.free_cell_cnt
= cbm_free_cell_no
;
279 dev
->qsb
.tau
= qsb_tau
;
280 dev
->qsb
.tstepc
=qsb_tstep
;
281 dev
->qsb
.sbl
= qsb_srvm
;
283 //allocate on the fly
284 dev
->cbm
.mem_addr
= NULL
;
285 dev
->cbm
.qd_addr
= NULL
;
289 /* Brief: Find QID for VCC
290 * Parameters: vcc - VCC data structure
291 * Return Value: -EINVAL - VCC not found
292 * qid - QID for this VCC
294 * This function returns the QID of a given VCC
296 static int amazon_atm_get_queue(struct atm_vcc
* vcc
)
299 for (i
=0;i
<AMAZON_ATM_MAX_QUEUE_NUM
;i
++) {
300 if (g_atm_dev
.queues
[i
].vcc
== vcc
) return i
;
307 * Brief: Find QID for VPI/VCI
308 * Parameters: vpi - VPI to found
311 * Return Value: -EINVAL - VPI/VCI not found
312 * qid - QID for this VPI/VCI
315 * This function returns the QID for a given VPI/VCI. itf doesn't matter
317 static int amazon_atm_find_vpivci(u8 vpi
, u16 vci
)
320 struct atm_vcc
* vcc
;
321 for (i
=0;i
<AMAZON_ATM_MAX_QUEUE_NUM
;i
++) {
322 if ( (vcc
= g_atm_dev
.queues
[i
].vcc
)!= NULL
) {
323 if ((vcc
->vpi
== vpi
) && (vcc
->vci
== vci
)) return i
;
329 /* Brief: Find QID for VPI
330 * Parameters: vpi - VPI to found
331 * Return Value: -EINVAL - VPI not found
332 * qid - QID for this VPI
335 * This function returns the QID for a given VPI. itf and VCI don't matter
337 static int amazon_atm_find_vpi(u8 vpi
)
340 for (i
=0;i
<AMAZON_ATM_MAX_QUEUE_NUM
;i
++) {
341 if ( g_atm_dev
.queues
[i
].vcc
!= NULL
) {
342 if (g_atm_dev
.queues
[i
].vcc
->vpi
== vpi
) return i
;
349 * Brief: Clears QID entries for VCC
351 * Parameters: vcc - VCC to found
354 * This function searches for the given VCC and sets it to NULL if found.
356 static inline void amazon_atm_clear_vcc(int i
)
358 g_atm_dev
.queues
[i
].vcc
= NULL
;
359 g_atm_dev
.queues
[i
].free
= 1;
364 * Brief: dump skb data
366 static inline void dump_skb(u32 len
, char * data
)
368 #ifdef AMAZON_TPE_DUMP
371 printk("%2.2x ",(u8
)(data
[i
]));
380 * Brief: dump queue descriptor
382 static inline void dump_qd(int qid
)
384 #ifdef AMAZON_TPE_DUMP
386 if (valid_qid(qid
) != 1) return;
387 qd_addr
= (u8
*) KSEG1ADDR((unsigned long)g_atm_dev
.cbm
.qd_addr
);
388 AMAZON_TPE_EMSG("qid: %u [%8x][%8x][%8x][%8x]\n", qid
389 ,readl(qd_addr
+qid
*CBM_QD_SIZE
+0x0)
390 ,readl(qd_addr
+qid
*CBM_QD_SIZE
+0x4)
391 ,readl(qd_addr
+qid
*CBM_QD_SIZE
+0x8)
392 ,readl(qd_addr
+qid
*CBM_QD_SIZE
+0xc));
397 * Brief: release TX skbuff
399 static inline void amazon_atm_free_tx_skb_vcc(struct atm_vcc
*vcc
, struct sk_buff
*skb
)
401 if ( vcc
->pop
!= NULL
) {
404 dev_kfree_skb_any(skb
);
408 * Brief: release TX skbuff
410 static inline void amazon_atm_free_tx_skb(struct sk_buff
*skb
)
412 struct atm_vcc
* vcc
= ATM_SKB(skb
)->vcc
;
414 amazon_atm_free_tx_skb_vcc(vcc
,skb
);
416 dev_kfree_skb_any(skb
);//fchang:Added
420 /* Brief: divide by 64 and round up
422 static inline u32
divide_by_64_round_up(int input
)
426 tmp1
= (tmp1
%64)?(tmp1
/64 + 1): (tmp1
/64);
427 if (tmp1
== 0) tmp1
= 1;
434 #ifdef AMAZON_ATM_DEBUG
435 static inline void queue_statics(int qid
, qs_t idx
)
438 g_atm_dev
.queues
[qid
].qs
[idx
]++;
441 #else //not AMAZON_ATM_DEBUG
442 static inline void queue_statics(int qid
, qs_t idx
){}
443 #endif //AMAZON_ATM_DEBUG
446 /* Brief: set dma tx full, i.e. there is no available descriptors
448 static void inline atm_dma_full(void)
450 AMAZON_TPE_DMSG("ch0 is full\n");
451 atomic_set(&g_atm_dev
.dma_tx_free_0
,0);
455 * Brief set dma tx free (at least one descript is available)
457 inline static void atm_dma_free(void)
459 AMAZON_TPE_DMSG("ch0 is free\n");
460 atomic_set(&g_atm_dev
.dma_tx_free_0
,1);
464 /* Brief: return the status of DMA TX descriptors
465 * Parameters: TX channel (DMA_TX_CH0, TX_CH1)
467 * 1: there are availabel TX descriptors
472 inline int dma_may_send(int ch
)
474 if (atomic_read(&g_atm_dev
.dma_tx_free_0
)){
480 /******************************* global functions *********************************/
482 * Brief: SWIE Cell Extraction Start Routine
483 * and task routine for swex_complete_task
484 * Parameters: irq_stat - interrupt status
487 * This is the routine for extracting cell. It will schedule itself if the hardware is busy.
488 * This routine runs in interrupt context
490 void amazon_atm_swex(void * irq_stat
)
494 // Read extraction status register
495 ex_stat
= readl(CBM_HWEXSTAT0_ADDR
);
497 // Check if extraction/insertion is in progress
498 if ( (ex_stat
& CBM_EXSTAT_SCB
) || (ex_stat
& CBM_EXSTAT_FB
) || (test_and_set_bit(SWIE_LOCK
, &(g_atm_dev
.swie
.lock
))!=0)) {
499 AMAZON_TPE_DMSG(" extraction in progress. Will wait\n");
500 swex_start_task
.data
= irq_stat
;
501 queue_task(&swex_start_task
, &tq_immediate
);
502 mark_bh(IMMEDIATE_BH
);
505 g_atm_dev
.swie
.qid
= (((u32
)irq_stat
) >> 24);
506 AMAZON_TPE_DMSG("extracting from qid=%u\n",g_atm_dev
.swie
.qid
);
508 addr
= KSEG1ADDR((unsigned long)g_atm_dev
.cbm
.qd_addr
);
509 addr
= readl((addr
+ g_atm_dev
.swie
.qid
* 0x10 + 4) & 0xFFFFFFC0);
510 addr
= KSEG1ADDR(addr
);
511 g_atm_dev
.swie
.sw
= readl(addr
+52)&SWIE_ADDITION_DATA_MASK
;
512 AMAZON_TPE_DMSG("cell addition word: %8x \n", g_atm_dev
.swie
.sw
);
515 AMAZON_WRITE_REGISTER_L(g_atm_dev
.swie
.qid
| SWIE_CBM_PID_SUBADDR
, CBM_HWEXPAR0_ADDR
);
516 AMAZON_WRITE_REGISTER_L(SWIE_CBM_SCE0
, CBM_HWEXCMD_ADDR
);
519 #ifdef AMAZON_TPE_SCR
522 * Brief: AAL5 Packet Extraction Routine and task routine for a5r_task
523 * Parameters: irq_stat - interrupt status
526 * This is the routine for extracting frame. It will schedule itself if the hardware is busy.
527 * This routine runs in interrupt context
529 void amazon_atm_a5r(void* qid
)
531 volatile u32 ex_stat
=0;
535 ex_stat
= readl(CBM_HWEXSTAT0_ADDR
);
537 // Check if extraction/insertion is in progress
538 if ( (ex_stat
& CBM_EXSTAT_SCB
) || (ex_stat
& CBM_EXSTAT_FB
) ) {
539 AMAZON_TPE_DMSG(" extraction in progress. Will wait\n");
541 queue_task(&a5r_task
, &tq_immediate
);
542 mark_bh(IMMEDIATE_BH
);
544 AMAZON_TPE_DMSG("extracting from qid=%u\n",(u8
)qid
);
546 AMAZON_WRITE_REGISTER_L(((u8
)qid
) | CBM_HWEXPAR_PN_A5
, CBM_HWEXPAR0_ADDR
);
547 AMAZON_WRITE_REGISTER_L(CBM_HWEXCMD_FE0
, CBM_HWEXCMD_ADDR
);
550 //while ( (ex_stat & CBM_EXSTAT_SCB) || (ex_stat & CBM_EXSTAT_FB) ) {
551 while ( ex_stat
!= 0x80){
553 ex_stat
= readl(CBM_HWEXSTAT0_ADDR
);
555 if (a5r_wait
>= 0xffffff){
561 if (a5r_wait
> g_a5r_wait
){
562 g_a5r_wait
= a5r_wait
;
564 AMAZON_WRITE_REGISTER_L(((u8
)qid
) | CBM_HWEXPAR_PN_A5
, CBM_HWEXPAR0_ADDR
);
565 AMAZON_WRITE_REGISTER_L(CBM_HWEXCMD_FE0
, CBM_HWEXCMD_ADDR
);
569 #endif //AMAZON_TPE_SCR
571 /* Brief: Handle F4/F5 OAM cell
576 static int inline amazon_handle_oam_cell(void *data
, u8 vpi
, u16 vci
,u32 status
)
578 struct atm_vcc
* vcc
=NULL
;
580 if (!status
&SWIE_EOAM_MASK
){
581 AMAZON_TPE_EMSG("unknown cell received, discarded\n");
582 goto amazon_handle_oam_cell_err_exit
;
583 }else if (status
&SWIE_ECRC10ERROR_MASK
){
584 AMAZON_TPE_EMSG("CRC-10 Error Status:%8x, discarded\n", status
);
585 goto amazon_handle_oam_cell_err_exit
;
587 if(status
& (SWIE_EVCI3_MASK
|SWIE_EVCI4_MASK
)){
588 //F4 level (VPI) OAM, Assume duplex
589 qid
= amazon_atm_find_vpi(vpi
)+CBM_RX_OFFSET
;
590 }else if (status
& (SWIE_EPTI4_MASK
|SWIE_EPTI5_MASK
)){
591 //F5 level (VCI) OAM, Assume duplex
592 qid
= amazon_atm_find_vpivci(vpi
,vci
)+CBM_RX_OFFSET
;
595 AMAZON_TPE_EMSG("non-F4/F5 OAM cells?, discarded\n");
596 goto amazon_handle_oam_cell_err_exit
;
599 if (valid_qid(qid
) && ((vcc
= g_atm_dev
.queues
[qid
].vcc
)!=NULL
)){
600 //TODO, should we do this for ALL OAM types? (Actually only User and CC)
601 g_atm_dev
.queues
[qid
].access_time
=xtime
;
603 (*vcc
->push_oam
)(vcc
,data
);
608 AMAZON_TPE_EMSG("no VCC yet\n");
609 goto amazon_handle_oam_cell_err_exit
;
612 amazon_handle_oam_cell_err_exit
:
613 dump_skb(AMAZON_AAL0_SDU
,(char *)data
);
617 /* Brief: SWIE Cell Extraction Finish Routine
618 * and task routine for swex_complete_task
620 * 1.Allocate a buffer of type struct sk_buff
621 * 2.Copy the data from the temporary memory to this buffer
622 * 3.Push the data to upper layer
623 * 4.Update the statistical data if necessary
624 * 5.Release the temporary data
627 void amazon_atm_swex_push(void * data
)
629 struct atm_vcc
* vcc
=NULL
;
630 struct sk_buff
* skb
=NULL
;
631 struct amazon_atm_cell_header
* cell_header
;
635 AMAZON_TPE_EMSG("data is NULL\n");
638 qid
= ((u8
*)data
)[AMAZON_AAL0_SDU
];
639 status
= ((u32
*)data
)[ATM_AAL0_SDU
/4];
640 cell_header
= (struct amazon_atm_cell_header
*) data
;
641 if (valid_qid(qid
) != 1){
642 AMAZON_TPE_EMSG("error qid: %u\n",qid
);
643 AMAZON_TPE_EMSG("unknown cells recieved\n");
644 }else if (qid
== AMAZON_ATM_OAM_Q_ID
){
645 //OAM or RM or OTHER cell
646 //Find real connection
648 #ifdef IKOS_MINI_BOOT
649 //for OAM loop back test
650 dump_skb(56,(char *)data
);
651 //kfree(data); using g_oam_cell
653 #endif //IKOS_MINI_BOOT
659 ret
= amazon_handle_oam_cell(data
,cell_header
->bit
.vpi
,cell_header
->bit
.vci
,status
);
663 //should be normal AAL0 cells
665 vcc
= g_atm_dev
.queues
[qid
].vcc
;
667 AMAZON_TPE_DMSG("push to upper layer\n");
668 skb
= dev_alloc_skb(AMAZON_AAL0_SDU
);
671 memcpy(skb_put(skb
, AMAZON_AAL0_SDU
), data
, AMAZON_AAL0_SDU
);
673 ATM_SKB(skb
)->vcc
= vcc
;
674 (*g_atm_dev
.queues
[qid
].push
)(vcc
,skb
,0);
676 AMAZON_TPE_EMSG(" No memory left for incoming AAL0 cell! Cell discarded!\n");
677 //inform the upper layer
678 (*g_atm_dev
.queues
[qid
].push
)(vcc
,skb
,-ENOMEM
);
679 atomic_inc(&vcc
->stats
->rx_drop
);
682 AMAZON_TPE_EMSG("invalid qid %u\n",qid
);
685 //kfree(data); using g_oam_cell
689 * Brief: Interrupt handler for software cell extraction (done)
690 * Parameters: irq - CPPN for this interrupt
691 * data - Device ID for this interrupt
692 * regs - Register file
695 * When a software extraction is finished this interrupt is issued.
696 * It reads the cell data and sends it to the ATM stack.
698 void amazon_atm_swex_isr(int irq
, void *data
, struct pt_regs
*regs
)
703 AMAZON_TPE_DMSG("SWIE extraction done\n");
704 cell
= (u32
*) g_oam_cell
;
706 //convert to host byte order from big endian
707 for(i
=0;i
<ATM_AAL0_SDU
;i
+=4){
708 cell
[i
/4]=readl(SWIE_ECELL_ADDR
+i
);
710 cell
[ATM_AAL0_SDU
/4]= g_atm_dev
.swie
.sw
;
711 ((u8
*)cell
)[AMAZON_AAL0_SDU
] = g_atm_dev
.swie
.qid
;
712 #ifdef IKOS_MINI_BOOT
713 for(i
=0;i
<ATM_AAL0_SDU
;i
+=4){
714 AMAZON_TPE_DMSG("[%2x][%2x][%2x][%2x]\n",
721 AMAZON_TPE_DMSG("qid: %u\n", ((u8
*)cell
)[AMAZON_AAL0_SDU
]);
722 amazon_atm_swex_push((void *) cell
);
723 #else //not IKOS_MINI_BOOT
724 swex_complete_task
.data
= cell
;
725 queue_task(&swex_complete_task
,&tq_immediate
);
726 mark_bh(IMMEDIATE_BH
);
727 #endif //not IKOS_MINI_BOOT
729 AMAZON_TPE_EMSG("no memory for receiving AAL0 cell\n");
732 /* release the lock and check */
733 if (test_and_clear_bit(SWIE_LOCK
,&(g_atm_dev
.swie
.lock
)) == 0){
734 AMAZON_TPE_EMSG("swie lock is already released\n");
736 wake_up(&g_atm_dev
.swie
.sleep
);
738 /* Brief: Interrupt handler for software cell insertion
740 * Parameters: irq - CPPN for this interrupt
741 * data - Device ID for this interrupt
742 * regs - Register file
745 * When a software insertion is finished this interrupt is issued.
746 * The only purpose is to release the semaphore and read the status register.
748 void amazon_atm_swin_isr(int irq
, void *data
, struct pt_regs
*regs
)
750 AMAZON_TPE_DMSG("SWIE insertion done\n");
751 /* release the lock and check */
752 if (test_and_clear_bit(SWIE_LOCK
,&(g_atm_dev
.swie
.lock
)) == 0){
753 AMAZON_TPE_EMSG("swie lock is already released");
756 up(&g_atm_dev
.swie
.in_sem
);
759 /* Brief: Interrupt handler for software cell insertion & extraction
760 * Parameters: irq - CPPN for this interrupt
761 * data - Device ID for this interrupt
762 * regs - Register file
764 * When a software insertion or extractionis finished this interrupt is issued.
766 void amazon_atm_swie_isr(int irq
, void *data
, struct pt_regs
*regs
)
769 // Read status register
770 status
= readl(SWIE_ISTAT_ADDR
);
771 AMAZON_TPE_DMSG("insertion status: %8x\n", status
);
772 if (status
& SWIE_ISTAT_DONE
){
773 //clear interrupt in peripheral and ICU
774 AMAZON_WRITE_REGISTER_L(SRC_TOS_MIPS
| SRC_CLRR
|SRC_SRE_ENABLE
| AMAZON_SWIE_INT
, SWIE_ISRC_ADDR
);
775 mask_and_ack_amazon_irq(AMAZON_SWIE_INT
);
777 amazon_atm_swin_isr(irq
,data
,regs
);
779 status
= readl(SWIE_ESTAT_ADDR
);
780 AMAZON_TPE_DMSG("extraction status: %8x\n", status
);
781 if (status
& SWIE_ESTAT_DONE
){
783 AMAZON_WRITE_REGISTER_L(SRC_TOS_MIPS
| SRC_CLRR
|SRC_SRE_ENABLE
| AMAZON_SWIE_INT
, SWIE_ESRC_ADDR
);
784 mask_and_ack_amazon_irq(AMAZON_SWIE_INT
);
786 amazon_atm_swex_isr(irq
,data
,regs
);
788 //clear interrupt in ICU
792 * Brief: Insert ATM cell into CBM
793 * Parameters: queue - Target queue
794 * cell - Pointer to cell data
795 * Return Value: EBUSY - CBM is busy
796 * 0 - OK, cell inserted
798 * This function inserts a cell into the CBM using the software insertion
799 * method. The format of the cell should be
800 * Little Endian (address starting from 0)
801 * H3, H2, H1, H0, P3, P2, P1, P0, P7, P6, P5, P4, ..., P47, P46, P45, P44
802 * Big Endian (address starting from 0)
803 * H0, H1, H2, H3, P0, P1, P2, P3, P4, P5, P6, P7, ..., P44, P45, P46, P47
804 * This function does not free memory!!!
806 int amazon_atm_swin(u8 queue
, void* cell
)
810 // Read status register
811 status
= readl(SWIE_ISTAT_ADDR
);
812 AMAZON_TPE_DMSG(" SWIE status=0x%08x\n",status
);
814 AMAZON_TPE_DMSG(" Inserting cell qid=%u\n",queue
);
816 #ifdef AMAZON_CHECK_LINK
817 if (adsl_link_status
== 0){
820 #endif //AMAZON_CHECK_LINK
822 // Get semaphore (if possible)
823 if (down_interruptible(&g_atm_dev
.swie
.in_sem
)) {
826 /* try to set lock */
827 wait_event_interruptible(g_atm_dev
.swie
.sleep
,(test_and_set_bit(SWIE_LOCK
,&(g_atm_dev
.swie
.lock
)) == 0));
828 if (signal_pending(current
)){
832 // Store cell in CBM memory
833 for(i
=0;i
<ATM_AAL0_SDU
;i
+=4){
834 AMAZON_WRITE_REGISTER_L(((u32
*)cell
)[i
/4],SWIE_ICELL_ADDR
+i
);
837 AMAZON_WRITE_REGISTER_L((u32
) queue
,SWIE_IQID_ADDR
);
840 AMAZON_WRITE_REGISTER_L(SWIE_ICMD_START
,SWIE_ICMD_ADDR
);
845 #ifdef AMAZON_ATM_DEBUG
847 * Brief: Interrupt handler for HTU
849 * Parameters: irq - CPPN for this interrupt
850 * data - Device ID for this interrupt
851 * regs - Register file
854 void amazon_atm_htu_isr(int irq
, void *data
, struct pt_regs
*regs
)
858 // Read interrupt status register
859 irq_stat
= readl(HTU_ISR0_ADDR
);
860 AMAZON_TPE_DMSG("HTU status: %8x\n",irq_stat
);
861 //Clear interrupt in CBM and ICU
862 AMAZON_WRITE_REGISTER_L(SRC_CLRR
|SRC_TOS_MIPS
| SRC_SRE_ENABLE
| AMAZON_HTU_INT
, HTU_SRC0_ADDR
);
863 mask_and_ack_amazon_irq(AMAZON_HTU_INT
);
864 // Check if Any Cell Arrived
865 if (irq_stat
& (HTU_ISR_NE
| HTU_ISR_PNE
) ) {
866 AMAZON_TPE_EMSG("INFNOENTRY %8x\n", readl(HTU_INFNOENTRY_ADDR
));
867 }else if (irq_stat
& (HTU_ISR_TORD
|HTU_ISR_PT
)){
868 AMAZON_TPE_EMSG("Time Out %8x\n", readl(HTU_INFTIMEOUT_ADDR
));
869 }else if (irq_stat
& HTU_ISR_IT
){
870 AMAZON_TPE_EMSG("Interrupt Test\n");
871 }else if (irq_stat
& HTU_ISR_OTOC
){
872 AMAZON_TPE_EMSG("Overflow of Time Out Counter\n");
873 }else if (irq_stat
& HTU_ISR_ONEC
){
874 AMAZON_TPE_EMSG("Overflow of No Entry Counter\n");
876 AMAZON_TPE_EMSG("unknown HTU interrupt occurs %8x\n", irq_stat
);
880 #endif //AMAZON_ATM_DEBUG
882 #ifdef AMAZON_TPE_TEST_AAL5_INT
884 * Brief: Interrupt handler for AAL5
886 * Parameters: irq - CPPN for this interrupt
887 * data - Device ID for this interrupt
888 * regs - Register file
891 void amazon_atm_aal5_isr(int irq
, void *data
, struct pt_regs
*regs
)
893 volatile u32 irq_stat
=0;
895 // Read interrupt status register
896 irq_stat
= readl(AAL5_SISR0_ADDR
);
898 AMAZON_TPE_EMSG("A5S status: %8x\n",irq_stat
);
899 //Clear interrupt in CBM and ICU
900 AMAZON_WRITE_REGISTER_L(SRC_CLRR
|SRC_TOS_MIPS
| SRC_SRE_ENABLE
| AMAZON_AAL5_INT
, AAL5_SSRC0_ADDR
);
901 mask_and_ack_amazon_irq(AMAZON_AAL5_INT
);
903 irq_stat
= readl(AAL5_RISR0_ADDR
);
905 AMAZON_TPE_EMSG("A5R status: %8x\n",irq_stat
);
906 //Clear interrupt in CBM and ICU
907 AMAZON_WRITE_REGISTER_L(SRC_CLRR
|SRC_TOS_MIPS
| SRC_SRE_ENABLE
| AMAZON_AAL5_INT
, AAL5_RSRC0_ADDR
);
908 mask_and_ack_amazon_irq(AMAZON_AAL5_INT
);
911 #endif //AMAZON_TPE_TEST_AAL5_INT
914 * Brief: Interrupt handler for CBM
916 * Parameters: irq - CPPN for this interrupt
917 * data - Device ID for this interrupt
918 * regs - Register file
921 * This is the MIPS interrupt handler for the CBM. It processes incoming cells
924 void amazon_atm_cbm_isr(int irq
, void *data
, struct pt_regs
*regs
)
929 // Read interrupt status register
930 while ( (irq_stat
= readl(CBM_INTINF0_ADDR
))){
931 AMAZON_TPE_DMSG("CBM INT status: %8x\n",irq_stat
);
932 //Clear interrupt in CBM and ICU
933 AMAZON_WRITE_REGISTER_L(SRC_CLRR
|SRC_TOS_MIPS
| SRC_SRE_ENABLE
| AMAZON_CBM_INT
, CBM_SRC0_ADDR
);
934 qid
= (u8
) ((irq_stat
& CBM_INTINF0_QID_MASK
)>>CBM_INTINF0_QID_SHIFT
);
935 #ifdef AMAZON_TPE_SCR
936 if (irq_stat
& CBM_INTINF0_EF
){
937 amazon_atm_a5r((void*)qid
);
940 // Check if Any Cell Arrived
941 if (irq_stat
& CBM_INTINF0_ACA
) {
942 amazon_atm_swex((void *)irq_stat
);
944 //TX AAL5 PDU discard
945 if (irq_stat
& CBM_INTINF0_OPF
){
946 if ( (qid
) < CBM_RX_OFFSET
){
947 g_atm_dev
.mib_counter
.tx_drop
++;
949 queue_statics(qid
, QS_HW_DROP
);
951 if (irq_stat
& (CBM_INTINF0_ERR
|CBM_INTINF0_Q0E
|CBM_INTINF0_Q0I
|CBM_INTINF0_RDE
)){
952 AMAZON_TPE_EMSG("CBM INT status: %8x\n",irq_stat
);
953 if (irq_stat
& CBM_INTINF0_ERR
){
954 AMAZON_TPE_EMSG("CBM Error: FPI Bus Error\n");
956 if (irq_stat
& CBM_INTINF0_Q0E
){
957 AMAZON_TPE_EMSG("CBM Error: Queue 0 Extract\n");
959 if (irq_stat
& CBM_INTINF0_Q0I
){
960 AMAZON_TPE_EMSG("CBM Error: Queue 0 Extract\n");
962 if (irq_stat
& CBM_INTINF0_RDE
){
963 AMAZON_TPE_EMSG("CBM Error: Read Empty Queue %u\n",qid
);
968 mask_and_ack_amazon_irq(AMAZON_CBM_INT
);
971 /* Brief: check the status word after AAL SDU after reassembly
973 static inline void check_aal5_error(u8 stw0
, u8 stw1
, int qid
)
975 if (stw0
& AAL5_STW0_MFL
){
976 AMAZON_TPE_DMSG("Maximum Frame Length\n");
977 g_atm_dev
.queues
[qid
].aal5VccOverSizedSDUs
++;
979 if (stw0
& AAL5_STW0_CRC
){
980 AMAZON_TPE_DMSG("CRC\n");
981 g_atm_dev
.queues
[qid
].aal5VccCrcErrors
++;
983 #ifdef AMAZON_ATM_DEBUG_RX
984 AMAZON_TPE_EMSG("qid:%u stw0:%8x stw1:%8x\n",qid
,stw0
,stw1
);
988 /* Brief: Process DMA rx data
990 dma_dev: pointer to the dma_device_info, provided by us when register the dma device
992 * Description: DMA interrupt handerl with OoS support. It is called when there is some data in rx direction.
995 //507261:tc.chen void atm_process_dma_rx(struct dma_device_info* dma_dev)
996 void __system
atm_process_dma_rx(struct dma_device_info
* dma_dev
)
1003 struct sk_buff
* skb
=NULL
;
1004 struct atm_vcc
* vcc
=NULL
;
1006 #ifdef AMAZON_ATM_DEBUG_RX
1007 static int dma_rx_dump
=0;
1012 printk("\n=========================[%u]=========================\n",seq
);
1015 length
=dma_device_read(dma_dev
,&head
,(void**)&skb
);
1016 AMAZON_TPE_DMSG("receive %8p[%u] from DMA\n", head
,length
);
1017 if (head
== NULL
||length
<=0) {
1018 AMAZON_TPE_DMSG("dma_read null \n");
1022 if (length
> (g_atm_dev
.aal5
.rx_max_sdu
+64)){
1023 AMAZON_TPE_EMSG("received packet too large (%u)\n",length
);
1026 //check AAL5R trail for error and qid
1029 qid
= (int) head
[length
];
1030 AMAZON_TPE_DMSG("head[%u] qid %u\n",length
, qid
);
1031 //STW0 is always 4 bytes before qid
1033 stw0
= head
[length
]&0xff;
1034 AMAZON_TPE_DMSG("head[%u] stw0 %8x\n",length
, stw0
);
1035 //position of STW1 depends on the BE bits
1036 length
= length
-4 + (stw0
&AAL5_STW0_BE
);
1037 stw1
= head
[length
]&0xff;
1038 AMAZON_TPE_DMSG("head[%u] stw1 %8x\n",length
, stw1
);
1039 if ( (stw0
& AAL5_STW0_MASK
) || (stw1
& AAL5_STW1_MASK
) ){
1041 check_aal5_error(stw0
, stw1
,qid
);
1044 //make data pointers consistent
1047 AMAZON_TPE_DMSG("packet length %u\n", length
);
1049 //error: cannot restore the qid
1050 if (valid_qid(qid
) != 1){
1051 AMAZON_TPE_EMSG("received frame in invalid qid %u!\n", qid
);
1054 vcc
= g_atm_dev
.queues
[qid
].vcc
;
1056 AMAZON_TPE_EMSG("received frame in invalid vcc, qid=%u!\n",qid
);
1060 AMAZON_TPE_EMSG("cannot restore skb pointer!\n");
1063 skb_put(skb
,length
);
1065 g_atm_dev
.queues
[qid
].access_time
=xtime
;
1066 if ((*g_atm_dev
.queues
[qid
].push
)(vcc
,skb
,0)){
1067 g_atm_dev
.mib_counter
.rx_drop
++;
1068 queue_statics(qid
, QS_SW_DROP
);
1070 g_atm_dev
.mib_counter
.rx
++;
1071 adsl_led_flash();//joelin adsl led
1072 queue_statics(qid
, QS_PKT
);
1073 AMAZON_TPE_DMSG("push successful!\n");
1075 #ifdef AMAZON_ATM_DEBUG_RX
1077 printk("\nOK packet [dump=%u] length=%u\n",dma_rx_dump
,length
);
1078 dump_skb(length
+7, head
);
1080 if (dma_rx_dump
>0) dma_rx_dump
--;
1084 #ifdef AMAZON_ATM_DEBUG_RX
1085 if ( (head
!=NULL
) && (length
>0)){
1086 AMAZON_TPE_EMSG("length=%u\n",length
);
1087 dump_skb(length
+5, head
);
1091 g_atm_dev
.mib_counter
.rx_err
++;
1092 queue_statics(qid
, QS_ERR
);
1095 (*g_atm_dev.queues[qid].push)(vcc,skb,1);
1099 dev_kfree_skb_any(skb
);
1104 /*Brief: ISR for DMA pseudo interrupt
1106 dma_dev: pointer to the dma_device_info, provided by us when register the dma device
1108 RCV_INT: rx data available
1109 TX_BUF_FULL_INT: tx descriptor run out of
1110 TRANSMIT_CPT_INT: tx descriptor available again
1114 //507261:tc.chen int amazon_atm_dma_handler(struct dma_device_info* dma_dev, int intr_status)
1115 int __system
amazon_atm_dma_handler(struct dma_device_info
* dma_dev
, int intr_status
)
1117 AMAZON_TPE_DMSG("status:%u\n",intr_status
);
1118 switch (intr_status
) {
1120 atm_process_dma_rx(dma_dev
);
1122 case TX_BUF_FULL_INT
:
1123 //TX full: no descriptors
1126 case TRANSMIT_CPT_INT
:
1127 //TX free: at least one descriptor
1131 AMAZON_TPE_EMSG("unknown status!\n");
1136 /*Brief: free buffer for DMA tx
1138 dataptr: pointers to data buffer
1139 opt: optional parameter, used to convey struct skb pointer, passwd in dma_device_write
1143 called by DMA module to release data buffer after DMA tx transaction
1145 cannot restore skb pointer
1147 int amazon_atm_free_tx(u8
*dataptr
, void* opt
)
1149 struct sk_buff
*skb
;
1151 AMAZON_TPE_DMSG("free skb%8p\n",opt
);
1152 skb
= (struct sk_buff
*)opt
;
1153 amazon_atm_free_tx_skb(skb
);
1155 AMAZON_TPE_EMSG("BUG: cannot restore skb pointer!\n");
1160 /*Brief: allocate buffer & do alignment
1162 inline struct sk_buff
* amazon_atm_alloc_buffer(int len
)
1164 struct sk_buff
*skb
;
1165 skb
= dev_alloc_skb(len
+16);
1167 //alignment requriements (4x32 bits (16 bytes) boundary)
1168 alloc_align_16(skb
);
1173 /*Brief: allocate buffer for DMA rx
1176 opt: optional data to convey the skb pointer, which will be returned to me in interrupt handler,
1178 pointer to buffer, NULL means error?
1180 must make sure byte alignment
1183 u8
* amazon_atm_alloc_rx(int len
, int* offset
, void **opt
)
1185 struct sk_buff
*skb
;
1187 skb
= amazon_atm_alloc_buffer(len
);
1189 AMAZON_TPE_DMSG("alloc skb->data:%8p len:%u\n",skb
->data
,len
);
1190 *(struct sk_buff
**)opt
= skb
;
1192 AMAZON_TPE_DMSG("no memory for receiving atm frame!\n");
1201 /* Brief: Allocate kernel memory for sending a datagram.
1203 * vcc virtual connection
1204 * size data buffer size
1207 * sk_buff a pointer to a sk_buff
1209 * This function can allocate our own additional memory for AAL5S inbound
1210 * header (8bytes). We have to replace the protocol default one (alloc_tx in /net/atm/common.c)
1211 * when we open the device.
1212 * byte alignment is done is DMA driver.
1214 struct sk_buff
*amazon_atm_alloc_tx(struct atm_vcc
*vcc
,unsigned int size
)
1216 struct sk_buff
*skb
;
1218 if (!dma_may_send(DMA_TX_CH0
)){
1219 AMAZON_TPE_EMSG("no DMA descriptor available!\n");
1222 //AAL5 inbound header space + alignment extra buffer
1223 size
+=8+AAL5S_INBOUND_HEADER
;
1225 if (atomic_read(&vcc
->tx_inuse
) && !atm_may_send(vcc
,size
)) {
1226 AMAZON_TPE_EMSG("Sorry tx_inuse = %u, size = %u, sndbuf = %u\n",
1227 atomic_read(&vcc
->tx_inuse
),size
,vcc
->sk
->sndbuf
);
1231 skb
= amazon_atm_alloc_buffer(size
);
1233 AMAZON_TPE_EMSG("no memory\n");
1236 AMAZON_TPE_DMSG("dev_alloc_skb(%u) = %x\n", skb
->len
, (u32
)skb
);
1237 AMAZON_TPE_DMSG("tx_inuse %u += %u\n",atomic_read(&vcc
->tx_inuse
),skb
->truesize
);
1238 atomic_add(skb
->truesize
+ATM_PDU_OVHD
,&vcc
->tx_inuse
);
1240 //reserve for AAL5 inbound header
1241 skb_reserve(skb
,AAL5S_INBOUND_HEADER
);
1246 /* Brief: change per queue QSB setting according to vcc qos parameters
1248 * vcc: atm_vcc pointer
1249 * qid: CBM queue id (1~15)
1252 static inline void set_qsb(struct atm_vcc
*vcc
, struct atm_qos
*qos
, int qid
)
1257 unsigned int qsb_clk
;
1259 qsb_clk
= amazon_get_fpi_hz()>>1;
1261 AMAZON_TPE_EMSG("Class=%u MAX_PCR=%u PCR=%u MIN_PCR=%u SCR=%u MBS=%u CDV=%u\n"
1262 ,qos
->txtp
.traffic_class
1272 if (qos
->txtp
.max_pcr
== 0){
1273 qptl
.bit
.tprs
= 0; /* 0 disables the PCR limiter */
1275 // peak cell rate will be slightly lower than requested (maximum rate / pcr)= (qsbclock/2^3 * timestep/4)/pcr
1276 tmp
= (( (qsb_clk
* g_atm_dev
.qsb
.tstepc
)>>5)/ qos
->txtp
.max_pcr
) + 1;
1277 // check if an overfow occured
1278 if (tmp
> QSB_TP_TS_MAX
) {
1279 AMAZON_TPE_EMSG("max_pcr is too small, max_pcr:%u tprs:%u\n",qos
->txtp
.max_pcr
, tmp
);
1280 qptl
.bit
.tprs
= QSB_TP_TS_MAX
;
1282 qptl
.bit
.tprs
= tmp
;
1286 if (qos
->txtp
.traffic_class
== ATM_CBR
|| qos
->txtp
.traffic_class
==ATM_VBR_RT
){
1287 // real time queue gets weighted fair queueing bypass
1289 }else if (qos
->txtp
.traffic_class
==ATM_VBR_NRT
||qos
->txtp
.traffic_class
==ATM_UBR_PLUS
){
1290 // wfq calculation here are based on virtual cell rates, to reduce granularity for large rates
1291 // wfq factor is maximum cell rate / garenteed cell rate.
1292 //qptl.bit.twfq = g_atm_dev.qsb.min_cr * QSB_WFQ_NONUBR_MAX / qos->txtp.min_pcr;
1293 if (qos
->txtp
.min_pcr
== 0) {
1294 AMAZON_TPE_EMSG("<warning> MIN_PCR should not be zero\n");
1295 qptl
.bit
.twfq
= QSB_WFQ_NONUBR_MAX
;
1297 tmp
= QSB_GCR_MIN
* QSB_WFQ_NONUBR_MAX
/ qos
->txtp
.min_pcr
;
1300 }else if (tmp
> QSB_WFQ_NONUBR_MAX
){
1301 AMAZON_TPE_EMSG("min_pcr is too small, min_pcr:%u twfq:%u\n",qos
->txtp
.min_pcr
, tmp
);
1302 qptl
.bit
.twfq
= QSB_WFQ_NONUBR_MAX
;
1304 qptl
.bit
.twfq
= tmp
;
1307 }else if (qos
->txtp
.traffic_class
== ATM_UBR
){
1308 // ubr bypass, twfq set to maximum value
1309 qptl
.bit
.twfq
= QSB_WFQ_UBR_BYPASS
;
1311 //tx is diabled, treated as UBR
1312 AMAZON_TPE_EMSG("<warning> unsupported traffic class %u \n", qos
->txtp
.traffic_class
);
1313 qos
->txtp
.traffic_class
= ATM_UBR
;
1314 qptl
.bit
.twfq
= QSB_WFQ_UBR_BYPASS
;
1317 //SCR Leaky Bucket Shaper VBR.0/VBR.1
1318 if (qos
->txtp
.traffic_class
==ATM_VBR_RT
|| qos
->txtp
.traffic_class
==ATM_VBR_NRT
){
1319 if (qos
->txtp
.scr
== 0){
1320 //SCR == 0 disable the shaper
1325 if (vcc
->atm_options
&ATM_ATMOPT_CLP
){
1333 tmp
= (( (qsb_clk
* g_atm_dev
.qsb
.tstepc
)>>5)/ qos
->txtp
.scr
) + 1;
1334 if (tmp
> QSB_TP_TS_MAX
) {
1335 AMAZON_TPE_EMSG("scr is too small, scr:%u ts:%u\n",qos
->txtp
.scr
, tmp
);
1336 qvpt
.bit
.ts
= QSB_TP_TS_MAX
;
1340 tmp
= (qos
->txtp
.mbs
- 1)*(qvpt
.bit
.ts
- qptl
.bit
.tprs
)/64;
1341 if (tmp
> QSB_TAUS_MAX
){
1342 AMAZON_TPE_EMSG("mbs is too large, mbr:%u taus:%u\n",qos
->txtp
.mbs
, tmp
);
1343 qvpt
.bit
.taus
= QSB_TAUS_MAX
;
1344 }else if (tmp
== 0){
1347 qvpt
.bit
.taus
= tmp
;
1353 //write the QSB Queue Parameter Table (QPT)
1354 AMAZON_WRITE_REGISTER_L(QSB_QPT_SET_MASK
,QSB_RTM_ADDR
);
1355 AMAZON_WRITE_REGISTER_L(qptl
.w0
, QSB_RTD_ADDR
);
1356 AMAZON_WRITE_REGISTER_L((QSB_TABLESEL_QPT
<<QSB_TABLESEL_SHIFT
)
1361 //write the QSB Queue VBR Parameter Table (QVPT)
1362 AMAZON_WRITE_REGISTER_L(QSB_QVPT_SET_MASK
,QSB_RTM_ADDR
);
1363 AMAZON_WRITE_REGISTER_L(qvpt
.w0
, QSB_RTD_ADDR
);
1364 AMAZON_WRITE_REGISTER_L((QSB_TABLESEL_QVPT
<<QSB_TABLESEL_SHIFT
)
1369 AMAZON_TPE_EMSG("tprs:%u twfq:%u ts:%u taus:%u\n",qptl
.bit
.tprs
,qptl
.bit
.twfq
,qvpt
.bit
.ts
,qvpt
.bit
.taus
);
1373 * Brief: create/change CBM queue descriptor
1375 * vcc: atm_vcc pointer
1376 * qid: CBM queue id (1~15)
1378 static inline void set_qd(struct atm_vcc
*vcc
, u32 qid
)
1380 u32 tx_config
=0,rx_config
=0;
1381 u32 itf
= (u32
) vcc
->itf
;
1385 tx_config
|=CBM_QD_W3_WM_EN
|CBM_QD_W3_CLPt
;
1386 //RT: check if the connection is a real time connection
1387 if (vcc
->qos
.txtp
.traffic_class
== ATM_CBR
|| vcc
->qos
.txtp
.traffic_class
== ATM_VBR_RT
){
1388 tx_config
|= CBM_QD_W3_RT
;
1390 tx_config
|= CBM_QD_W3_AAL5
; //don't set the AAL5 flag if it is a RT service
1392 rx_config
= tx_config
;
1394 if(vcc
->qos
.aal
== ATM_AAL5
){
1395 //QoS: DMA QoS according to the traffic class
1396 switch (vcc
->qos
.txtp
.traffic_class
){
1397 case ATM_CBR
: dma_qos
= CBR_DMA_QOS
;break;
1398 case ATM_VBR_RT
: dma_qos
= VBR_RT_DMA_QOS
;break;
1399 case ATM_VBR_NRT
: dma_qos
= VBR_NRT_DMA_QOS
;break;
1400 case ATM_UBR_PLUS
: dma_qos
= UBR_PLUS_DMA_QOS
;break;
1401 case ATM_UBR
: dma_qos
= UBR_DMA_QOS
;break;
1404 //TX: upstream, AAL5(EPD or PPD), NOINT, SBid
1405 tx_config
|= CBM_QD_W3_DIR_UP
|CBM_QD_W3_INT_NOINT
|(itf
&CBM_QD_W3_SBID_MASK
);
1406 //RX: DMA QoS, downstream, no interrupt, AAL5(EPD, PPD), NO INT, HCR
1407 #ifdef AMAZON_TPE_SCR
1408 rx_config
|= dma_qos
|CBM_QD_W3_DIR_DOWN
|CBM_QD_W3_INT_EOF
;
1410 rx_config
|= dma_qos
|CBM_QD_W3_DIR_DOWN
|CBM_QD_W3_INT_NOINT
|CBM_QD_W3_HCR
;
1414 //upstream, NOINT, SBid
1415 tx_config
|= CBM_QD_W3_DIR_UP
|CBM_QD_W3_INT_NOINT
|(itf
&CBM_QD_W3_SBID_MASK
);
1416 //RX: downstream, ACA interrupt,
1417 rx_config
|= CBM_QD_W3_DIR_DOWN
|CBM_QD_W3_INT_ACA
;
1420 //Threshold: maximum threshold for tx/rx queue, which is adjustable in steps of 64 cells
1421 tx_config
|= ( (divide_by_64_round_up(tx_q_threshold
)&0xffff)<<CBM_QD_W3_THRESHOLD_SHIFT
) & CBM_QD_W3_THRESHOLD_MASK
;
1422 rx_config
|= ( (divide_by_64_round_up(rx_q_threshold
)&0xffff)<<CBM_QD_W3_THRESHOLD_SHIFT
) & CBM_QD_W3_THRESHOLD_MASK
;
1424 qd_addr
= (u8
*) KSEG1ADDR((unsigned long)g_atm_dev
.cbm
.qd_addr
);
1426 AMAZON_WRITE_REGISTER_L(tx_config
, (qd_addr
+qid
*CBM_QD_SIZE
+ 0xc));
1427 AMAZON_WRITE_REGISTER_L(0, (qd_addr
+qid
*CBM_QD_SIZE
+ 0x8));
1429 AMAZON_WRITE_REGISTER_L(rx_config
, (qd_addr
+(qid
+CBM_RX_OFFSET
)*CBM_QD_SIZE
+ 0xc));
1430 AMAZON_WRITE_REGISTER_L(0, (qd_addr
+(qid
+CBM_RX_OFFSET
)*CBM_QD_SIZE
+ 0x8));
1433 * Brief: add HTU table entry
1436 * qid: CBM queue id (DEST is qid + CBM_RX_OFFSET)
1437 * idx: entry id (starting from zero to 14)
1440 * EIO: HTU table entry cannot be written
1443 inline int set_htu_entry(u8 vpi
, u16 vci
, u8 qid
, u8 idx
)
1447 while ((tmp1
= readl(HTU_RAMSTAT_ADDR
))!=0 && i
< 1024) i
++;
1450 AMAZON_TPE_EMSG("timeout\n");
1453 // write address register,
1454 AMAZON_WRITE_REGISTER_L(idx
, HTU_RAMADDR_ADDR
);
1455 // configure transmit queue
1456 tmp1
= vpi
<<24|vci
<<8;
1457 tmp1
|= HTU_RAMDAT1_VCON
// valid connection the entry is not validated here !!!!!!!!!!!!!!!!
1458 |HTU_RAMDAT1_VCI3
// vci3 -> oam queue
1459 |HTU_RAMDAT1_VCI4
// vci4 -> oam queue
1460 |HTU_RAMDAT1_VCI6
// vci6 -> rm queue
1461 |HTU_RAMDAT1_PTI4
// pti4 -> oam queue
1462 |HTU_RAMDAT1_PTI5
; // pti5 -> oam queue
1464 // ramdat 1 (in params & oam handling)
1465 AMAZON_WRITE_REGISTER_L( tmp1
, HTU_RAMDAT1_ADDR
);
1466 // ramdat 2 (out params & oam handling)
1467 tmp1
= ((qid
+CBM_RX_OFFSET
)&HTU_RAMDAT2_QID_MASK
)
1473 AMAZON_WRITE_REGISTER_L( tmp1
, HTU_RAMDAT2_ADDR
);
1476 AMAZON_WRITE_REGISTER_L(HTU_RAMCMD_WR
, HTU_RAMCMD_ADDR
);
1480 * Brief: add HTU table entry
1482 * vcc: atm_vcc pointer
1486 * EIO: HTU table entry cannot be written
1488 inline static int set_htu(struct atm_vcc
*vcc
, u32 qid
)
1490 return set_htu_entry(vcc
->vpi
, vcc
->vci
, qid
, (qid
- CBM_DEFAULT_Q_OFFSET
));
1494 * Brief: allocate a queue
1496 * <=0 no available queues
1499 static int atm_allocate_q(short itf
)
1504 amazon_atm_port_t
* dev
;
1505 dev
= &g_atm_dev
.ports
[itf
];
1506 //find start queue id for this interface
1507 for (i
=0; i
< itf
; i
++)
1509 qid
+= g_atm_dev
.ports
[i
].max_conn
;
1511 // apply default queue offset ( oam, free cell queue, others, rm )
1512 qid
+= CBM_DEFAULT_Q_OFFSET
;
1514 // search for a free queue
1515 while ( (qid
<tmp1
+dev
->max_conn
)
1516 && ( g_atm_dev
.queues
[qid
].free
!= 1)) {
1519 // if none was found, send failure message and return
1520 if ( tmp1
+dev
->max_conn
== qid
)
1527 /* Brief: open a aal5 or aal0 connection
1529 static int atm_open(struct atm_vcc
*vcc
, push_back_t push
)
1533 amazon_atm_port_t
* port
= & g_atm_dev
.ports
[vcc
->itf
];
1534 unsigned long flags
;
1535 /***************** check bandwidth ******************/
1536 /* 511045:linmars change ATM_VBR_NRT to use scr instead of pcr */
1537 if ((vcc
->qos
.txtp
.traffic_class
==ATM_CBR
&&vcc
->qos
.txtp
.max_pcr
>port
->tx_rem_cr
)
1538 ||(vcc
->qos
.txtp
.traffic_class
==ATM_VBR_RT
&&vcc
->qos
.txtp
.max_pcr
>port
->tx_rem_cr
)
1539 ||(vcc
->qos
.txtp
.traffic_class
==ATM_VBR_NRT
&&vcc
->qos
.txtp
.scr
>port
->tx_rem_cr
)
1540 ||(vcc
->qos
.txtp
.traffic_class
==ATM_UBR_PLUS
&&vcc
->qos
.txtp
.min_pcr
>port
->tx_rem_cr
)
1542 AMAZON_TPE_EMSG("not enough bandwidth left (%u) cells per seconds \n",port
->tx_rem_cr
);
1545 if ( (qid
= amazon_atm_find_vpivci(vcc
->vpi
, vcc
->vci
)) >0 ){
1546 AMAZON_TPE_EMSG("vpi:%u vci:%u is alreay open on queue:%u\n", vcc
->vpi
, vcc
->vci
, qid
);
1550 /***************** allocate entry queueID for this port *****************/
1551 if ( (qid
=atm_allocate_q(vcc
->itf
)) <= 0){
1552 AMAZON_TPE_EMSG("port: %u max:%u qid: %u\n", vcc
->itf
, port
->max_conn
, qid
);
1553 AMAZON_TPE_EMSG("no availabel connections for this port:%u\n",vcc
->itf
);
1556 /**************QSB parameters and CBM descriptors*************/
1557 set_qsb(vcc
, &vcc
->qos
, qid
);
1560 err
=set_htu(vcc
,qid
);
1562 AMAZON_TPE_EMSG("set htu entry fails %u\n",err
);
1565 /************set internal mapping*************/
1566 local_irq_save(flags
);
1567 g_atm_dev
.queues
[qid
].free
= 0;
1568 g_atm_dev
.queues
[qid
].vcc
= vcc
;
1569 g_atm_dev
.queues
[qid
].push
= push
;
1570 g_atm_dev
.queues
[qid
+CBM_RX_OFFSET
].free
= 0;
1571 g_atm_dev
.queues
[qid
+CBM_RX_OFFSET
].vcc
= vcc
;
1572 g_atm_dev
.queues
[qid
+CBM_RX_OFFSET
].push
= push
;
1573 /******************reserve bandwidth**********************/
1574 if (vcc
->qos
.txtp
.traffic_class
== ATM_CBR
){
1575 //CBR, real time connection, reserve PCR
1576 port
->tx_cur_cr
+= vcc
->qos
.txtp
.max_pcr
;
1577 port
->tx_rem_cr
-= vcc
->qos
.txtp
.max_pcr
;
1578 }else if (vcc
->qos
.txtp
.traffic_class
== ATM_VBR_RT
){
1579 //VBR_RT, real time connection, reserve PCR
1580 port
->tx_cur_cr
+= vcc
->qos
.txtp
.max_pcr
;
1581 port
->tx_rem_cr
-= vcc
->qos
.txtp
.max_pcr
;
1582 }else if (vcc
->qos
.txtp
.traffic_class
== ATM_VBR_NRT
){
1583 //VBR_NRT, reserve SCR
1584 port
->tx_cur_cr
+= vcc
->qos
.txtp
.pcr
;
1585 port
->tx_rem_cr
-= vcc
->qos
.txtp
.pcr
;
1586 }else if (vcc
->qos
.txtp
.traffic_class
== ATM_UBR_PLUS
){
1587 //UBR_PLUS, reserve MCR
1588 port
->tx_cur_cr
+= vcc
->qos
.txtp
.min_pcr
;
1589 port
->tx_rem_cr
-= vcc
->qos
.txtp
.min_pcr
;
1591 local_irq_restore(flags
);
1594 /* Brief: Open ATM connection
1595 * Parameters: atm_vcc - Pointer to VCC data structure
1596 * vpi - VPI value for new connection
1597 * vci - VCI value for new connection
1599 * Return: 0 - sucessful
1600 * -ENOMEM - No memory available
1601 * -EINVAL - No bandwidth/queue/ or unsupported AAL type
1603 * This function opens an ATM connection on a specific device/interface
1606 int amazon_atm_open(struct atm_vcc
*vcc
,push_back_t push
)
1610 AMAZON_TPE_DMSG("vpi %u vci %u itf %u aal %u\n"
1617 AMAZON_TPE_DMSG("tx cl %u bw %u mtu %u\n"
1618 ,vcc
->qos
.txtp
.traffic_class
1619 ,vcc
->qos
.txtp
.max_pcr
1620 ,vcc
->qos
.txtp
.max_sdu
1622 AMAZON_TPE_DMSG("rx cl %u bw %u mtu %u\n"
1623 ,vcc
->qos
.rxtp
.traffic_class
1624 ,vcc
->qos
.rxtp
.max_pcr
1625 ,vcc
->qos
.rxtp
.max_sdu
1627 if (vcc
->qos
.aal
== ATM_AAL5
|| vcc
->qos
.aal
== ATM_AAL0
){
1628 err
= atm_open(vcc
,push
);
1630 AMAZON_TPE_EMSG("unsupported aal type %u\n", vcc
->qos
.aal
);
1631 err
= -EPROTONOSUPPORT
;
1634 //replace the default memory allocation function with our own
1635 vcc
->alloc_tx
= amazon_atm_alloc_tx
;
1636 set_bit(ATM_VF_READY
,&vcc
->flags
);
1641 /* Brief: Send ATM OAM cell
1642 * Parameters: atm_vcc - Pointer to VCC data structure
1643 * skb - Pointer to sk_buff structure, that contains the data
1644 * Return: 0 - sucessful
1645 * -ENOMEM - No memory available
1646 * -EINVAL - Not supported
1648 * This function sends a cell over and ATM connection
1649 * We always release the skb
1650 * TODO: flags handling (ATM_OF_IMMED, ATM_OF_INRATE)
1652 int amazon_atm_send_oam(struct atm_vcc
*vcc
, void * cell
, int flags
)
1656 struct amazon_atm_cell_header
* cell_header
;
1658 cell_header
= (struct amazon_atm_cell_header
*) cell
;
1659 if ((cell_header
->bit
.pti
== ATM_PTI_SEGF5
) || (cell_header
->bit
.pti
== ATM_PTI_E2EF5
)) {
1660 qid
= amazon_atm_find_vpivci( cell_header
->bit
.vpi
, cell_header
->bit
.vci
);
1661 }else if (cell_header
->bit
.vci
== 0x3 || cell_header
->bit
.vci
== 0x4) {
1662 //507281:tc.chen qid = amazon_atm_find_vpi((int) cell_header->bit.vpi);
1663 // 507281:tc.chen start
1665 f4_vpi
= cell_header
->bit
.vpi
;
1666 qid
= amazon_atm_find_vpi(f4_vpi
);
1667 // 507281:tc.chen end
1669 //non-OAM cells, always invalid
1672 if (qid
== -EINVAL
) {
1674 AMAZON_TPE_EMSG("not valid AAL0 packet\n");
1676 //send the cell using swie
1678 err
= amazon_atm_swin(AMAZON_ATM_OAM_Q_ID
, cell
);
1680 err
= amazon_atm_swin(qid
, cell
);
1687 /* Brief: Send AAL5 frame through DMA
1688 * Parameters: vpi - virtual path id
1689 * vci - virtual circuit id
1690 * clp - cell loss priority
1691 * qid - CBM queue to be sent to
1692 * skb - packet to be sent
1693 * Return: 0 - sucessful
1694 * -ENOMEM - No memory available
1695 * -EINVAL - Not supported
1697 * This function sends a AAL5 frame over and ATM connection
1698 * 1. make sure that the data is aligned to 4x32-bit boundary
1699 * 2. provide the inbound data (CPCS-UU and CPI, not used here)
1701 * 4. send the frame by DMA
1702 * 5. release the buffer ???
1703 ** use our own allocation alloc_tx
1704 ** we make sure the alignment and additional memory
1705 *** we always release the skb
1708 int amazon_atm_dma_tx(u8 vpi
, u16 vci
, u8 clp
, u8 qid
, struct sk_buff
*skb
)
1710 int err
=0,need_pop
=1;
1713 struct sk_buff
*skb_tmp
;
1716 //AAL5S inbound header 8 bytes
1717 if (skb
->len
> g_atm_dev
.aal5
.tx_max_sdu
- AAL5S_INBOUND_HEADER
) {
1718 AMAZON_TPE_DMSG("tx_max_sdu:%u\n",g_atm_dev
.aal5
.tx_max_sdu
);
1719 AMAZON_TPE_DMSG("skb too large [%u]!\n",skb
->len
);
1721 goto atm_dma_tx_error_exit
;
1724 //Check the byte alignment requirement and header space
1725 if ( ( ((u32
)(skb
->data
)%16) !=AAL5S_INBOUND_HEADER
)|| (skb_headroom(skb
)<AAL5S_INBOUND_HEADER
)){
1726 //not aligned or no space for header, fall back to memcpy
1727 skb_tmp
= dev_alloc_skb(skb
->len
+16);
1730 goto atm_dma_tx_error_exit
;
1732 alloc_align_16(skb_tmp
);
1733 g_atm_dev
.aal5
.cnt_cpy
++;
1734 skb_reserve(skb_tmp
,AAL5S_INBOUND_HEADER
);
1735 memcpy(skb_put(skb_tmp
,skb
->len
), skb
->data
, skb
->len
);
1736 amazon_atm_free_tx_skb(skb
);
1740 //Provide AAL5S inbound header
1741 data
= (u32
*)skb_push(skb
,8);
1742 data
[0] = __be32_to_cpu(vpi
<<20|vci
<<4|clp
);
1743 data
[1] = __be32_to_cpu(g_atm_dev
.aal5
.padding_byte
<<8|qid
);
1748 AMAZON_TPE_DMSG("AAL5S header 0 %8x\n", data
[0]);
1749 AMAZON_TPE_DMSG("AAL5S header 0 %8x\n", data
[1]);
1750 AMAZON_TPE_DMSG("about to call dma_write len: %u\n", len
);
1751 nwrite
=dma_device_write( &g_dma_dev
,skb
->data
,len
,skb
);
1752 if (nwrite
!= len
) {
1753 //DMA descriptors full
1754 // AMAZON_TPE_EMSG("AAL5 packet drop due to DMA nwrite:%u skb->len:%u\n", nwrite,len);
1755 AMAZON_TPE_DMSG("AAL5 packet drop due to DMA nwrite:%u skb->len:%u\n", nwrite
,len
);
1757 goto atm_dma_tx_drop_exit
;
1759 AMAZON_TPE_DMSG("just finish call dma_write\n");
1760 //release in the "dma done" call-back
1762 atm_dma_tx_error_exit
:
1763 g_atm_dev
.mib_counter
.tx_err
++;
1764 queue_statics(qid
, QS_ERR
);
1765 goto atm_dma_tx_exit
;
1767 atm_dma_tx_drop_exit
:
1768 g_atm_dev
.mib_counter
.tx_drop
++;
1769 queue_statics(qid
, QS_SW_DROP
);
1772 amazon_atm_free_tx_skb(skb
);
1774 dev_kfree_skb_any(skb
);
1779 /* Brief: Send AAL0/AAL5 packet
1780 * Parameters: atm_vcc - Pointer to VCC data structure
1781 * skb - Pointer to sk_buff structure, that contains the data
1782 * Return: 0 - sucessful
1783 * -ENOMEM - No memory available
1784 * -EINVAL - Not supported
1786 * See amazon_atm_dma_tx
1788 int amazon_atm_send(struct atm_vcc
*vcc
,struct sk_buff
*skb
)
1795 if (vcc
== NULL
|| skb
== NULL
){
1796 AMAZON_TPE_EMSG("invalid parameter\n");
1799 ATM_SKB(skb
)->vcc
= vcc
;
1800 qid
= amazon_atm_get_queue(vcc
);
1801 if (valid_qid(qid
) != 1) {
1802 AMAZON_TPE_EMSG("invalid vcc!\n");
1804 goto atm_send_err_exit
;
1807 //Send AAL0 using SWIN
1808 if (vcc
->qos
.aal
== ATM_AAL0
){
1810 err
=amazon_atm_swin((qid
+CBM_RX_OFFSET
), skb
->data
);
1812 err
=amazon_atm_swin(qid
, skb
->data
);
1815 goto atm_send_err_exit
;
1822 g_atm_dev
.mib_counter
.tx
++;
1823 adsl_led_flash();//joelin adsl led
1824 queue_statics(qid
, QS_PKT
);
1826 #ifdef AMAZON_CHECK_LINK
1828 if (adsl_link_status
== 0){
1830 AMAZON_TPE_DMSG("ADSL link down, discarded!\n");
1832 goto atm_send_drop_exit
;
1835 clp
= (vcc
->atm_options
&ATM_ATMOPT_CLP
)?1:0;
1836 //check watermark first
1837 wm
= readl(CBM_WMSTAT0_ADDR
);
1838 if ( (wm
& (1<<qid
))
1839 ||( (vcc
->qos
.txtp
.traffic_class
!= ATM_CBR
1840 &&vcc
->qos
.txtp
.traffic_class
!= ATM_VBR_RT
)
1841 &(wm
& (CBM_WM_NRT_MASK
| (clp
&CBM_WM_CLP1_MASK
)) ))){
1843 AMAZON_TPE_DMSG("watermark hit, discarded!\n");
1845 goto atm_send_drop_exit
;
1848 return amazon_atm_dma_tx(vcc
->vpi
, vcc
->vci
,clp
, (qid
+CBM_RX_OFFSET
),skb
);
1850 return amazon_atm_dma_tx(vcc
->vpi
, vcc
->vci
,clp
, qid
,skb
);
1854 amazon_atm_free_tx_skb_vcc(vcc
,skb
);
1858 g_atm_dev
.mib_counter
.tx_drop
++;
1859 queue_statics(qid
,QS_SW_DROP
);
1861 amazon_atm_free_tx_skb_vcc(vcc
,skb
);
1865 /* Brief: Return ATM port related MIB
1866 * Parameter: interface number
1869 int amazon_atm_cell_mib(atm_cell_ifEntry_t
* to
,u32 itf
)
1871 g_atm_dev
.mib_counter
.htu_unp
+= readl(HTU_MIBCIUP
);
1872 to
->ifInUnknownProtos
= g_atm_dev
.mib_counter
.htu_unp
;
1873 #ifdef AMAZON_TPE_READ_ARC
1875 meiDebugRead((AR_CELL0_ADDR
+itf
*4),®_val
,1);
1876 g_atm_dev
.mib_counter
.rx_cells
+= reg_val
;
1878 meiDebugWrite((AR_CELL0_ADDR
+itf
*4),®_val
,1);
1879 to
->ifHCInOctets_h
= (g_atm_dev
.mib_counter
.rx_cells
* 53)>>32;
1880 to
->ifHCInOctets_l
= (g_atm_dev
.mib_counter
.rx_cells
* 53) & 0xffff;
1882 meiDebugRead((AT_CELL0_ADDR
+itf
*4),®_val
,1);
1883 g_atm_dev
.mib_counter
.tx_cells
+= reg_val
;
1885 meiDebugWrite((AT_CELL0_ADDR
+itf
*4),®_val
,1);
1886 to
->ifHCOutOctets_h
= (g_atm_dev
.mib_counter
.tx_cells
* 53)>>32;
1887 to
->ifHCOutOctets_l
= (g_atm_dev
.mib_counter
.rx_cells
* 53) & 0xffff;
1889 meiDebugRead((AR_CD_CNT0_ADDR
+itf
*4),®_val
,1);
1890 g_atm_dev
.mib_counter
.rx_err_cells
+= reg_val
;
1892 meiDebugWrite((AR_CD_CNT0_ADDR
+itf
*4),®_val
,1);
1893 to
->ifInErrors
= g_atm_dev
.mib_counter
.rx_err_cells
;
1895 to
->ifOutErrors
= 0;
1897 to
->ifHCInOctets_h
= 0;
1898 to
->ifHCInOctets_l
= 0;
1899 to
->ifHCOutOctets_h
= 0;
1900 to
->ifHCOutOctets_l
= 0;
1902 to
->ifOutErrors
= 0;
1907 /* Brief: Return ATM AAL5 related MIB
1911 int amazon_atm_aal5_mib(atm_aal5_ifEntry_t
* to
)
1914 //AAL5R received Octets from ATM
1915 reg_l
= readl(AAL5_RIOL_ADDR
);
1916 reg_h
= readl(AAL5_RIOM_ADDR
);
1917 g_atm_dev
.mib_counter
.rx_cnt_h
+=reg_h
;
1918 if (reg_l
+ g_atm_dev
.mib_counter
.rx_cnt_l
< reg_l
){
1919 g_atm_dev
.mib_counter
.rx_cnt_h
++;
1922 g_atm_dev
.mib_counter
.rx_cnt_l
+= reg_l
;
1923 //AAL5S sent Octets to ATM
1924 reg_l
= readl(AAL5_SOOL_ADDR
);
1925 reg_h
= readl(AAL5_SOOM_ADDR
);
1926 g_atm_dev
.mib_counter
.tx_cnt_h
+=reg_h
;
1927 if (reg_l
+ g_atm_dev
.mib_counter
.tx_cnt_l
< reg_l
){
1928 g_atm_dev
.mib_counter
.tx_cnt_h
++;
1930 g_atm_dev
.mib_counter
.tx_cnt_l
+= reg_l
;
1933 g_atm_dev
.mib_counter
.tx_ppd
+= readl(CBM_AAL5ODIS_ADDR
);
1934 g_atm_dev
.mib_counter
.rx_drop
+= readl(CBM_AAL5IDIS_ADDR
);
1937 to
->ifHCInOctets_h
= g_atm_dev
.mib_counter
.rx_cnt_h
;
1938 to
->ifHCInOctets_l
= g_atm_dev
.mib_counter
.rx_cnt_l
;
1939 to
->ifHCOutOctets_h
= g_atm_dev
.mib_counter
.tx_cnt_h
;
1940 to
->ifHCOutOctets_l
= g_atm_dev
.mib_counter
.tx_cnt_l
;
1941 to
->ifOutDiscards
= g_atm_dev
.mib_counter
.tx_drop
;
1942 to
->ifInDiscards
= g_atm_dev
.mib_counter
.rx_drop
;
1944 //Software provided counters
1945 //packets passed to higher layer
1946 to
->ifInUcastPkts
= g_atm_dev
.mib_counter
.rx
;
1947 //packets passed from higher layer
1948 to
->ifOutUcastPkts
= g_atm_dev
.mib_counter
.tx
;
1949 //number of wrong downstream packets
1950 to
->ifInErrors
= g_atm_dev
.mib_counter
.rx_err
;
1951 //number of wrong upstream packets
1952 to
->ifOutErros
= g_atm_dev
.mib_counter
.tx_err
;
1956 /* Brief: Return ATM AAL5 VCC related MIB from internale use
1961 static int __amazon_atm_vcc_mib(int qid
, atm_aal5_vcc_t
* to
)
1964 to
->aal5VccCrcErrors
= g_atm_dev
.queues
[qid
].aal5VccCrcErrors
;
1965 to
->aal5VccOverSizedSDUs
=g_atm_dev
.queues
[qid
].aal5VccOverSizedSDUs
;
1966 to
->aal5VccSarTimeOuts
= 0; //not supported yet
1969 /* Brief: Return ATM AAL5 VCC related MIB from vpi/vci
1970 * Parameter: atm_vcc
1973 int amazon_atm_vcc_mib_x(int vpi
, int vci
,atm_aal5_vcc_t
* to
)
1977 qid
= amazon_atm_find_vpivci(vpi
, vci
);
1979 err
= __amazon_atm_vcc_mib(qid
,to
);
1987 /* Brief: Return ATM AAL5 VCC related MIB
1988 * Parameter: atm_vcc
1991 int amazon_atm_vcc_mib(struct atm_vcc
*vcc
,atm_aal5_vcc_t
* to
)
1995 qid
= amazon_atm_get_queue(vcc
);
1997 err
= __amazon_atm_vcc_mib(qid
,to
);
2004 /* Brief: Close ATM connection
2005 * Parameters: atm_vcc - Pointer to VCC data structure
2008 * This function closes the given ATM connection
2010 void amazon_atm_close(struct atm_vcc
*vcc
){
2015 unsigned long flags
;
2017 AMAZON_TPE_EMSG("invalid parameter. vcc is null\n");
2020 u32 itf
= (u32
) vcc
->itf
;
2022 if (vcc
->qos
.txtp
.traffic_class
== ATM_CBR
){
2023 g_atm_dev
.ports
[itf
].tx_rem_cr
+= vcc
->qos
.txtp
.max_pcr
;
2024 g_atm_dev
.ports
[itf
].tx_cur_cr
-= vcc
->qos
.txtp
.max_pcr
;
2025 }else if (vcc
->qos
.txtp
.traffic_class
== ATM_VBR_RT
){
2026 g_atm_dev
.ports
[itf
].tx_rem_cr
+= vcc
->qos
.txtp
.max_pcr
;
2027 g_atm_dev
.ports
[itf
].tx_cur_cr
-= vcc
->qos
.txtp
.max_pcr
;
2028 }else if (vcc
->qos
.txtp
.traffic_class
== ATM_VBR_NRT
){
2029 g_atm_dev
.ports
[itf
].tx_rem_cr
+= vcc
->qos
.txtp
.pcr
;
2030 g_atm_dev
.ports
[itf
].tx_cur_cr
-= vcc
->qos
.txtp
.pcr
;
2031 }else if (vcc
->qos
.txtp
.traffic_class
== ATM_UBR_PLUS
){
2032 g_atm_dev
.ports
[itf
].tx_rem_cr
+= vcc
->qos
.txtp
.min_pcr
;
2033 g_atm_dev
.ports
[itf
].tx_cur_cr
-= vcc
->qos
.txtp
.min_pcr
;
2036 qid
= amazon_atm_get_queue(vcc
);
2037 if (qid
== -EINVAL
){
2038 AMAZON_TPE_EMSG("unknown vcc %u.%u.%u\n", vcc
->itf
, vcc
->vpi
, vcc
->vci
);
2041 local_irq_save(flags
);
2044 while ((tmp1
= readl(HTU_RAMSTAT_ADDR
))!=0 && i
< HTU_RAM_ACCESS_MAX
) i
++;
2045 if (i
== HTU_RAM_ACCESS_MAX
){
2046 AMAZON_TPE_EMSG("HTU RAM ACCESS out of time\n");
2049 // write address register
2050 AMAZON_WRITE_REGISTER_L(qid
- CBM_DEFAULT_Q_OFFSET
, HTU_RAMADDR_ADDR
);
2051 // invalidate the connection
2052 AMAZON_WRITE_REGISTER_L(0, HTU_RAMDAT1_ADDR
);
2054 AMAZON_WRITE_REGISTER_L(HTU_RAMCMD_WR
,HTU_RAMCMD_ADDR
);
2056 qd_addr
= (u8
*) KSEG1ADDR((unsigned long)g_atm_dev
.cbm
.qd_addr
);
2057 #ifdef AMAZON_ATM_DEBUG
2058 tmp1
= readl(qd_addr
+qid
*CBM_QD_SIZE
+0x8) & 0xffff;
2059 AMAZON_TPE_DMSG("TX queue has %u cells \n", tmp1
);
2060 tmp1
= readl( qd_addr
+(qid
+CBM_RX_OFFSET
)*CBM_QD_SIZE
+0x08)&0xffff;
2061 AMAZON_TPE_DMSG("RX queue has %u cells \n", tmp1
);
2063 // set threshold of txqueue to 0
2064 tmp1
= readl(qd_addr
+qid
*CBM_QD_SIZE
+0x0c);
2065 tmp1
&= (~ CBM_QD_W3_THRESHOLD_MASK
);
2066 AMAZON_WRITE_REGISTER_L(tmp1
, (qd_addr
+qid
*CBM_QD_SIZE
+0x0c));
2067 // set threshold of rxqueue to 0
2068 tmp1
= readl( qd_addr
+(qid
+CBM_RX_OFFSET
)*CBM_QD_SIZE
+0x0c);
2069 tmp1
&= (~ CBM_QD_W3_THRESHOLD_MASK
);
2070 AMAZON_WRITE_REGISTER_L(tmp1
,(qd_addr
+(qid
+CBM_RX_OFFSET
)*CBM_QD_SIZE
+0x0c));
2072 //clear internal mapping
2073 amazon_atm_clear_vcc(qid
);
2074 amazon_atm_clear_vcc(qid
+CBM_RX_OFFSET
);
2076 local_irq_restore(flags
);
2080 /* Brief: initialize internal data structure
2082 static void atm_constructor(amazon_atm_dev_t
* dev
)
2085 memset(dev
,0,sizeof(amazon_atm_dev_t
));
2086 atm_init_parameters(dev
);
2087 //internal: queue "free" flag
2088 for(i
=1;i
<AMAZON_ATM_MAX_QUEUE_NUM
;i
++) {
2089 //dev->queues[i].vcc=NULL;
2090 dev
->queues
[i
].free
= 1;
2092 for(i
=0;i
<AMAZON_ATM_PORT_NUM
;i
++){
2093 dev
->ports
[i
].tx_rem_cr
= dev
->ports
[i
].tx_max_cr
;
2096 atomic_set(&dev
->dma_tx_free_0
,1); //initially there should be free descriptors
2099 /* Brief: return round up base-2 logarithm
2101 static inline int get_log_2(u32 value
)
2105 if (j
>=value
) break;
2109 AMAZON_TPE_DMSG("round up base-2 logarithm of %u is %u\n", value
, i
);
2113 /* Brief: TPE hardware initialization
2114 * Parameter: specifiy the configurations of the hardware
2116 static inline int atm_init_hard(amazon_atm_dev_t
* dev
)
2119 u32 tmp1
, tmp2
, tmp3
;
2122 //PMU power on the module 1st
2123 *(AMAZON_PMU_PWDCR
) = (*AMAZON_PMU_PWDCR
) | (AMAZON_PMU_PWDCR_TPE
);
2125 *(AMAZON_RST_REQ
) = (* AMAZON_RST_REQ
) | (AMAZON_RST_REQ_TPE
);
2128 *(AMAZON_RST_REQ
) = (* AMAZON_RST_REQ
) & (~(AMAZON_RST_REQ_TPE
));
2131 unsigned long qsb_clk
= amazon_get_fpi_hz()>>1;
2132 /*********allocate & arrange memory for CBM *********/
2133 if (dev
->cbm
.mem_addr
== NULL
){
2134 dev
->cbm
.allocated
= 1;
2135 mem_addr
= (u8
*)__get_free_pages(GFP_KERNEL
, get_log_2(((CBM_CELL_SIZE
* dev
->cbm
.free_cell_cnt
) >>PAGE_SHIFT
) + 1));
2136 if (mem_addr
!= NULL
){
2137 dev
->cbm
.mem_addr
= mem_addr
;
2142 if (dev
->cbm
.qd_addr
== NULL
){
2143 #ifdef CONFIG_USE_VENUS
2144 //to work around a bug, bit15 of QDOFF address should be 1,Aug4, 2004
2145 //thus, we allocate 64k memory
2146 qd_addr
= (u8
*)__get_free_pages(GFP_KERNEL
, 4);
2147 if (qd_addr
!= NULL
) {
2148 dev
->cbm
.qd_addr_free
= (u8
*) (((unsigned long) qd_addr
));
2149 dev
->cbm
.qd_addr
= (u8
*) (((unsigned long) qd_addr
) | 0x8000);
2153 #else //CONFIG_USE_VENUS
2154 qd_addr
= (u8
*)kmalloc( CBM_QD_SIZE
* AMAZON_ATM_MAX_QUEUE_NUM
, GFP_KERNEL
);
2155 if (qd_addr
!= NULL
) {
2156 dev
->cbm
.qd_addr
= qd_addr
;
2160 #endif //CONFIG_USE_VENUS
2162 //#ifndef CONFIG_MIPS_UNCACHED
2163 mem_addr
= (u8
*)KSEG1ADDR((unsigned long)dev
->cbm
.mem_addr
);
2164 qd_addr
= (u8
*)KSEG1ADDR((unsigned long)dev
->cbm
.qd_addr
);
2166 //CBM reset cell queue memory, 64 bytes / cell
2167 memset_io(mem_addr
, 0, CBM_CELL_SIZE
* dev
->cbm
.free_cell_cnt
);
2168 //make a link list, last 4 bytes is pointer
2169 for(i
=1;i
<dev
->cbm
.free_cell_cnt
;i
++){
2170 AMAZON_WRITE_REGISTER_L(CPHYSADDR((mem_addr
+ CBM_CELL_SIZE
* i
)),(mem_addr
+ CBM_CELL_SIZE
* (i
-1) + 0x3c));
2172 //reset queue descriptor
2173 memset_io(qd_addr
, 0, CBM_QD_SIZE
* AMAZON_ATM_MAX_QUEUE_NUM
);
2174 //init word 0-2 of q0 (free cell list)
2175 //address of last cell
2176 AMAZON_WRITE_REGISTER_L(CPHYSADDR((mem_addr
+ CBM_CELL_SIZE
* (dev
->cbm
.free_cell_cnt
-1))), qd_addr
);
2177 //address of first cell
2178 AMAZON_WRITE_REGISTER_L(CPHYSADDR((mem_addr
)), (qd_addr
+ 4));
2180 AMAZON_WRITE_REGISTER_L(dev
->cbm
.free_cell_cnt
,(qd_addr
+ 8));
2181 //init q descriptor for OAM receiving
2182 AMAZON_WRITE_REGISTER_L((CBM_QD_W3_INT_ACA
| (divide_by_64_round_up(oam_q_threshold
)&0xff)<< CBM_QD_W3_THRESHOLD_SHIFT
), (qd_addr
+ AMAZON_ATM_OAM_Q_ID
* CBM_QD_SIZE
+ 0x0c));
2183 // AMAZON_WRITE_REGISTER_L((CBM_QD_W3_INT_ACA | (u32)oam_q_threshold<< CBM_QD_W3_THRESHOLD_SHIFT), (qd_addr + AMAZON_ATM_OAM_Q_ID * CBM_QD_SIZE + 0x0c));
2185 //set offset address and threshold
2186 AMAZON_WRITE_REGISTER_L(CPHYSADDR(qd_addr
), CBM_QDOFF_ADDR
);
2187 AMAZON_WRITE_REGISTER_L(((dev
->cbm
.nrt_thr
&CBM_THR_MASK
)|CBM_WM_3_1
), CBM_NRTTHR_ADDR
);
2188 AMAZON_WRITE_REGISTER_L(((dev
->cbm
.clp0_thr
&CBM_THR_MASK
)|CBM_WM_3_1
), CBM_CLP0THR_ADDR
);
2189 AMAZON_WRITE_REGISTER_L(((dev
->cbm
.clp1_thr
&CBM_THR_MASK
)|CBM_WM_3_1
), CBM_CLP1THR_ADDR
);
2191 AMAZON_WRITE_REGISTER_L( CBM_IMR_MASK
& (~(CBM_IMR_ACA
|CBM_IMR_Q0E
|CBM_IMR_Q0I
|CBM_IMR_RDE
|CBM_IMR_OPF
|CBM_IMR_ERR
2192 #ifdef AMAZON_ATM_DEBUG
2193 |CBM_IMR_DISC
|CBM_IMR_QFD
|CBM_IMR_NFCA
|CBM_IMR_CLP1TR
|CBM_IMR_CLP0TR
|CBM_IMR_NRTTR
|CBM_IMR_QTR
2195 #ifdef AMAZON_TPE_SCR
2199 AMAZON_WRITE_REGISTER_L(SRC_CLRR
|SRC_TOS_MIPS
| SRC_SRE_ENABLE
| AMAZON_CBM_INT
, CBM_SRC0_ADDR
);
2202 //RAM entry for number of possible connections per interface
2203 tmp1
= dev
->ports
[0].max_conn
?dev
->ports
[0].max_conn
-1:0;
2204 AMAZON_WRITE_REGISTER_L(tmp1
, HTU_RX0_ADDR
);
2205 for(i
=1;i
<AMAZON_ATM_PORT_NUM
;i
++){
2206 tmp1
+=dev
->ports
[i
].max_conn
;
2207 AMAZON_WRITE_REGISTER_L(tmp1
, HTU_RX0_ADDR
+ 4 * i
);
2209 dev
->cbm
.max_q_off
= tmp1
+1;
2210 //Queue ID for OAM/RM/Other cells
2211 AMAZON_WRITE_REGISTER_L (AMAZON_ATM_OAM_Q_ID
, HTU_DESTOAM_ADDR
);
2212 AMAZON_WRITE_REGISTER_L( AMAZON_ATM_RM_Q_ID
, HTU_DESTRM_ADDR
);
2213 AMAZON_WRITE_REGISTER_L( AMAZON_ATM_OTHER_Q_ID
, HTU_DESTOTHER_ADDR
);
2215 AMAZON_WRITE_REGISTER_L((u32
) HTUTIMEOUT
, HTU_TIMEOUT_ADDR
);
2216 #ifdef AMAZON_ATM_DEBUG
2217 AMAZON_WRITE_REGISTER_L((u32
) HTU_ISR_MASK
2218 &(~(HTU_ISR_NE
|HTU_ISR_TORD
|HTU_ISR_OTOC
|HTU_ISR_ONEC
|HTU_ISR_PNE
|HTU_ISR_PT
)), HTU_IMR0_ADDR
);
2219 AMAZON_WRITE_REGISTER_L(SRC_CLRR
|SRC_TOS_MIPS
|SRC_SRE_ENABLE
|AMAZON_HTU_INT
,HTU_SRC0_ADDR
);
2222 //global setting, TstepC, SBL, Tau
2224 AMAZON_WRITE_REGISTER_L(dev
->qsb
.tau
, QSB_TAU_ADDR
);
2226 AMAZON_WRITE_REGISTER_L(dev
->qsb
.sbl
, QSB_SBL_ADDR
);
2228 AMAZON_WRITE_REGISTER_L(dev
->qsb
.tstepc
>>1, QSB_CONFIG_ADDR
);
2231 for(i
=0;i
<AMAZON_ATM_PORT_NUM
;i
++){
2232 if ( (dev
->ports
[i
].enable
) && (dev
->ports
[i
].tx_max_cr
!=0) ){
2233 tmp1
= ((qsb_clk
* dev
->qsb
.tstepc
) >>1) / dev
->ports
[i
].tx_max_cr
;
2234 tmp2
= tmp1
/ 64; //integer value of Tsb
2235 tmp3
= tmp1
%64 + 1; //fractional part of Tsb
2236 //carry over to integer part (?)
2245 //1. set mask 2. write value to data transfer register 3. start the transfer
2247 AMAZON_WRITE_REGISTER_L(QSB_SET_SCT_MASK
, QSB_RTM_ADDR
);
2248 AMAZON_WRITE_REGISTER_L(tmp3
,QSB_RTD_ADDR
);
2249 AMAZON_WRITE_REGISTER_L(((QSB_TABLESEL_SCT
<<QSB_TABLESEL_SHIFT
)|QSB_RAMAC_REG_LOW
|QSB_WRITE
|i
),QSB_RAMAC_ADDR
);
2250 //SPT(SBV + PN + IntRage)
2251 AMAZON_WRITE_REGISTER_L(QSB_SET_SPT_MASK
, QSB_RTM_ADDR
);
2252 AMAZON_WRITE_REGISTER_L(QSB_SPT_SBVALID
|tmp2
|(i
<<16),QSB_RTD_ADDR
);
2253 AMAZON_WRITE_REGISTER_L(((QSB_TABLESEL_SPT
<<QSB_TABLESEL_SHIFT
)|QSB_RAMAC_REG_LOW
|QSB_WRITE
|i
),QSB_RAMAC_ADDR
);
2259 //SWIE: Setup Service Request Control Registers to enable interrupts
2260 AMAZON_WRITE_REGISTER_L(SRC_CLRR
|SRC_TOS_MIPS
| SRC_SRE_ENABLE
| AMAZON_SWIE_INT
, SWIE_ISRC_ADDR
);
2261 AMAZON_WRITE_REGISTER_L(SRC_CLRR
|SRC_TOS_MIPS
| SRC_SRE_ENABLE
| AMAZON_SWIE_INT
, SWIE_ESRC_ADDR
);
2264 #ifdef AMAZON_TPE_TEST_AAL5_INT
2265 AMAZON_WRITE_REGISTER_L(AAL5R_ISR_FE
,AAL5_RIMR0_ADDR
);
2266 AMAZON_WRITE_REGISTER_L(0, AAL5_SIMR0_ADDR
);
2267 AMAZON_WRITE_REGISTER_L(SRC_CLRR
|SRC_TOS_MIPS
| SRC_SRE_ENABLE
| AMAZON_AAL5_INT
,AAL5_SSRC0_ADDR
);
2268 AMAZON_WRITE_REGISTER_L(SRC_CLRR
|SRC_TOS_MIPS
| SRC_SRE_ENABLE
| AMAZON_AAL5_INT
,AAL5_RSRC0_ADDR
);
2269 #endif //AMAZON_TPE_TEST_AAL5_INT
2271 AMAZON_WRITE_REGISTER_L(dev
->aal5
.tx_max_sdu
,AAL5_SMFL_ADDR
);
2272 AMAZON_WRITE_REGISTER_L(dev
->aal5
.rx_max_sdu
,AAL5_RMFL_ADDR
);
2273 AMAZON_WRITE_REGISTER_L(AAL5_SCMD_MODE_POLL
// enable polling mode
2278 AMAZON_WRITE_REGISTER_L(CBM_CFG_START
,CBM_CFG_ADDR
);
2282 if (mem_addr
!= NULL
) free_pages((unsigned long)mem_addr
,get_log_2(((CBM_CELL_SIZE
* dev
->cbm
.free_cell_cnt
) >>PAGE_SHIFT
) + 1));
2284 #ifdef CONFIG_USE_VENUS
2285 //to work around a bug, bit15 of QDOFF address should be 1
2286 if (qd_addr
!= NULL
) free_pages((unsigned long)qd_addr
,4);
2287 #else //CONFIG_USE_VENUS
2288 if (qd_addr
!= NULL
) kfree(qd_addr
);
2289 #endif //CONFIG_USE_VENUS
2294 * Brief: Create entry in /proc for status information
2296 void atm_create_proc(void)
2298 create_proc_read_entry("amazon_atm", 0,NULL
, amazon_atm_read_procmem
,(void*)PROC_ATM
);
2299 create_proc_read_entry("amazon_atm_mib", 0,NULL
, amazon_atm_read_procmem
,(void*)PROC_MIB
);
2300 create_proc_read_entry("amazon_atm_vcc", 0,NULL
, amazon_atm_read_procmem
,(void*)PROC_VCC
);
2302 create_proc_read_entry("amazon_atm_aal5", 0,NULL
, amazon_atm_read_procmem
,(void*)PROC_AAL5
);
2303 create_proc_read_entry("amazon_atm_cbm", 0,NULL
, amazon_atm_read_procmem
,(void*)PROC_CBM
);
2304 create_proc_read_entry("amazon_atm_htu", 0,NULL
, amazon_atm_read_procmem
,(void*)PROC_HTU
);
2305 create_proc_read_entry("amazon_atm_qsb", 0,NULL
, amazon_atm_read_procmem
,(void*)PROC_QSB
);
2306 create_proc_read_entry("amazon_atm_swie", 0,NULL
, amazon_atm_read_procmem
,(void*)PROC_SWIE
);
2311 * Brief: Delete entry in /proc for status information
2313 void atm_delete_proc(void)
2315 remove_proc_entry("amazon_atm", NULL
);
2316 remove_proc_entry("amazon_atm_mib", NULL
);
2317 remove_proc_entry("amazon_atm_vcc", NULL
);
2319 remove_proc_entry("amazon_atm_aal5", NULL
);
2320 remove_proc_entry("amazon_atm_cbm", NULL
);
2321 remove_proc_entry("amazon_atm_htu", NULL
);
2322 remove_proc_entry("amazon_atm_qsb", NULL
);
2323 remove_proc_entry("amazon_atm_swie", NULL
);
2326 /* Brief: Initialize ATM module
2328 * Return: &g_atm_dev - sucessful
2330 * 1. invalid parameter
2331 * 2. No memory available
2333 * This function configure the TPE components according to the input info,
2340 amazon_atm_dev_t
* amazon_atm_create(void)
2343 AMAZON_TPE_DMSG("atm_init\n");
2344 /************initialize global data structure****************/
2345 atm_constructor(&g_atm_dev
);
2346 /***********allocate kernel resources****************/
2347 //bottom halfs for SWEX
2348 swex_start_task
.routine
= amazon_atm_swex
;
2349 swex_start_task
.data
= NULL
;
2350 swex_complete_task
.routine
= amazon_atm_swex_push
;
2351 swex_complete_task
.data
= NULL
;
2352 #ifdef AMAZON_TPE_SCR
2353 a5r_task
.routine
= amazon_atm_a5r
;
2354 a5r_task
.data
= NULL
;
2355 #endif //AMAZON_TPE_SCR
2357 sema_init(&(g_atm_dev
.swie
.in_sem
), 1);
2359 clear_bit(SWIE_LOCK
, &(g_atm_dev
.swie
.lock
));
2361 init_waitqueue_head(&(g_atm_dev
.swie
.sleep
));
2365 memset(&g_dma_dev
,0,sizeof(struct dma_device_info
));
2366 strcpy(g_dma_dev
.device_name
,"TPE");
2368 g_dma_dev
.num_tx_chan
=2;
2369 g_dma_dev
.num_rx_chan
=2;
2371 g_dma_dev
.tx_burst_len
=4;
2372 g_dma_dev
.rx_burst_len
=4;
2376 g_dma_dev
.tx_chan
[i
].weight
=QOS_DEFAULT_WGT
;
2377 g_dma_dev
.tx_chan
[i
].desc_num
=10;
2378 g_dma_dev
.tx_chan
[i
].packet_size
=g_atm_dev
.aal5
.tx_max_sdu
+ AAL5S_INBOUND_HEADER
;
2379 g_dma_dev
.tx_chan
[i
].control
=1;
2383 g_dma_dev
.rx_chan
[i
].weight
=QOS_DEFAULT_WGT
;
2384 /* BingTao's suggestion, change from 5->10 will prevent packet loss in NO_TX_INT mode */
2385 g_dma_dev
.rx_chan
[i
].desc_num
=10;
2386 g_dma_dev
.rx_chan
[i
].packet_size
=(g_atm_dev
.aal5
.rx_max_sdu
+ AAL5R_TRAILER_LEN
+0x10f)&(~0xf);
2387 g_dma_dev
.rx_chan
[i
].control
=1;
2389 g_dma_dev
.intr_handler
=amazon_atm_dma_handler
;
2390 g_dma_dev
.buffer_alloc
=amazon_atm_alloc_rx
;
2391 g_dma_dev
.buffer_free
=amazon_atm_free_tx
;
2392 dma_device_register(&g_dma_dev
);
2393 /***********intialize the atm hardware ****************/
2394 if ( atm_init_hard(&g_atm_dev
) != 0){
2398 AMAZON_WRITE_REGISTER_L(CBM_CFG_START
,CBM_CFG_ADDR
);
2402 AMAZON_WRITE_REGISTER_L(HTU_CFG_START
,HTU_CFG_ADDR
);
2406 // Register interrupts for insertion and extraction
2407 request_irq(AMAZON_SWIE_INT
, amazon_atm_swie_isr
, IRQF_DISABLED
, "tpe_swie", NULL
);
2408 request_irq(AMAZON_CBM_INT
, amazon_atm_cbm_isr
, IRQF_DISABLED
, "tpe_cbm", NULL
);
2409 #ifdef AMAZON_ATM_DEBUG
2410 request_irq(AMAZON_HTU_INT
, amazon_atm_htu_isr
, IRQF_DISABLED
, "tpe_htu", NULL
);
2412 #ifdef AMAZON_TPE_TEST_AAL5_INT
2413 request_irq(AMAZON_AAL5_INT
, amazon_atm_aal5_isr
, IRQF_DISABLED
, "tpe_aal5", NULL
);
2418 /* Brief: clean up atm
2422 * Disable the device.
2424 void amazon_atm_cleanup(void){
2426 clear_bit(SWIE_LOCK
, &(g_atm_dev
.swie
.lock
));
2427 wake_up(&g_atm_dev
.swie
.sleep
);
2428 up(&g_atm_dev
.swie
.in_sem
);
2429 // diable SWIE interrupts
2430 AMAZON_WRITE_REGISTER_L(0, SWIE_ISRC_ADDR
);
2431 AMAZON_WRITE_REGISTER_L(0, SWIE_ESRC_ADDR
);
2434 // Disable schedulers ( including interrupts )-----------------------
2435 for (i
= 0; i
< AMAZON_ATM_PORT_NUM
; i
++);
2437 AMAZON_WRITE_REGISTER_L(QSB_SET_SPT_SBVALID_MASK
, QSB_RTM_ADDR
);
2438 AMAZON_WRITE_REGISTER_L( 0 ,QSB_RTD_ADDR
);
2439 AMAZON_WRITE_REGISTER_L( (QSB_TABLESEL_SPT
<<QSB_TABLESEL_SHIFT
)
2445 // disable QSB_Interrupts
2446 AMAZON_WRITE_REGISTER_L( 0, QSB_IMR_ADDR
);
2447 AMAZON_WRITE_REGISTER_L( 0, QSB_SRC_ADDR
);
2448 // disable CBM interrupts
2449 AMAZON_WRITE_REGISTER_L( 0 , CBM_IMR0_ADDR
);
2450 AMAZON_WRITE_REGISTER_L( 0 , CBM_SRC0_ADDR
);
2451 // set CBM start bit to 0
2452 AMAZON_WRITE_REGISTER_L(0,CBM_CFG_ADDR
);
2453 // request hardware extraction of queue 0, wich should force the CBM
2454 // to recognize that the start bit is not set
2455 AMAZON_WRITE_REGISTER_L(CBM_HWEXPAR_PN_A5
, CBM_HWEXPAR0_ADDR
);
2456 // write frame extraction command into the hw extract command register
2457 AMAZON_WRITE_REGISTER_L(CBM_HWEXCMD_FE0
, CBM_HWEXCMD_ADDR
);
2459 // disable all HTU interrupts
2460 AMAZON_WRITE_REGISTER_L(0 ,HTU_IMR0_ADDR
);
2461 AMAZON_WRITE_REGISTER_L(0 ,HTU_SRC0_ADDR
);
2463 if (g_atm_dev
.cbm
.allocated
){
2464 free_pages((unsigned long)g_atm_dev
.cbm
.mem_addr
, get_log_2(((CBM_CELL_SIZE
* g_atm_dev
.cbm
.free_cell_cnt
) >>PAGE_SHIFT
)+1));
2465 #ifdef CONFIG_USE_VENUS
2466 //to work around a bug, bit15 of QDOFF address should be 1
2467 free_pages((unsigned long)g_atm_dev
.cbm
.qd_addr_free
,4);
2468 #else //CONFIG_USE_VENUS
2469 kfree(g_atm_dev
.cbm
.qd_addr
);
2470 #endif //CONFIG_USE_VENUS
2473 // free interrupts for insertion and extraction
2474 dma_device_unregister(&g_dma_dev
);
2475 free_irq(AMAZON_SWIE_INT
, NULL
);
2476 free_irq(AMAZON_CBM_INT
, NULL
);
2477 #ifdef AMAZON_ATM_DEBUG
2478 free_irq(AMAZON_HTU_INT
, NULL
);
2480 #ifdef AMAZON_TPE_TEST_AAL5_INT
2481 free_irq(AMAZON_AAL5_INT
, NULL
);
2486 /************************ ATM network interface ***********************************************/
2487 /* Brief: getsockopt
2489 int amazon_atm_getsockopt(struct atm_vcc
*vcc
, int level
, int optname
, char *optval
, int optlen
)
2492 atm_aal5_vcc_t mib_vcc
;
2493 AMAZON_TPE_DMSG("1\n");
2495 case SO_AMAZON_ATM_MIB_VCC
:
2496 AMAZON_TPE_DMSG("2\n");
2497 err
= amazon_atm_vcc_mib(vcc
, &mib_vcc
);
2498 AMAZON_TPE_DMSG("%u\n",mib_vcc
.aal5VccCrcErrors
);
2499 err
= copy_to_user((void *)optval
,&mib_vcc
, sizeof(mib_vcc
));
2500 AMAZON_TPE_DMSG("err %u\n",err
);
2511 int amazon_atm_ioctl(struct atm_dev
*dev
,unsigned int cmd
,void *arg
)
2515 atm_cell_ifEntry_t mib_cell
;
2516 atm_aal5_ifEntry_t mib_aal5
;
2517 atm_aal5_vcc_x_t mib_vcc
;
2518 if (_IOC_TYPE(cmd
) != AMAZON_ATM_IOC_MAGIC
) return -ENOTTY
;
2519 if (_IOC_NR(cmd
) > AMAZON_ATM_IOC_MAXNR
) return -ENOTTY
;
2521 if (_IOC_DIR(cmd
) & _IOC_READ
)
2522 err
= !access_ok(VERIFY_WRITE
, (void *)arg
, _IOC_SIZE(cmd
));
2523 else if (_IOC_DIR(cmd
) & _IOC_WRITE
)
2524 err
= !access_ok(VERIFY_READ
, (void *)arg
, _IOC_SIZE(cmd
));
2526 AMAZON_TPE_EMSG("acess verification fails \n");
2530 case AMAZON_ATM_MIB_CELL
:
2531 err
= amazon_atm_cell_mib(&mib_cell
,(u32
)arg
);
2533 err
= __copy_to_user((void *)arg
,&mib_cell
,sizeof(mib_cell
));
2535 AMAZON_TPE_EMSG("cannot get MIB ATM_CELL\n");
2538 case AMAZON_ATM_MIB_AAL5
:
2539 err
= amazon_atm_aal5_mib(&mib_aal5
);
2541 err
=__copy_to_user(arg
, &mib_aal5
, sizeof(mib_aal5
));
2543 AMAZON_TPE_EMSG("cannot get MIB ATM_AAL5\n");
2546 case AMAZON_ATM_MIB_VCC
:
2547 err
=__copy_from_user(&mib_vcc
,arg
, sizeof(mib_vcc
));
2548 AMAZON_TPE_DMSG("return of copy_from_user %x\n",err
);
2549 err
= amazon_atm_vcc_mib_x(mib_vcc
.vpi
, mib_vcc
.vci
, &(mib_vcc
.mib_vcc
));
2551 err
=__copy_to_user(arg
, &mib_vcc
, sizeof(mib_vcc
));
2553 AMAZON_TPE_EMSG("cannot get MIB ATM_VCC\n");
2561 /* Brief: return a link list of OAM related time stamp info
2564 a link list of "struct oam_last_activity" data
2566 Each time, a F4/F5 cell or AAL5 packet is received, the time stamp is updated.
2567 Through this call, u get a list of this time stamp for all active connection.
2568 Please note that u have read-only access.
2570 const struct oam_last_activity
* get_oam_time_stamp()
2573 for(i
=CBM_DEFAULT_Q_OFFSET
+CBM_RX_OFFSET
,j
=0;i
<CBM_RX_OFFSET
+CBM_DEFAULT_Q_OFFSET
+AMAZON_ATM_MAX_VCC_NUM
;i
++){
2574 if (g_atm_dev
.queues
[i
].free
!= 1 && g_atm_dev
.queues
[i
].vcc
!= NULL
){
2577 g_oam_time_stamp
[j
-1].next
= &g_oam_time_stamp
[j
];
2579 g_oam_time_stamp
[j
].vpi
= g_atm_dev
.queues
[i
].vcc
->vpi
;
2580 g_oam_time_stamp
[j
].vci
= g_atm_dev
.queues
[i
].vcc
->vci
;
2581 g_oam_time_stamp
[j
].stamp
= g_atm_dev
.queues
[i
].access_time
;
2582 g_oam_time_stamp
[j
].next
= NULL
;
2589 return g_oam_time_stamp
;
2594 /* Brief: call back routine for rx
2596 * vcc atm_vcc pointer
2597 * skb data if no error
2598 err error flag, 0: no error, 1:error
2601 * <>0 cannot push up
2603 * release the packet if cannot push up
2605 static int amazon_atm_net_push(struct atm_vcc
*vcc
,struct sk_buff
*skb
, int err
)
2608 if (vcc
&& vcc
->stats
) {
2609 atomic_inc(&vcc
->stats
->rx_err
);
2612 ATM_SKB(skb
)->vcc
= vcc
;
2614 if (!atm_charge(vcc
, skb
->truesize
)){
2616 AMAZON_TPE_EMSG("no space for this vcc\n");
2617 dev_kfree_skb_any(skb
);
2620 atomic_inc(&vcc
->stats
->rx
);
2621 AMAZON_TPE_DMSG("push to vcc\n");
2626 int amazon_atm_net_send_oam(struct atm_vcc
*vcc
, void *cell
, int flags
)
2628 return amazon_atm_send_oam(vcc
,cell
,flags
);
2631 int amazon_atm_net_send(struct atm_vcc
*vcc
,struct sk_buff
*skb
)
2634 if (vcc
->qos
.aal
== ATM_AAL0
|| vcc
->qos
.aal
== ATM_AAL5
) {
2635 err
=amazon_atm_send(vcc
,skb
);
2638 err
= -EPROTONOSUPPORT
;
2641 atomic_inc(&vcc
->stats
->tx_err
);
2643 atomic_inc(&vcc
->stats
->tx
);
2645 AMAZON_TPE_DMSG("sent, tx_inuse:%u\n", atomic_read(&vcc
->tx_inuse
));
2649 int amazon_atm_net_open(struct atm_vcc
*vcc
,short vpi
, int vci
)
2651 vcc
->itf
= (int) vcc
->dev
->dev_data
;
2654 return(amazon_atm_open(vcc
,amazon_atm_net_push
));
2657 static int amazon_atm_change_qos(struct atm_vcc
*vcc
, struct atm_qos
*qos
, int flgs
)
2661 if (vcc
== NULL
|| qos
== NULL
){
2662 AMAZON_TPE_EMSG("invalid parameters\n");
2665 qid
= amazon_atm_get_queue(vcc
);
2666 if (valid_qid(qid
) != 1) {
2667 AMAZON_TPE_EMSG("no vcc connection opened\n");
2670 set_qsb(vcc
,qos
,qid
);
2674 static struct atmdev_ops amazon_atm_ops
= {
2675 open
: amazon_atm_net_open
,
2676 close
: amazon_atm_close
,
2677 ioctl
: amazon_atm_ioctl
,
2678 send
: amazon_atm_net_send
,
2679 send_oam
: amazon_atm_net_send_oam
,
2680 // getsockopt: amazon_atm_getsockopt,
2681 change_qos
: amazon_atm_change_qos
,
2682 // proc_read: amazon_atm_proc_read,
2684 }; // ATM device callback functions
2687 * brief "/proc" function
2689 int amazon_atm_read_procmem(char *buf
, char **start
, off_t offset
,int count
, int *eof
, void *data
)
2691 int buf_off
=0; /* for buf */
2693 int type
= (u32
)data
;//which module
2694 atm_aal5_ifEntry_t mib_aal5
;
2695 atm_cell_ifEntry_t mib_cell
;
2696 atm_aal5_vcc_t mib_vcc
;
2700 amazon_atm_aal5_mib(&mib_aal5
);
2702 buf_off
+=sprintf(buf
+buf_off
,"\n============= AAL5 Upstream =========\n");
2703 buf_off
+=sprintf(buf
+buf_off
,"received %u (pkts) from upper layer\n", mib_aal5
.ifOutUcastPkts
);
2704 buf_off
+=sprintf(buf
+buf_off
,"errors: %u (pkts)\n",mib_aal5
.ifOutErros
);
2705 buf_off
+=sprintf(buf
+buf_off
,"discards: %u (ptks)\n", mib_aal5
.ifOutDiscards
);
2706 buf_off
+=sprintf(buf
+buf_off
,"transmitted: %x-%x (bytes) \n",
2707 mib_aal5
.ifHCOutOctets_h
, mib_aal5
.ifHCOutOctets_l
);
2709 buf_off
+=sprintf(buf
+buf_off
,"\n============= AAL5 Downstream =========\n");
2710 buf_off
+=sprintf(buf
+buf_off
,"received %x-%x (bytes)\n",
2711 mib_aal5
.ifHCInOctets_h
,mib_aal5
.ifHCInOctets_l
);
2712 buf_off
+=sprintf(buf
+buf_off
,"discards: %u (ptks)\n",mib_aal5
.ifInDiscards
);
2713 buf_off
+=sprintf(buf
+buf_off
,"errors: %u (ptks)\n",mib_aal5
.ifInErrors
);
2714 buf_off
+=sprintf(buf
+buf_off
,"passed %u (ptks) to upper layer\n",mib_aal5
.ifInUcastPkts
);
2717 buf_off
+=sprintf(buf
+buf_off
,"\n============= ATM Cell =========\n");
2718 amazon_atm_cell_mib(&mib_cell
,0);
2719 #ifdef AMAZON_TPE_READ_ARC
2720 buf_off
+=sprintf(buf
+buf_off
,"Port 0: downstream received: %x-%x (bytes)\n",mib_cell
.ifHCInOctets_h
,mib_cell
.ifHCInOctets_l
);
2721 buf_off
+=sprintf(buf
+buf_off
,"Port 0: upstream transmitted: %x-%x (bytes)\n",mib_cell
.ifHCOutOctets_h
,mib_cell
.ifHCOutOctets_l
);
2722 buf_off
+=sprintf(buf
+buf_off
,"Port 0: downstream errors: %u (cells)\n",mib_cell
.ifInErrors
);
2723 amazon_atm_cell_mib(&mib_cell
,1);
2724 buf_off
+=sprintf(buf
+buf_off
,"Port 1: downstream received: %x-%x (bytes)\n",mib_cell
.ifHCInOctets_h
,mib_cell
.ifHCInOctets_l
);
2725 buf_off
+=sprintf(buf
+buf_off
,"Port 1: upstream transmitted: %x-%x (bytes)\n",mib_cell
.ifHCOutOctets_h
,mib_cell
.ifHCOutOctets_l
);
2726 buf_off
+=sprintf(buf
+buf_off
,"Port 1: downstream errors: %u (cells)\n",mib_cell
.ifInErrors
);
2728 buf_off
+=sprintf(buf
+buf_off
,"HTU discards: %u (cells)\n",mib_cell
.ifInUnknownProtos
);
2730 buf_off
+=sprintf(buf
+buf_off
,"\n====== Specials =====\n");
2731 buf_off
+=sprintf(buf
+buf_off
,"AAL5S PPD: %u (cells)\n",g_atm_dev
.mib_counter
.tx_ppd
);
2732 #ifdef AMAZON_TPE_SCR
2733 buf_off
+=sprintf(buf
+buf_off
,"Reassembly wait: %u \n",g_a5r_wait
);
2738 buf_off
+=sprintf(buf
+buf_off
,"[Interfaces]\n");
2739 for(i
=0;i
<AMAZON_ATM_PORT_NUM
;i
++){
2740 if (g_atm_dev
.ports
[i
].enable
==0){
2741 buf_off
+=sprintf(buf
+buf_off
,"\tport[%u] not in use\n",i
);
2743 buf_off
+=sprintf(buf
+buf_off
,"\tport[%u]\n\t\tmax_conn=%u\n"
2745 ,g_atm_dev
.ports
[i
].max_conn
2747 buf_off
+=sprintf(buf
+buf_off
,"\t\ttx_max=%u\n\t\trem=%u\n\t\tcur=%u\n"
2748 ,g_atm_dev
.ports
[i
].tx_max_cr
2749 ,g_atm_dev
.ports
[i
].tx_rem_cr
2750 ,g_atm_dev
.ports
[i
].tx_cur_cr
2757 buf_off
+=sprintf(buf
+buf_off
,"[AAL5]\n\tpad=%c(%x)\n\trx_mtu=%u\n\ttx_mtu=%u\n"
2758 ,g_atm_dev
.aal5
.padding_byte
2759 ,g_atm_dev
.aal5
.padding_byte
2760 ,g_atm_dev
.aal5
.rx_max_sdu
2761 ,g_atm_dev
.aal5
.tx_max_sdu
2764 buf_off
+=sprintf(buf
+buf_off
,
2765 "[CBM]\n\tnrt_thr=%u\n\tclp0_thr=%u\n\tclp1_thr=%u\n\ttx_q_threshold=%u\n\trx_q_threshold=%u\n\toam_q_threshold=%u\n\tfree_cell_cnt=%u\n"
2766 ,g_atm_dev
.cbm
.nrt_thr
2767 ,g_atm_dev
.cbm
.clp0_thr
2768 ,g_atm_dev
.cbm
.clp1_thr
2772 ,g_atm_dev
.cbm
.free_cell_cnt
2775 buf_off
+=sprintf(buf
+buf_off
,"[QSB]\n\ttau=%u\n\ttstepc=%u\n\tsbl=%u\n"
2777 ,g_atm_dev
.qsb
.tstepc
2780 buf_off
+=sprintf(buf
+buf_off
,"[Debugging]\n\taal5_need_copy=%u\n",g_atm_dev
.aal5
.cnt_cpy
);
2783 for(i
=CBM_DEFAULT_Q_OFFSET
,j
=0;i
<g_atm_dev
.cbm
.max_q_off
+CBM_DEFAULT_Q_OFFSET
;i
++){
2784 if (g_atm_dev
.queues
[i
].free
!=1){
2785 buf_off
+=sprintf(buf
+buf_off
,"vcc[%u]\n\tvpi=%u vci=%u itf=%u qid=%u access_time=%u.%u\n"
2787 ,g_atm_dev
.queues
[i
].vcc
->vpi
2788 ,g_atm_dev
.queues
[i
].vcc
->vci
2789 ,g_atm_dev
.queues
[i
].vcc
->itf
2791 ,(u32
)g_atm_dev
.queues
[i
+CBM_RX_OFFSET
].access_time
.tv_sec
2792 ,(u32
)g_atm_dev
.queues
[i
+CBM_RX_OFFSET
].access_time
.tv_usec
2794 buf_off
+=sprintf(buf
+buf_off
,"\tqos_tx class=%u max_pcr=%u pcr=%u min_pcr=%u scr=%u mbs=%u cdv=%u\n"
2795 ,g_atm_dev
.queues
[i
].vcc
->qos
.txtp
.traffic_class
2796 ,g_atm_dev
.queues
[i
].vcc
->qos
.txtp
.max_pcr
2797 ,g_atm_dev
.queues
[i
].vcc
->qos
.txtp
.pcr
2798 ,g_atm_dev
.queues
[i
].vcc
->qos
.txtp
.min_pcr
2799 ,g_atm_dev
.queues
[i
].vcc
->qos
.txtp
.scr
2800 ,g_atm_dev
.queues
[i
].vcc
->qos
.txtp
.mbs
2801 ,g_atm_dev
.queues
[i
].vcc
->qos
.txtp
.cdv
2803 buf_off
+=sprintf(buf
+buf_off
,"\tqos_rx class=%u max_pcr=%u pcr=%u min_pcr=%u scr=%u mbs=%u cdv=%u\n"
2804 ,g_atm_dev
.queues
[i
].vcc
->qos
.rxtp
.traffic_class
2805 ,g_atm_dev
.queues
[i
].vcc
->qos
.rxtp
.max_pcr
2806 ,g_atm_dev
.queues
[i
].vcc
->qos
.rxtp
.pcr
2807 ,g_atm_dev
.queues
[i
].vcc
->qos
.rxtp
.min_pcr
2808 ,g_atm_dev
.queues
[i
].vcc
->qos
.rxtp
.scr
2809 ,g_atm_dev
.queues
[i
].vcc
->qos
.rxtp
.mbs
2810 ,g_atm_dev
.queues
[i
].vcc
->qos
.rxtp
.cdv
2812 __amazon_atm_vcc_mib((i
+CBM_RX_OFFSET
),&mib_vcc
);
2813 buf_off
+=sprintf(buf
+buf_off
,"\tCRC error=%u\n", mib_vcc
.aal5VccCrcErrors
);
2814 buf_off
+=sprintf(buf
+buf_off
,"\toversized packet=%u\n", mib_vcc
.aal5VccOverSizedSDUs
);
2815 #ifdef AMAZON_ATM_DEBUG
2816 if ( valid_qid(i
+CBM_RX_OFFSET
)){
2817 buf_off
+=sprintf(buf
+buf_off
,"\tdownstream statics\n" );
2818 buf_off
+=sprintf(buf
+buf_off
,"\t\tpackets=%u\n",g_atm_dev
.queues
[i
+CBM_RX_OFFSET
].qs
[QS_PKT
]);
2819 buf_off
+=sprintf(buf
+buf_off
,"\t\terr_packets=%u\n",g_atm_dev
.queues
[i
+CBM_RX_OFFSET
].qs
[QS_ERR
] );
2820 buf_off
+=sprintf(buf
+buf_off
,"\t\tsw_dropped=%u\n",g_atm_dev
.queues
[i
+CBM_RX_OFFSET
].qs
[QS_SW_DROP
] );
2823 buf_off
+=sprintf(buf
+buf_off
,"\tupstream statics\n" );
2824 buf_off
+=sprintf(buf
+buf_off
,"\t\tpackets=%u\n",g_atm_dev
.queues
[i
].qs
[QS_PKT
]);
2825 buf_off
+=sprintf(buf
+buf_off
,"\t\terr_packets=%u\n",g_atm_dev
.queues
[i
].qs
[QS_ERR
] );
2826 buf_off
+=sprintf(buf
+buf_off
,"\t\thw_dropped=%u\n",g_atm_dev
.queues
[i
].qs
[QS_HW_DROP
] );
2827 buf_off
+=sprintf(buf
+buf_off
,"\t\tsw_dropped=%u\n",g_atm_dev
.queues
[i
].qs
[QS_SW_DROP
] );
2838 if(buf_off
>0) *eof
= 1;
2842 #ifdef AMAZON_TPE_AAL5_RECOVERY
2843 extern int (*tpe_reset
)(void);
2844 extern int (*tpe_start
)(void);
2845 extern int (*tpe_inject
)(void);
2846 /* Brief: Reset TPE hardware
2848 * This is a wordaround for AAL5 bug. It tries to reset TPE.
2849 * take care of software
2850 * setup all previous connection
2852 int amazon_tpe_reset(void)
2854 struct atm_vcc
* vcc
;
2859 unsigned int a_cfg_value
=0;
2860 unsigned int a_cfg_old_value
=0;
2861 atm_aal5_ifEntry_t mib_aal5
;
2862 atm_cell_ifEntry_t mib_cell
;
2864 //make sure all cells transmitting out first
2866 amazon_atm_aal5_mib(&mib_aal5
);
2867 reg_l
= g_atm_dev
.mib_counter
.tx_cnt_l
;
2868 reg_h
= g_atm_dev
.mib_counter
.tx_cnt_h
;
2871 amazon_atm_aal5_mib(&mib_aal5
);
2872 if( (reg_l
== g_atm_dev
.mib_counter
.tx_cnt_l
) && (reg_h
== g_atm_dev
.mib_counter
.tx_cnt_h
) ){
2875 AMAZON_TPE_DMSG("AAL5 Segmentation still in progress!\n");
2876 reg_l
= g_atm_dev
.mib_counter
.tx_cnt_l
;
2877 reg_h
= g_atm_dev
.mib_counter
.tx_cnt_h
;
2880 qd_addr
= (u8
*) KSEG1ADDR((unsigned long)g_atm_dev
.cbm
.qd_addr
);
2882 while ( (err
=readl(qd_addr
+i
*CBM_QD_SIZE
+0x8)&0xffff) !=0 ){
2884 AMAZON_TPE_DMSG("queue %u not empty (%u)\n",i
,err
);
2887 //insurance for interfaces between Aware and CARB
2889 amazon_atm_cell_mib(&mib_cell
,0);
2890 amazon_atm_cell_mib(&mib_cell
,1);
2891 amazon_atm_aal5_mib(&mib_aal5
);
2894 while ( (AMAZON_READ_REGISTER_L(AR_CELLRDY_BC0
) != 0 ) || (AMAZON_READ_REGISTER_L(AR_CELLRDY_BC0
) != 0 ) ){
2895 AMAZON_TPE_EMSG("\nwaiting for AWARE");
2896 AMAZON_TPE_EMSG(" BC0 %u ", AMAZON_READ_REGISTER_L(AR_CELLRDY_BC0
));
2897 AMAZON_TPE_EMSG(" BC1 %u ", AMAZON_READ_REGISTER_L(AR_CELLRDY_BC1
));
2898 AMAZON_TPE_EMSG("\n");
2901 // disable AAI module
2902 meiDebugRead(A_CFG_ADDR
,&a_cfg_value
,1);
2903 a_cfg_old_value
=a_cfg_value
;
2904 a_cfg_value
&= (~(0x2800));
2905 meiDebugWrite(A_CFG_ADDR
,&a_cfg_value
,1);
2908 meiDebugWrite(AR_CB0_STATUS_ADDR
,&a_cfg_value
,1);
2909 meiDebugWrite(AR_CB1_STATUS_ADDR
,&a_cfg_value
,1);
2911 if ( atm_init_hard(&g_atm_dev
) != 0){
2914 sema_init(&(g_atm_dev
.swie
.in_sem
), 1);
2916 clear_bit(SWIE_LOCK
, &(g_atm_dev
.swie
.lock
));
2918 init_waitqueue_head(&(g_atm_dev
.swie
.sleep
));
2920 for (i
=CBM_DEFAULT_Q_OFFSET
;i
<AMAZON_ATM_MAX_QUEUE_NUM
/2;i
++) {
2921 vcc
= g_atm_dev
.queues
[i
].vcc
;
2923 set_qsb(vcc
, &vcc
->qos
, i
);
2928 AMAZON_TPE_EMSG("set htu entry fails %u\n",err
);
2932 meiDebugWrite(A_CFG_ADDR
,&a_cfg_old_value
,1);
2935 *(AMAZON_RST_REQ
) = (* AMAZON_RST_REQ
) | (AMAZON_RST_REQ_DFE
);
2937 *(AMAZON_RST_REQ
) = (* AMAZON_RST_REQ
) & (~AMAZON_RST_REQ_DFE
);
2944 /* Brief: Send a ATM EoP packet to save DMA channel
2946 int amazon_tpe_inject_debug_cell(void)
2948 //Send a ATM cell to save DMA channel
2950 unsigned char atm_cell
[48];
2952 AMAZON_TPE_DMSG("qid = %d\n",qid
);
2953 memset(atm_cell
,0,48);
2955 if ( amazon_atm_swin(qid
,atm_cell
)) {
2956 AMAZON_TPE_EMSG("cannot insert EoP cell\n");
2962 /* Brief: start HTU (TPE)
2965 int amazon_tpe_start(void)
2967 AMAZON_WRITE_REGISTER_L(HTU_CFG_START
,HTU_CFG_ADDR
);
2971 #endif //AMAZON_TPE_AAL5_RECOVERY
2973 #ifdef AMAZON_CHECK_LINK
2974 extern int (*adsl_link_notify
)(int);
2975 /* Brief: notify link status of ADSL link
2976 * Parameters: 0 link down
2979 * Details: called by MEI driver
2980 * should update status and inform upper layer
2982 int amazon_tpe_link_notify(int status
)
2984 adsl_link_status
= status
;
2985 AMAZON_TPE_DMSG("link status %s\n",(status
==1)?"Up":"Down");
2987 //wait until no cells in upstream queues
2988 set_current_state(TASK_INTERRUPTIBLE
);
2989 schedule_timeout(2*HZ
);
2993 #endif //ifdef AMAZON_CHECK_LINK
2996 * Brief: Initialize ATM module
2998 * Return Value: ENOMEM - No memory available
2999 * EBUSY - Cannot register atm device
3000 * ERESTARTSYS - Process interrupted by other signal
3001 * 0 - OK, module initialized
3004 * This function registers an atm device for all UTOPIA devices.
3005 * It also allocates memory for the private device data structures
3007 int __init
amazon_atm_net_init(void)
3011 amazon_atm_dev_t
*dev
= NULL
;
3013 if ((dev
=amazon_atm_create()) != NULL
){
3014 for(i
=0;i
<AMAZON_ATM_PORT_NUM
;i
++){
3015 if (!dev
->ports
[i
].enable
){
3016 amazon_atm_devs
[i
] = NULL
;
3019 amazon_atm_devs
[i
] =atm_dev_register("amazon_atm",&amazon_atm_ops
,-1,0UL);
3020 if (amazon_atm_devs
[i
] == NULL
){
3021 AMAZON_TPE_EMSG("atm_dev_register fails\n");
3023 goto amazon_atm_net_init_exit
;
3025 AMAZON_TPE_DMSG("registering device %u\n",i
);
3026 amazon_atm_devs
[i
]->ci_range
.vpi_bits
= 8;
3027 amazon_atm_devs
[i
]->ci_range
.vci_bits
= 16;
3028 amazon_atm_devs
[i
]->link_rate
= dev
->ports
[i
].tx_max_cr
;
3029 amazon_atm_devs
[i
]->dev_data
= (void *) i
;
3035 AMAZON_TPE_EMSG("cannot init atm device\n");
3036 goto amazon_atm_net_init_exit
;
3038 #ifdef AMAZON_TPE_AAL5_RECOVERY
3039 tpe_reset
= & amazon_tpe_reset
;
3040 tpe_start
= & amazon_tpe_start
;
3041 tpe_inject
= & amazon_tpe_inject_debug_cell
;
3042 #endif //AMAZON_TPE_AAL5_RECOVERY
3043 #ifdef AMAZON_CHECK_LINK
3044 adsl_link_notify
=amazon_tpe_link_notify
;
3045 #endif //AMAZON_CHECK_LINK
3046 amazon_atm_net_init_exit
:
3050 void __exit
amazon_atm_net_cleanup(void)
3053 amazon_atm_cleanup();
3054 for(i
=0;i
<AMAZON_ATM_PORT_NUM
;i
++){
3055 if (amazon_atm_devs
[i
] != NULL
){
3056 AMAZON_TPE_DMSG("unregister dev %u\n",i
);
3057 atm_dev_deregister(amazon_atm_devs
[i
]);
3062 EXPORT_SYMBOL(get_oam_time_stamp
);
3064 MODULE_LICENSE ("GPL");
3065 MODULE_AUTHOR("Infineon IFAP DC COM peng.liu@infineon.com");
3066 MODULE_DESCRIPTION("AMAZON ATM driver");
3068 module_init(amazon_atm_net_init
);
3069 module_exit(amazon_atm_net_cleanup
);