#include #include #include "common.h" void mailbox_signal(unsigned int channel, int is_tx) { if(is_tx) { while(MBOX_IGU3_ISR_ISR(channel + 16)); *MBOX_IGU3_ISRS = MBOX_IGU3_ISRS_SET(channel + 16); } else { while(MBOX_IGU3_ISR_ISR(channel)); *MBOX_IGU3_ISRS = MBOX_IGU3_ISRS_SET(channel); } } static int mailbox_rx_irq_handler(unsigned int channel, unsigned int *len) { int conn; int skb_base; register struct rx_descriptor reg_desc; struct rx_descriptor *desc; struct sk_buff *skb; struct atm_vcc *vcc; struct rx_inband_trailer *trailer; /* get sk_buff pointer and descriptor */ skb_base = ppe_dev.dma.rx_descriptor_number * channel + ppe_dev.dma.rx_desc_read_pos[channel]; desc = &ppe_dev.dma.rx_descriptor_base[skb_base]; reg_desc = *desc; if ( reg_desc.own || !reg_desc.c ) return -EAGAIN; if ( ++ppe_dev.dma.rx_desc_read_pos[channel] == ppe_dev.dma.rx_descriptor_number ) ppe_dev.dma.rx_desc_read_pos[channel] = 0; skb = *(struct sk_buff **)((((u32)reg_desc.dataptr << 2) | KSEG0) - 4); if ( (u32)skb <= 0x80000000 ) { int key = 0; printk("skb problem: skb = %08X, system is panic!\n", (u32)skb); for ( ; !key; ); } conn = reg_desc.id; if ( conn == ppe_dev.oam_rx_queue ) { /* OAM */ struct uni_cell_header *header = (struct uni_cell_header *)skb->data; if ( header->pti == ATM_PTI_SEGF5 || header->pti == ATM_PTI_E2EF5 ) conn = find_vpivci(header->vpi, header->vci); else if ( header->vci == 0x03 || header->vci == 0x04 ) conn = find_vpi(header->vpi); else conn = -1; if ( conn >= 0 && ppe_dev.connection[conn].vcc != NULL ) { vcc = ppe_dev.connection[conn].vcc; ppe_dev.connection[conn].access_time = xtime; if ( vcc->push_oam != NULL ) vcc->push_oam(vcc, skb->data); } /* don't need resize */ } else { if ( len ) *len = 0; if ( ppe_dev.connection[conn].vcc != NULL ) { vcc = ppe_dev.connection[conn].vcc; if ( !reg_desc.err ) if ( vcc->qos.aal == ATM_AAL5 ) { /* AAL5 packet */ resize_skb_rx(skb, reg_desc.datalen + reg_desc.byteoff, 0); skb_reserve(skb, reg_desc.byteoff); skb_put(skb, reg_desc.datalen); if ( (u32)ATM_SKB(skb) <= 0x80000000 ) { int key = 0; printk("ATM_SKB(skb) problem: ATM_SKB(skb) = %08X, system is panic!\n", (u32)ATM_SKB(skb)); for ( ; !key; ); } ATM_SKB(skb)->vcc = vcc; ppe_dev.connection[conn].access_time = xtime; if ( atm_charge(vcc, skb->truesize) ) { struct sk_buff *new_skb; new_skb = alloc_skb_rx(); if ( new_skb ) { UPDATE_VCC_STAT(conn, rx_pdu, 1); ppe_dev.mib.wrx_pdu++; if ( vcc->stats ) atomic_inc(&vcc->stats->rx); vcc->push(vcc, skb); { struct k_atm_aal_stats stats = *vcc->stats; int flag = 0; vcc->push(vcc, skb); if ( vcc->stats->rx.counter != stats.rx.counter ) { printk("vcc->stats->rx (diff) = %d", vcc->stats->rx.counter - stats.rx.counter); flag++; } if ( vcc->stats->rx_err.counter != stats.rx_err.counter ) { printk("vcc->stats->rx_err (diff) = %d", vcc->stats->rx_err.counter - stats.rx_err.counter); flag++; } if ( vcc->stats->rx_drop.counter != stats.rx_drop.counter ) { printk("vcc->stats->rx_drop (diff) = %d", vcc->stats->rx_drop.counter - stats.rx_drop.counter); flag++; } if ( vcc->stats->tx.counter != stats.tx.counter ) { printk("vcc->stats->tx (diff) = %d", vcc->stats->tx.counter - stats.tx.counter); flag++; } if ( vcc->stats->tx_err.counter != stats.tx_err.counter ) { printk("vcc->stats->tx_err (diff) = %d", vcc->stats->tx_err.counter - stats.tx_err.counter); flag++; } if ( !flag ) printk("vcc->stats not changed"); } reg_desc.dataptr = (u32)new_skb->data >> 2; if ( len ) *len = reg_desc.datalen; } else { /* no sk buffer */ UPDATE_VCC_STAT(conn, rx_sw_drop_pdu, 1); ppe_dev.mib.wrx_drop_pdu++; if ( vcc->stats ) atomic_inc(&vcc->stats->rx_drop); resize_skb_rx(skb, ppe_dev.aal5.rx_buffer_size, 0); } } else { /* no enough space */ UPDATE_VCC_STAT(conn, rx_sw_drop_pdu, 1); ppe_dev.mib.wrx_drop_pdu++; if ( vcc->stats ) atomic_inc(&vcc->stats->rx_drop); resize_skb_rx(skb, ppe_dev.aal5.rx_buffer_size, 0); } } else { /* AAL0 cell */ resize_skb_rx(skb, CELL_SIZE, 1); skb_put(skb, CELL_SIZE); ATM_SKB(skb)->vcc = vcc; ppe_dev.connection[conn].access_time = xtime; if ( atm_charge(vcc, skb->truesize) ) { struct sk_buff *new_skb; new_skb = alloc_skb_rx(); if ( new_skb ) { if ( vcc->stats ) atomic_inc(&vcc->stats->rx); vcc->push(vcc, skb); reg_desc.dataptr = (u32)new_skb->data >> 2; if ( len ) *len = CELL_SIZE; } else { if ( vcc->stats ) atomic_inc(&vcc->stats->rx_drop); resize_skb_rx(skb, ppe_dev.aal5.rx_buffer_size, 0); } } else { if ( vcc->stats ) atomic_inc(&vcc->stats->rx_drop); resize_skb_rx(skb, ppe_dev.aal5.rx_buffer_size, 0); } } else { printk("reg_desc.err\n"); /* drop packet/cell */ if ( vcc->qos.aal == ATM_AAL5 ) { UPDATE_VCC_STAT(conn, rx_err_pdu, 1); trailer = (struct rx_inband_trailer *)((u32)skb->data + ((reg_desc.byteoff + reg_desc.datalen + DMA_ALIGNMENT - 1) & ~ (DMA_ALIGNMENT - 1))); if ( trailer->stw_crc ) ppe_dev.connection[conn].aal5_vcc_crc_err++; if ( trailer->stw_ovz ) ppe_dev.connection[conn].aal5_vcc_oversize_sdu++; } if ( vcc->stats ) atomic_inc(&vcc->stats->rx_err); /* don't need resize */ } } else { printk("ppe_dev.connection[%d].vcc == NULL\n", conn); ppe_dev.mib.wrx_drop_pdu++; /* don't need resize */ } } reg_desc.byteoff = 0; reg_desc.datalen = ppe_dev.aal5.rx_buffer_size; reg_desc.own = 1; reg_desc.c = 0; /* write discriptor to memory */ *desc = reg_desc; printk("leave mailbox_rx_irq_handler"); return 0; } static inline void mailbox_tx_irq_handler(unsigned int conn) { if ( ppe_dev.dma.tx_desc_alloc_flag[conn] ) { int desc_base; int *release_pos; struct sk_buff *skb; release_pos = &ppe_dev.dma.tx_desc_release_pos[conn]; desc_base = ppe_dev.dma.tx_descriptor_number * (conn - QSB_QUEUE_NUMBER_BASE) + *release_pos; while ( !ppe_dev.dma.tx_descriptor_base[desc_base].own ) { skb = ppe_dev.dma.tx_skb_pointers[desc_base]; ppe_dev.dma.tx_descriptor_base[desc_base].own = 1; // pretend PP32 hold owner bit, so that won't be released more than once, so allocation process don't check this bit if ( ++*release_pos == ppe_dev.dma.tx_descriptor_number ) *release_pos = 0; if ( *release_pos == ppe_dev.dma.tx_desc_alloc_pos[conn] ) { ppe_dev.dma.tx_desc_alloc_flag[conn] = 0; atm_free_tx_skb_vcc(skb); break; } if ( *release_pos == 0 ) desc_base = ppe_dev.dma.tx_descriptor_number * (conn - QSB_QUEUE_NUMBER_BASE); else desc_base++; atm_free_tx_skb_vcc(skb); } } } #if defined(ENABLE_RX_QOS) && ENABLE_RX_QOS static inline int check_desc_valid(unsigned int channel) { int skb_base; struct rx_descriptor *desc; skb_base = ppe_dev.dma.rx_descriptor_number * channel + ppe_dev.dma.rx_desc_read_pos[channel]; desc = &ppe_dev.dma.rx_descriptor_base[skb_base]; return !desc->own && desc->c ? 1 : 0; } #endif irqreturn_t mailbox_irq_handler(int irq, void *dev_id) { int channel_mask; /* DMA channel accordant IRQ bit mask */ int channel; unsigned int rx_irq_number[MAX_RX_DMA_CHANNEL_NUMBER] = {0}; unsigned int total_rx_irq_number = 0; printk("mailbox_irq_handler"); if ( !*MBOX_IGU1_ISR ) return IRQ_RETVAL(1); channel_mask = 1; channel = 0; while ( channel < ppe_dev.dma.rx_total_channel_used ) { if ( (*MBOX_IGU1_ISR & channel_mask) ) { /* RX */ /* clear IRQ */ *MBOX_IGU1_ISRC = channel_mask; printk(" RX: *MBOX_IGU1_ISR = 0x%08X\n", *MBOX_IGU1_ISR); /* wait for mailbox cleared */ while ( (*MBOX_IGU3_ISR & channel_mask) ); /* shadow the number of valid descriptor */ rx_irq_number[channel] = WRX_DMA_CHANNEL_CONFIG(channel)->vlddes; total_rx_irq_number += rx_irq_number[channel]; printk("total_rx_irq_number = %d", total_rx_irq_number); printk("vlddes = %d, rx_irq_number[%d] = %d, total_rx_irq_number = %d\n", WRX_DMA_CHANNEL_CONFIG(channel)->vlddes, channel, rx_irq_number[channel], total_rx_irq_number); } channel_mask <<= 1; channel++; } channel_mask = 1 << (16 + QSB_QUEUE_NUMBER_BASE); channel = QSB_QUEUE_NUMBER_BASE; while ( channel - QSB_QUEUE_NUMBER_BASE < ppe_dev.dma.tx_total_channel_used ) { if ( (*MBOX_IGU1_ISR & channel_mask) ) { // if ( channel != 1 ) // { printk("TX irq error\n"); // while ( 1 ) // { // } // } /* TX */ /* clear IRQ */ *MBOX_IGU1_ISRC = channel_mask; printk(" TX: *MBOX_IGU1_ISR = 0x%08X\n", *MBOX_IGU1_ISR); mailbox_tx_irq_handler(channel); } channel_mask <<= 1; channel++; } #if defined(ENABLE_RX_QOS) && ENABLE_RX_QOS channel = 0; while ( total_rx_irq_number ) { switch ( channel ) { case RX_DMA_CH_CBR: case RX_DMA_CH_OAM: /* handle it as soon as possible */ while ( rx_irq_number[channel] != 0 && mailbox_rx_irq_handler(channel, NULL) == 0 ) { rx_irq_number[channel]--; total_rx_irq_number--; printk("RX_DMA_CH_CBR, total_rx_irq_number = %d", total_rx_irq_number); printk("RX_DMA_CH_CBR, total_rx_irq_number = %d, rx_irq_number[%d] = %d\n", total_rx_irq_number, channel, rx_irq_number[channel]); /* signal firmware that descriptor is updated */ mailbox_signal(channel, 0); } // if ( rx_irq_number[channel] != 0 ) printk("RX_DMA_CH_CBR, rx_irq_number[channel] = %d", rx_irq_number[channel]); break; case RX_DMA_CH_VBR_RT: /* WFQ */ if ( rx_irq_number[RX_DMA_CH_VBR_RT] != 0 && (rx_irq_number[RX_DMA_CH_VBR_NRT] == 0 || !check_desc_valid(RX_DMA_CH_VBR_NRT) || ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT] < ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT]) && (rx_irq_number[RX_DMA_CH_AVR] == 0 || !check_desc_valid(RX_DMA_CH_AVR) || ppe_dev.dma.rx_weight[RX_DMA_CH_AVR] < ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT]) ) { unsigned int len; if ( mailbox_rx_irq_handler(RX_DMA_CH_VBR_RT, &len) == 0 ) { rx_irq_number[RX_DMA_CH_VBR_RT]--; total_rx_irq_number--; printk("RX_DMA_CH_VBR_RT, total_rx_irq_number = %d", total_rx_irq_number); printk("RX_DMA_CH_VBR_RT, total_rx_irq_number = %d, rx_irq_number[%d] = %d\n", total_rx_irq_number, channel, rx_irq_number[channel]); /* signal firmware that descriptor is updated */ mailbox_signal(channel, 0); len = (len + CELL_SIZE - 1) / CELL_SIZE; if ( ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT] <= len ) ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT] = ppe_dev.dma.rx_default_weight[RX_DMA_CH_VBR_RT] + ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT] - len; } } // if ( rx_irq_number[channel] != 0 ) // { printk("RX_DMA_CH_VBR_RT, rx_irq_number[channel] = %d, total_rx_irq_number = %d", rx_irq_number[channel], total_rx_irq_number); // rx_irq_number[channel] = 0; // total_rx_irq_number = 0; // } break; case RX_DMA_CH_VBR_NRT: /* WFQ */ if ( rx_irq_number[RX_DMA_CH_VBR_NRT] != 0 && (rx_irq_number[RX_DMA_CH_VBR_RT] == 0 || !check_desc_valid(RX_DMA_CH_VBR_RT) || ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT] < ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT]) && (rx_irq_number[RX_DMA_CH_AVR] == 0 || !check_desc_valid(RX_DMA_CH_AVR) || ppe_dev.dma.rx_weight[RX_DMA_CH_AVR] < ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT]) ) { unsigned int len; if ( mailbox_rx_irq_handler(RX_DMA_CH_VBR_NRT, &len) == 0 ) { rx_irq_number[RX_DMA_CH_VBR_NRT]--; total_rx_irq_number--; printk("RX_DMA_CH_VBR_NRT, total_rx_irq_number = %d", total_rx_irq_number); printk("RX_DMA_CH_VBR_NRT, total_rx_irq_number = %d, rx_irq_number[%d] = %d\n", total_rx_irq_number, channel, rx_irq_number[channel]); /* signal firmware that descriptor is updated */ mailbox_signal(channel, 0); len = (len + CELL_SIZE - 1) / CELL_SIZE; if ( ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT] <= len ) ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT] = ppe_dev.dma.rx_default_weight[RX_DMA_CH_VBR_NRT] + ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT] - len; } } // if ( rx_irq_number[channel] != 0 ) printk("RX_DMA_CH_VBR_NRT, rx_irq_number[channel] = %d", rx_irq_number[channel]); break; case RX_DMA_CH_AVR: /* WFQ */ if ( rx_irq_number[RX_DMA_CH_AVR] != 0 && (rx_irq_number[RX_DMA_CH_VBR_RT] == 0 || !check_desc_valid(RX_DMA_CH_VBR_RT) || ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_RT] < ppe_dev.dma.rx_weight[RX_DMA_CH_AVR]) && (rx_irq_number[RX_DMA_CH_VBR_NRT] == 0 || !check_desc_valid(RX_DMA_CH_VBR_NRT) || ppe_dev.dma.rx_weight[RX_DMA_CH_VBR_NRT] < ppe_dev.dma.rx_weight[RX_DMA_CH_AVR]) ) { unsigned int len; if ( mailbox_rx_irq_handler(RX_DMA_CH_AVR, &len) == 0 ) { rx_irq_number[RX_DMA_CH_AVR]--; total_rx_irq_number--; printk("RX_DMA_CH_AVR, total_rx_irq_number = %d", total_rx_irq_number); printk("RX_DMA_CH_AVR, total_rx_irq_number = %d, rx_irq_number[%d] = %d\n", total_rx_irq_number, channel, rx_irq_number[channel]); /* signal firmware that descriptor is updated */ mailbox_signal(channel, 0); len = (len + CELL_SIZE - 1) / CELL_SIZE; if ( ppe_dev.dma.rx_weight[RX_DMA_CH_AVR] <= len ) ppe_dev.dma.rx_weight[RX_DMA_CH_AVR] = ppe_dev.dma.rx_default_weight[RX_DMA_CH_AVR] + ppe_dev.dma.rx_weight[RX_DMA_CH_AVR] - len; } } // if ( rx_irq_number[channel] != 0 ) printk("RX_DMA_CH_AVR, rx_irq_number[channel] = %d", rx_irq_number[channel]); break; case RX_DMA_CH_UBR: default: /* Handle it when all others are handled or others are not available to handle. */ if ( rx_irq_number[channel] != 0 && (rx_irq_number[RX_DMA_CH_VBR_RT] == 0 || !check_desc_valid(RX_DMA_CH_VBR_RT)) && (rx_irq_number[RX_DMA_CH_VBR_NRT] == 0 || !check_desc_valid(RX_DMA_CH_VBR_NRT)) && (rx_irq_number[RX_DMA_CH_AVR] == 0 || !check_desc_valid(RX_DMA_CH_AVR)) ) if ( mailbox_rx_irq_handler(channel, NULL) == 0 ) { rx_irq_number[channel]--; total_rx_irq_number--; printk("RX_DMA_CH_UBR, total_rx_irq_number = %d, rx_irq_number[%d] = %d", total_rx_irq_number, channel, rx_irq_number[channel]); printk("RX_DMA_CH_UBR, total_rx_irq_number = %d, rx_irq_number[%d] = %d\n", total_rx_irq_number, channel, rx_irq_number[channel]); /* signal firmware that descriptor is updated */ mailbox_signal(channel, 0); } printk("RX_DMA_CH_UBR, rx_irq_number[channel] = %d", rx_irq_number[channel]); } if ( ++channel == ppe_dev.dma.rx_total_channel_used ) channel = 0; } #else channel = 0; while ( total_rx_irq_number ) { while ( rx_irq_number[channel] != 0 && mailbox_rx_irq_handler(channel, NULL) == 0 ) { rx_irq_number[channel]--; total_rx_irq_number--; /* signal firmware that descriptor is updated */ mailbox_signal(channel, 0); } if ( ++channel == ppe_dev.dma.rx_total_channel_used ) channel = 0; } #endif // defined(ENABLE_RX_QOS) && ENABLE_RX_QOS return IRQ_RETVAL(1); }