diff options
Diffstat (limited to 'drivers/net/ibm_newemac/mal.c')
-rw-r--r-- | drivers/net/ibm_newemac/mal.c | 487 |
1 files changed, 453 insertions, 34 deletions
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c index 2a2fc17b287..1f79a34bedf 100644 --- a/drivers/net/ibm_newemac/mal.c +++ b/drivers/net/ibm_newemac/mal.c @@ -29,8 +29,23 @@ #include "core.h" #include <asm/dcr-regs.h> +#include <asm/ppc4xx_ocm.h> static int mal_count; +#ifdef CONFIG_IBM_NEW_EMAC_INTR_COALESCE +static char *tx_coal_irqname[] = { + "TX0 COAL", + "TX1 COAL", + "TX2 COAL", + "TX3 COAL", +}; +static char *rx_coal_irqname[] = { + "RX0 COAL", + "RX1 COAL", + "RX2 COAL", + "RX3 COAL", +}; +#endif int __devinit mal_register_commac(struct mal_instance *mal, struct mal_commac *commac) @@ -217,9 +232,176 @@ static inline void mal_disable_eob_irq(struct mal_instance *mal) MAL_DBG2(mal, "disable_irq" NL); } +#ifdef CONFIG_IBM_NEW_EMAC_INTR_COALESCE + +#if defined(CONFIG_460SX) +/* Set Tx fram count */ +static inline void set_ic_txfthr(struct mal_instance *mal) +{ + int reg; + int val = mal->coales_param[0].tx_count; + + reg = (val<<23) | (1<<22) ; + + SDR_WRITE(DCRN_SDR0_ICCRTX0, reg); /* set counter */ + SDR_WRITE(DCRN_SDR0_ICCRTX0,(val<<23)); /* enable counter */ + + SDR_WRITE(DCRN_SDR0_ICCRTX1, reg); /* set counter */ + SDR_WRITE(DCRN_SDR0_ICCRTX1,(val<<23)); /* enable counter */ + + SDR_WRITE(DCRN_SDR0_ICCRTX2, reg); /* set counter */ + SDR_WRITE(DCRN_SDR0_ICCRTX2,(val<<23)); /* enable counter */ + + SDR_WRITE(DCRN_SDR0_ICCRTX3, reg); /* set counter */ + SDR_WRITE(DCRN_SDR0_ICCRTX3,(val<<23)); /* enable counter */ + + + mal->enet_coales_iccrtx = reg; +} +/* Set Rx fram count */ +static inline void set_ic_rxfthr(struct mal_instance *mal) +{ + int reg; + int val = mal->coales_param[0].rx_count; + + reg = (val<<23) | (1<<22) ; + + SDR_WRITE(DCRN_SDR0_ICCRRX0,reg); /* set counter */ + SDR_WRITE(DCRN_SDR0_ICCRRX0,(val<<23)); /* enable counter */ + + SDR_WRITE(DCRN_SDR0_ICCRRX1,reg); /* set counter */ + SDR_WRITE(DCRN_SDR0_ICCRRX1,(val<<23)); /* enable counter */ + + SDR_WRITE(DCRN_SDR0_ICCRRX2,reg); /* set counter */ + SDR_WRITE(DCRN_SDR0_ICCRRX2,(val<<23)); /* enable counter */ + + SDR_WRITE(DCRN_SDR0_ICCRRX3,reg); /* set counter */ + SDR_WRITE(DCRN_SDR0_ICCRRX3,(val<<23)); /* enable counter */ + + mal->enet_coales_iccrrx = reg; +} +#endif + +inline void mal_enable_coal(struct mal_instance *mal) +{ + unsigned int val; +#if defined(CONFIG_405EX) + /* Clear the counters */ + val = SDR0_ICC_FLUSH0 | SDR0_ICC_FLUSH1; + mtdcri(SDR0, DCRN_SDR0_ICCRTX, val); + mtdcri(SDR0, DCRN_SDR0_ICCRRX, val); + + /* Set Tx/Rx Timer values */ + mtdcri(SDR0, DCRN_SDR0_ICCTRTX0, CONFIG_IBM_NEW_EMAC_TX_COAL_TIMER); + mtdcri(SDR0, DCRN_SDR0_ICCTRTX1, CONFIG_IBM_NEW_EMAC_TX_COAL_TIMER); + mtdcri(SDR0, DCRN_SDR0_ICCTRRX0, CONFIG_IBM_NEW_EMAC_RX_COAL_TIMER); + mtdcri(SDR0, DCRN_SDR0_ICCTRRX1, CONFIG_IBM_NEW_EMAC_RX_COAL_TIMER); + + /* Enable the Tx/Rx Coalescing interrupt */ + val = ((CONFIG_IBM_NEW_EMAC_TX_COAL_COUNT & COAL_FRAME_MASK) + << SDR0_ICC_FTHR0_SHIFT) | + ((CONFIG_IBM_NEW_EMAC_TX_COAL_COUNT & COAL_FRAME_MASK) + << SDR0_ICC_FTHR1_SHIFT); + mtdcri(SDR0, DCRN_SDR0_ICCRTX, val); + + val = ((CONFIG_IBM_NEW_EMAC_RX_COAL_COUNT & COAL_FRAME_MASK) + << SDR0_ICC_FTHR0_SHIFT) | + ((CONFIG_IBM_NEW_EMAC_RX_COAL_COUNT & COAL_FRAME_MASK) + << SDR0_ICC_FTHR1_SHIFT); + + mtdcri(SDR0, DCRN_SDR0_ICCRRX, val); +#elif defined(CONFIG_APM82181) + /* Clear the counters */ + val = SDR0_ICC_FLUSH; + mtdcri(SDR0, DCRN_SDR0_ICCRTX0, val); + mtdcri(SDR0, DCRN_SDR0_ICCRRX0, val); + + /* Set Tx/Rx Timer values */ + mtdcri(SDR0, DCRN_SDR0_ICCTRTX0, mal->coales_param[0].tx_time); + mtdcri(SDR0, DCRN_SDR0_ICCTRRX0, mal->coales_param[0].rx_time); + + /* Enable the Tx/Rx Coalescing interrupt */ + val = (mal->coales_param[0].tx_count & COAL_FRAME_MASK) + << SDR0_ICC_FTHR_SHIFT; + mtdcri(SDR0, DCRN_SDR0_ICCRTX0, val); + + val = (mal->coales_param[0].rx_count & COAL_FRAME_MASK) + << SDR0_ICC_FTHR_SHIFT; + mtdcri(SDR0, DCRN_SDR0_ICCRRX0, val); + +#elif defined(CONFIG_460EX) || defined(CONFIG_460GT) + /* Clear the counters */ + val = SDR0_ICC_FLUSH; + mtdcri(SDR0, DCRN_SDR0_ICCRTX0, val); + mtdcri(SDR0, DCRN_SDR0_ICCRTX1, val); + mtdcri(SDR0, DCRN_SDR0_ICCRRX0, val); + mtdcri(SDR0, DCRN_SDR0_ICCRRX1, val); +#if defined(CONFIG_460GT) + mtdcri(SDR0, DCRN_SDR0_ICCRTX2, val); + mtdcri(SDR0, DCRN_SDR0_ICCRTX3, val); + mtdcri(SDR0, DCRN_SDR0_ICCRRX2, val); + mtdcri(SDR0, DCRN_SDR0_ICCRRX3, val); +#endif + + /* Set Tx/Rx Timer values */ + mtdcri(SDR0, DCRN_SDR0_ICCTRTX0, CONFIG_IBM_NEW_EMAC_TX_COAL_TIMER); + mtdcri(SDR0, DCRN_SDR0_ICCTRTX1, CONFIG_IBM_NEW_EMAC_TX_COAL_TIMER); + mtdcri(SDR0, DCRN_SDR0_ICCTRRX0, CONFIG_IBM_NEW_EMAC_RX_COAL_TIMER); + mtdcri(SDR0, DCRN_SDR0_ICCTRRX1, CONFIG_IBM_NEW_EMAC_RX_COAL_TIMER); +#if defined(CONFIG_460GT) + mtdcri(SDR0, DCRN_SDR0_ICCTRTX2, CONFIG_IBM_NEW_EMAC_TX_COAL_TIMER); + mtdcri(SDR0, DCRN_SDR0_ICCTRTX3, CONFIG_IBM_NEW_EMAC_TX_COAL_TIMER); + mtdcri(SDR0, DCRN_SDR0_ICCTRRX2, CONFIG_IBM_NEW_EMAC_RX_COAL_TIMER); + mtdcri(SDR0, DCRN_SDR0_ICCTRRX3, CONFIG_IBM_NEW_EMAC_RX_COAL_TIMER); +#endif + + /* Enable the Tx/Rx Coalescing interrupt */ + val = (CONFIG_IBM_NEW_EMAC_TX_COAL_COUNT & COAL_FRAME_MASK) + << SDR0_ICC_FTHR_SHIFT; + mtdcri(SDR0, DCRN_SDR0_ICCRTX0, val); + mtdcri(SDR0, DCRN_SDR0_ICCRTX1, val); +#if defined(CONFIG_460GT) + mtdcri(SDR0, DCRN_SDR0_ICCRTX2, val); + mtdcri(SDR0, DCRN_SDR0_ICCRTX3, val); +#endif + + val = (CONFIG_IBM_NEW_EMAC_RX_COAL_COUNT & COAL_FRAME_MASK) + << SDR0_ICC_FTHR_SHIFT; + mtdcri(SDR0, DCRN_SDR0_ICCRRX0, val); + mtdcri(SDR0, DCRN_SDR0_ICCRRX1, val); +#if defined(CONFIG_460GT) + mtdcri(SDR0, DCRN_SDR0_ICCRRX2, val); + mtdcri(SDR0, DCRN_SDR0_ICCRRX3, val); +#endif + +#elif defined(CONFIG_460SX) + mtdcri(SDR0, DCRN_SDR0_ICCTRTX0, mal->coales_param[0].tx_time); + mtdcri(SDR0, DCRN_SDR0_ICCTRTX1, mal->coales_param[1].tx_time); + mtdcri(SDR0, DCRN_SDR0_ICCTRTX2, mal->coales_param[2].tx_time); + mtdcri(SDR0, DCRN_SDR0_ICCTRTX3, mal->coales_param[3].tx_time); + + mtdcri(SDR0, DCRN_SDR0_ICCTRRX0, mal->coales_param[0].rx_time); + mtdcri(SDR0, DCRN_SDR0_ICCTRRX1, mal->coales_param[1].rx_time); + mtdcri(SDR0, DCRN_SDR0_ICCTRRX2, mal->coales_param[2].rx_time); + mtdcri(SDR0, DCRN_SDR0_ICCTRRX3, mal->coales_param[3].rx_time); + + set_ic_rxfthr(mal); + set_ic_txfthr(mal); +#endif + printk(KERN_INFO "MAL: Enabled Interrupt Coal TxCnt: %d RxCnt: %d\n", + mal->coales_param[0].tx_count, + mal->coales_param[0].rx_count); + + printk(KERN_INFO " TxTimer: %d RxTimer: %d\n", + mal->coales_param[0].tx_time, + mal->coales_param[0].rx_time); +} +#endif + static irqreturn_t mal_serr(int irq, void *dev_instance) { struct mal_instance *mal = dev_instance; + struct list_head *l; u32 esr = get_mal_dcrn(mal, MAL_ESR); @@ -256,6 +438,14 @@ static irqreturn_t mal_serr(int irq, void *dev_instance) "mal%d: system error, OPB (ESR = 0x%08x)\n", mal->index, esr); } + + + list_for_each(l, &mal->poll_list) { + struct mal_commac *mc = + list_entry(l, struct mal_commac, poll_list); + mc->ops->reset(mc->dev); + } + return IRQ_HANDLED; } @@ -309,6 +499,15 @@ static irqreturn_t mal_rxeob(int irq, void *dev_instance) return IRQ_HANDLED; } +#ifdef CONFIG_IBM_NEW_EMAC_INTR_COALESCE +static irqreturn_t mal_coal(int irq, void *dev_instance) +{ + struct mal_instance *mal = dev_instance; + mal_schedule_poll(mal); + return IRQ_HANDLED; +} +#endif + static irqreturn_t mal_txde(int irq, void *dev_instance) { struct mal_instance *mal = dev_instance; @@ -393,6 +592,9 @@ void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac) static int mal_poll(struct napi_struct *napi, int budget) { +#if defined(CONFIG_IBM_EMAC_MAL_QOS_V404) + int v; +#endif struct mal_instance *mal = container_of(napi, struct mal_instance, napi); struct list_head *l; int received = 0; @@ -455,6 +657,32 @@ static int mal_poll(struct napi_struct *napi, int budget) mc->ops->poll_tx(mc->dev); } +#if defined(CONFIG_IBM_EMAC_MAL_QOS_V404) + /* Process RX skbs QOS virtual channels. + * + */ + for ( v = 1; v < MAX_VCHANS; v++ ) { + list_for_each(l, &mal->poll_list) { + struct mal_commac *mc = + list_entry(l, struct mal_commac, poll_list); + struct emac_instance *dev = mc->dev; + int n; + if ( v >= dev->rx_vchans ) { + continue; + } + n = mc->ops->poll_rx(dev->vdev[v],budget); + if (n) { + received += n; + budget -= n; + if (budget <= 0) { + goto more_work; + } + } + } + + } +#endif + more_work: MAL_DBG2(mal, "poll() %d <- %d" NL, budget, received); return received; @@ -516,6 +744,7 @@ void *mal_dump_regs(struct mal_instance *mal, void *buf) return regs + 1; } + static int __devinit mal_probe(struct of_device *ofdev, const struct of_device_id *match) { @@ -524,9 +753,14 @@ static int __devinit mal_probe(struct of_device *ofdev, int index = mal_count++; unsigned int dcr_base; const u32 *prop; + const char *str_prop; u32 cfg; unsigned long irqflags; irq_handler_t hdlr_serr, hdlr_txde, hdlr_rxde; +#ifdef CONFIG_IBM_NEW_EMAC_INTR_COALESCE + int num_phys_chans; + int coal_intr_index; +#endif mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL); if (!mal) { @@ -541,6 +775,13 @@ static int __devinit mal_probe(struct of_device *ofdev, MAL_DBG(mal, "probe" NL); + str_prop = of_get_property(ofdev->node, "descriptor-memory", NULL); + if (str_prop && (!strcmp(str_prop,"ocm") || !strcmp(str_prop,"OCM"))) { + printk(KERN_INFO + "mal%d: descriptor-memory = %s\n", index, str_prop); + mal->desc_memory = MAL_DESC_MEM_OCM; + } + prop = of_get_property(ofdev->node, "num-tx-chans", NULL); if (prop == NULL) { printk(KERN_ERR @@ -609,6 +850,46 @@ static int __devinit mal_probe(struct of_device *ofdev, goto fail_unmap; } +#ifdef CONFIG_IBM_NEW_EMAC_INTR_COALESCE + /* Number of Tx channels is equal to Physical channels */ + /* Rx channels include Virtual channels so use Tx channels */ + BUG_ON(mal->num_tx_chans > MAL_MAX_PHYS_CHANNELS); + num_phys_chans = mal->num_tx_chans; + /* Older revs in 460EX and 460GT have coalesce bug in h/w */ +#if defined(CONFIG_460EX) || defined(CONFIG_460GT) + { + unsigned int pvr; + unsigned short min; + pvr = mfspr(SPRN_PVR); + min = PVR_MIN(pvr); + if (min < 4) { + printk(KERN_INFO "PVR %x Intr Coal disabled: H/W bug\n", + pvr); + mal->coalesce_disabled = 1; + } + } +#else + mal->coalesce_disabled = 0; +#endif + coal_intr_index = 5; + + /* If device tree doesn't Interrupt coal IRQ, fall back to EOB IRQ */ + for (i = 0; (i < num_phys_chans) && (mal->coalesce_disabled == 0) ; i++) { + mal->txcoal_irq[i] = irq_of_parse_and_map(ofdev->node, coal_intr_index++); + if (mal->txcoal_irq[i] == NO_IRQ) { + printk(KERN_INFO "MAL: No device tree IRQ for TxCoal%d - disabling coalescing\n", i); + mal->coalesce_disabled = 1; + } + } + for (i = 0; (i < num_phys_chans) && (mal->coalesce_disabled == 0); i++) { + mal->rxcoal_irq[i] = irq_of_parse_and_map(ofdev->node, coal_intr_index++); + if (mal->rxcoal_irq[i] == NO_IRQ) { + printk(KERN_INFO "MAL: No device tree IRQ for RxCoal%d - disabling coalescing\n", i); + mal->coalesce_disabled = 1; + } + } +#endif + INIT_LIST_HEAD(&mal->poll_list); INIT_LIST_HEAD(&mal->list); spin_lock_init(&mal->lock); @@ -641,9 +922,25 @@ static int __devinit mal_probe(struct of_device *ofdev, bd_size = sizeof(struct mal_descriptor) * (NUM_TX_BUFF * mal->num_tx_chans + NUM_RX_BUFF * mal->num_rx_chans); - mal->bd_virt = - dma_alloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma, - GFP_KERNEL); + + if (mal->desc_memory == MAL_DESC_MEM_OCM) { + mal->bd_virt = ocm_alloc(&mal->bd_phys, bd_size, 4, + OCM_NON_CACHED, "mal_descriptors"); + mal->bd_dma = (u32)mal->bd_phys; + } + + if (mal->bd_virt == NULL) { + /* Allocate BD on SDRAM in case !MAL_DESC_MEM_OCM or failed OCM alloc */ + if (mal->desc_memory == MAL_DESC_MEM_OCM){ + printk(KERN_INFO + "mal%d: failed OCM alloc, descriptor-memory = SDRAM\n", index); + mal->desc_memory = MAL_DESC_MEM_SDRAM; + } + mal->bd_virt = dma_alloc_coherent(&ofdev->dev, bd_size, + &mal->bd_dma, GFP_KERNEL); + } + + if (mal->bd_virt == NULL) { printk(KERN_ERR "mal%d: out of memory allocating RX/TX descriptors!\n", @@ -651,17 +948,25 @@ static int __devinit mal_probe(struct of_device *ofdev, err = -ENOMEM; goto fail_unmap; } + memset(mal->bd_virt, 0, bd_size); + for (i = 0; i < mal->num_tx_chans; ++i) { + if (mal->desc_memory == MAL_DESC_MEM_OCM) + set_mal_dcrn(mal, MAL_TXBADDR, (mal->bd_phys >> 32)); - for (i = 0; i < mal->num_tx_chans; ++i) set_mal_dcrn(mal, MAL_TXCTPR(i), mal->bd_dma + sizeof(struct mal_descriptor) * mal_tx_bd_offset(mal, i)); + } + + for (i = 0; i < mal->num_rx_chans; ++i) { + if (mal->desc_memory == MAL_DESC_MEM_OCM) + set_mal_dcrn(mal, MAL_RXBADDR, (u32)(mal->bd_phys >> 32)); - for (i = 0; i < mal->num_rx_chans; ++i) set_mal_dcrn(mal, MAL_RXCTPR(i), mal->bd_dma + sizeof(struct mal_descriptor) * mal_rx_bd_offset(mal, i)); + } if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) { irqflags = IRQF_SHARED; @@ -674,20 +979,65 @@ static int __devinit mal_probe(struct of_device *ofdev, } err = request_irq(mal->serr_irq, hdlr_serr, irqflags, "MAL SERR", mal); - if (err) - goto fail2; + if (err) { + mal->serr_irq = NO_IRQ; + goto failirq; + } err = request_irq(mal->txde_irq, hdlr_txde, irqflags, "MAL TX DE", mal); - if (err) - goto fail3; - err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); - if (err) - goto fail4; + if (err) { + mal->txde_irq = NO_IRQ; + goto failirq; + } err = request_irq(mal->rxde_irq, hdlr_rxde, irqflags, "MAL RX DE", mal); - if (err) - goto fail5; - err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); - if (err) - goto fail6; + if (err) { + mal->rxde_irq = NO_IRQ; + goto failirq; + } +#ifdef CONFIG_IBM_NEW_EMAC_INTR_COALESCE + for (i = 0; (i < num_phys_chans) && (mal->coalesce_disabled == 0); i++) { + err = request_irq(mal->txcoal_irq[i], + mal_coal, 0, tx_coal_irqname[i], mal); + if (err) { + printk(KERN_INFO "MAL: TxCoal%d ReqIRQ failed - disabling coalescing\n", i); + mal->txcoal_irq[i] = NO_IRQ; + mal->coalesce_disabled = 1; + break; + } + } + for (i = 0; (i < num_phys_chans) && (mal->coalesce_disabled == 0); i++) { + err = request_irq(mal->rxcoal_irq[i], + mal_coal, 0, rx_coal_irqname[i], mal); + if (err) { + printk(KERN_INFO "MAL: RxCoal%d ReqIRQ failed - disabling coalescing\n", i); + mal->rxcoal_irq[i] = NO_IRQ; + mal->coalesce_disabled = 1; + break; + } + } + + /* Fall back to EOB IRQ if coalesce not supported */ + if (mal->coalesce_disabled) { + /* Clean up any IRQs allocated for Coalescing */ + for (i = 0; i < num_phys_chans; i++) { + if (mal->txcoal_irq[i] != NO_IRQ) + free_irq(mal->txcoal_irq[i], mal); + if (mal->rxcoal_irq[i] != NO_IRQ) + free_irq(mal->rxcoal_irq[i], mal); + } +#endif + err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); + if (err) { + mal->txeob_irq = NO_IRQ; + goto failirq; + } + err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); + if (err) { + mal->rxeob_irq = NO_IRQ; + goto failirq; + } +#ifdef CONFIG_IBM_NEW_EMAC_INTR_COALESCE + } +#endif /* Enable all MAL SERR interrupt sources */ if (mal->version == 2) @@ -695,6 +1045,31 @@ static int __devinit mal_probe(struct of_device *ofdev, else set_mal_dcrn(mal, MAL_IER, MAL1_IER_EVENTS); +#ifdef CONFIG_IBM_NEW_EMAC_INTR_COALESCE + if (mal->coalesce_disabled == 0) { + mal->coales_param[0].tx_count = (CONFIG_IBM_NEW_EMAC_TX_COAL_COUNT & COAL_FRAME_MASK); + mal->coales_param[1].tx_count = (CONFIG_IBM_NEW_EMAC_TX_COAL_COUNT & COAL_FRAME_MASK); + mal->coales_param[2].tx_count = (CONFIG_IBM_NEW_EMAC_TX_COAL_COUNT & COAL_FRAME_MASK); + mal->coales_param[3].tx_count = (CONFIG_IBM_NEW_EMAC_TX_COAL_COUNT & COAL_FRAME_MASK); + + mal->coales_param[0].rx_count = (CONFIG_IBM_NEW_EMAC_RX_COAL_COUNT & COAL_FRAME_MASK); + mal->coales_param[1].rx_count = (CONFIG_IBM_NEW_EMAC_RX_COAL_COUNT & COAL_FRAME_MASK); + mal->coales_param[2].rx_count = (CONFIG_IBM_NEW_EMAC_RX_COAL_COUNT & COAL_FRAME_MASK); + mal->coales_param[3].rx_count = (CONFIG_IBM_NEW_EMAC_RX_COAL_COUNT & COAL_FRAME_MASK); + + mal->coales_param[0].tx_time = CONFIG_IBM_NEW_EMAC_TX_COAL_TIMER; + mal->coales_param[1].tx_time = CONFIG_IBM_NEW_EMAC_TX_COAL_TIMER; + mal->coales_param[2].tx_time = CONFIG_IBM_NEW_EMAC_TX_COAL_TIMER; + mal->coales_param[3].tx_time = CONFIG_IBM_NEW_EMAC_TX_COAL_TIMER; + + mal->coales_param[0].rx_time = CONFIG_IBM_NEW_EMAC_RX_COAL_TIMER; + mal->coales_param[1].rx_time = CONFIG_IBM_NEW_EMAC_RX_COAL_TIMER; + mal->coales_param[2].rx_time = CONFIG_IBM_NEW_EMAC_RX_COAL_TIMER; + mal->coales_param[3].rx_time = CONFIG_IBM_NEW_EMAC_RX_COAL_TIMER; + + mal_enable_coal(mal); +} +#endif /* Enable EOB interrupt */ mal_enable_eob_irq(mal); @@ -711,16 +1086,35 @@ static int __devinit mal_probe(struct of_device *ofdev, return 0; - fail6: - free_irq(mal->rxde_irq, mal); - fail5: - free_irq(mal->txeob_irq, mal); - fail4: - free_irq(mal->txde_irq, mal); - fail3: - free_irq(mal->serr_irq, mal); - fail2: - dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma); + failirq: + if (mal->serr_irq != NO_IRQ) + free_irq(mal->serr_irq, mal); + if (mal->txde_irq != NO_IRQ) + free_irq(mal->txde_irq, mal); + if (mal->rxde_irq != NO_IRQ) + free_irq(mal->rxde_irq, mal); +#ifdef CONFIG_IBM_NEW_EMAC_INTR_COALESCE + if (mal->coalesce_disabled == 0) { + for (i = 0; i < num_phys_chans; i++) { + if (mal->txcoal_irq[i] != NO_IRQ) + free_irq(mal->txcoal_irq[i], mal); + if (mal->rxcoal_irq[i] != NO_IRQ) + free_irq(mal->rxcoal_irq[i], mal); + } + } else { +#endif + if (mal->txeob_irq != NO_IRQ) + free_irq(mal->txeob_irq, mal); + if (mal->rxeob_irq != NO_IRQ) + free_irq(mal->rxeob_irq, mal); +#ifdef CONFIG_IBM_NEW_EMAC_INTR_COALESCE + } +#endif + if (mal->desc_memory == MAL_DESC_MEM_OCM) + ocm_free(mal->bd_virt); + else + dma_free_coherent(&ofdev->dev, bd_size, + mal->bd_virt, mal->bd_dma); fail_unmap: dcr_unmap(mal->dcr_host, 0x100); fail: @@ -732,6 +1126,10 @@ static int __devinit mal_probe(struct of_device *ofdev, static int __devexit mal_remove(struct of_device *ofdev) { struct mal_instance *mal = dev_get_drvdata(&ofdev->dev); +#ifdef CONFIG_IBM_NEW_EMAC_INTR_COALESCE + int i; + int num_phys_chans; +#endif MAL_DBG(mal, "remove" NL); @@ -748,17 +1146,38 @@ static int __devexit mal_remove(struct of_device *ofdev) dev_set_drvdata(&ofdev->dev, NULL); - free_irq(mal->serr_irq, mal); - free_irq(mal->txde_irq, mal); - free_irq(mal->txeob_irq, mal); - free_irq(mal->rxde_irq, mal); - free_irq(mal->rxeob_irq, mal); - + if (mal->serr_irq != NO_IRQ) + free_irq(mal->serr_irq, mal); + if (mal->txde_irq != NO_IRQ) + free_irq(mal->txde_irq, mal); + if (mal->rxde_irq != NO_IRQ) + free_irq(mal->rxde_irq, mal); +#ifdef CONFIG_IBM_NEW_EMAC_INTR_COALESCE + num_phys_chans = mal->num_tx_chans; + if (mal->coalesce_disabled == 0) { + for (i = 0; i < num_phys_chans; i++) { + if (mal->txcoal_irq[i] != NO_IRQ) + free_irq(mal->txcoal_irq[i], mal); + if (mal->rxcoal_irq[i] != NO_IRQ) + free_irq(mal->rxcoal_irq[i], mal); + } + } else { +#endif + if (mal->txeob_irq != NO_IRQ) + free_irq(mal->txeob_irq, mal); + if (mal->rxeob_irq != NO_IRQ) + free_irq(mal->rxeob_irq, mal); +#ifdef CONFIG_IBM_NEW_EMAC_INTR_COALESCE + } +#endif mal_reset(mal); mal_dbg_unregister(mal); - dma_free_coherent(&ofdev->dev, + if (mal->desc_memory == MAL_DESC_MEM_OCM) + ocm_free(mal->bd_virt); + else + dma_free_coherent(&ofdev->dev, sizeof(struct mal_descriptor) * (NUM_TX_BUFF * mal->num_tx_chans + NUM_RX_BUFF * mal->num_rx_chans), mal->bd_virt, |