diff options
Diffstat (limited to 'drivers/net/ibm_emac/ibm_emac_mal.c')
| -rw-r--r-- | drivers/net/ibm_emac/ibm_emac_mal.c | 463 |
1 files changed, 0 insertions, 463 deletions
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c deleted file mode 100644 index e59f57f363c..00000000000 --- a/drivers/net/ibm_emac/ibm_emac_mal.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - * ibm_ocp_mal.c - * - * Armin Kuster akuster@mvista.com - * Juen, 2002 - * - * Copyright 2002 MontaVista Softare Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/netdevice.h> -#include <linux/init.h> -#include <linux/dma-mapping.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/ocp.h> - -#include "ibm_emac_mal.h" - -// Locking: Should we share a lock with the client ? The client could provide -// a lock pointer (optionally) in the commac structure... I don't think this is -// really necessary though - -/* This lock protects the commac list. On today UP implementations, it's - * really only used as IRQ protection in mal_{register,unregister}_commac() - */ -static DEFINE_RWLOCK(mal_list_lock); - -int mal_register_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac) -{ - unsigned long flags; - - write_lock_irqsave(&mal_list_lock, flags); - - /* Don't let multiple commacs claim the same channel */ - if ((mal->tx_chan_mask & commac->tx_chan_mask) || - (mal->rx_chan_mask & commac->rx_chan_mask)) { - write_unlock_irqrestore(&mal_list_lock, flags); - return -EBUSY; - } - - mal->tx_chan_mask |= commac->tx_chan_mask; - mal->rx_chan_mask |= commac->rx_chan_mask; - - list_add(&commac->list, &mal->commac); - - write_unlock_irqrestore(&mal_list_lock, flags); - - return 0; -} - -int mal_unregister_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac) -{ - unsigned long flags; - - write_lock_irqsave(&mal_list_lock, flags); - - mal->tx_chan_mask &= ~commac->tx_chan_mask; - mal->rx_chan_mask &= ~commac->rx_chan_mask; - - list_del_init(&commac->list); - - write_unlock_irqrestore(&mal_list_lock, flags); - - return 0; -} - -int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, unsigned long size) -{ - switch (channel) { - case 0: - set_mal_dcrn(mal, DCRN_MALRCBS0, size); - break; -#ifdef DCRN_MALRCBS1 - case 1: - set_mal_dcrn(mal, DCRN_MALRCBS1, size); - break; -#endif -#ifdef DCRN_MALRCBS2 - case 2: - set_mal_dcrn(mal, DCRN_MALRCBS2, size); - break; -#endif -#ifdef DCRN_MALRCBS3 - case 3: - set_mal_dcrn(mal, DCRN_MALRCBS3, size); - break; -#endif - default: - return -EINVAL; - } - - return 0; -} - -static irqreturn_t mal_serr(int irq, void *dev_instance, struct pt_regs *regs) -{ - struct ibm_ocp_mal *mal = dev_instance; - unsigned long mal_error; - - /* - * This SERR applies to one of the devices on the MAL, here we charge - * it against the first EMAC registered for the MAL. - */ - - mal_error = get_mal_dcrn(mal, DCRN_MALESR); - - printk(KERN_ERR "%s: System Error (MALESR=%lx)\n", - "MAL" /* FIXME: get the name right */ , mal_error); - - /* FIXME: decipher error */ - /* DIXME: distribute to commacs, if possible */ - - /* Clear the error status register */ - set_mal_dcrn(mal, DCRN_MALESR, mal_error); - - return IRQ_HANDLED; -} - -static irqreturn_t mal_txeob(int irq, void *dev_instance, struct pt_regs *regs) -{ - struct ibm_ocp_mal *mal = dev_instance; - struct list_head *l; - unsigned long isr; - - isr = get_mal_dcrn(mal, DCRN_MALTXEOBISR); - set_mal_dcrn(mal, DCRN_MALTXEOBISR, isr); - - read_lock(&mal_list_lock); - list_for_each(l, &mal->commac) { - struct mal_commac *mc = list_entry(l, struct mal_commac, list); - - if (isr & mc->tx_chan_mask) { - mc->ops->txeob(mc->dev, isr & mc->tx_chan_mask); - } - } - read_unlock(&mal_list_lock); - - return IRQ_HANDLED; -} - -static irqreturn_t mal_rxeob(int irq, void *dev_instance, struct pt_regs *regs) -{ - struct ibm_ocp_mal *mal = dev_instance; - struct list_head *l; - unsigned long isr; - - isr = get_mal_dcrn(mal, DCRN_MALRXEOBISR); - set_mal_dcrn(mal, DCRN_MALRXEOBISR, isr); - - read_lock(&mal_list_lock); - list_for_each(l, &mal->commac) { - struct mal_commac *mc = list_entry(l, struct mal_commac, list); - - if (isr & mc->rx_chan_mask) { - mc->ops->rxeob(mc->dev, isr & mc->rx_chan_mask); - } - } - read_unlock(&mal_list_lock); - - return IRQ_HANDLED; -} - -static irqreturn_t mal_txde(int irq, void *dev_instance, struct pt_regs *regs) -{ - struct ibm_ocp_mal *mal = dev_instance; - struct list_head *l; - unsigned long deir; - - deir = get_mal_dcrn(mal, DCRN_MALTXDEIR); - - /* FIXME: print which MAL correctly */ - printk(KERN_WARNING "%s: Tx descriptor error (MALTXDEIR=%lx)\n", - "MAL", deir); - - read_lock(&mal_list_lock); - list_for_each(l, &mal->commac) { - struct mal_commac *mc = list_entry(l, struct mal_commac, list); - - if (deir & mc->tx_chan_mask) { - mc->ops->txde(mc->dev, deir & mc->tx_chan_mask); - } - } - read_unlock(&mal_list_lock); - - return IRQ_HANDLED; -} - -/* - * This interrupt should be very rare at best. This occurs when - * the hardware has a problem with the receive descriptors. The manual - * states that it occurs when the hardware cannot the receive descriptor - * empty bit is not set. The recovery mechanism will be to - * traverse through the descriptors, handle any that are marked to be - * handled and reinitialize each along the way. At that point the driver - * will be restarted. - */ -static irqreturn_t mal_rxde(int irq, void *dev_instance, struct pt_regs *regs) -{ - struct ibm_ocp_mal *mal = dev_instance; - struct list_head *l; - unsigned long deir; - - deir = get_mal_dcrn(mal, DCRN_MALRXDEIR); - - /* - * This really is needed. This case encountered in stress testing. - */ - if (deir == 0) - return IRQ_HANDLED; - - /* FIXME: print which MAL correctly */ - printk(KERN_WARNING "%s: Rx descriptor error (MALRXDEIR=%lx)\n", - "MAL", deir); - - read_lock(&mal_list_lock); - list_for_each(l, &mal->commac) { - struct mal_commac *mc = list_entry(l, struct mal_commac, list); - - if (deir & mc->rx_chan_mask) { - mc->ops->rxde(mc->dev, deir & mc->rx_chan_mask); - } - } - read_unlock(&mal_list_lock); - - return IRQ_HANDLED; -} - -static int __init mal_probe(struct ocp_device *ocpdev) -{ - struct ibm_ocp_mal *mal = NULL; - struct ocp_func_mal_data *maldata; - int err = 0; - - maldata = (struct ocp_func_mal_data *)ocpdev->def->additions; - if (maldata == NULL) { - printk(KERN_ERR "mal%d: Missing additional datas !\n", - ocpdev->def->index); - return -ENODEV; - } - - mal = kmalloc(sizeof(struct ibm_ocp_mal), GFP_KERNEL); - if (mal == NULL) { - printk(KERN_ERR - "mal%d: Out of memory allocating MAL structure !\n", - ocpdev->def->index); - return -ENOMEM; - } - memset(mal, 0, sizeof(*mal)); - - switch (ocpdev->def->index) { - case 0: - mal->dcrbase = DCRN_MAL_BASE; - break; -#ifdef DCRN_MAL1_BASE - case 1: - mal->dcrbase = DCRN_MAL1_BASE; - break; -#endif - default: - BUG(); - } - - /**************************/ - - INIT_LIST_HEAD(&mal->commac); - - set_mal_dcrn(mal, DCRN_MALRXCARR, 0xFFFFFFFF); - set_mal_dcrn(mal, DCRN_MALTXCARR, 0xFFFFFFFF); - - set_mal_dcrn(mal, DCRN_MALCR, MALCR_MMSR); /* 384 */ - /* FIXME: Add delay */ - - /* Set the MAL configuration register */ - set_mal_dcrn(mal, DCRN_MALCR, - MALCR_PLBB | MALCR_OPBBL | MALCR_LEA | - MALCR_PLBLT_DEFAULT); - - /* It would be nice to allocate buffers separately for each - * channel, but we can't because the channels share the upper - * 13 bits of address lines. Each channels buffer must also - * be 4k aligned, so we allocate 4k for each channel. This is - * inefficient FIXME: do better, if possible */ - mal->tx_virt_addr = dma_alloc_coherent(&ocpdev->dev, - MAL_DT_ALIGN * - maldata->num_tx_chans, - &mal->tx_phys_addr, GFP_KERNEL); - if (mal->tx_virt_addr == NULL) { - printk(KERN_ERR - "mal%d: Out of memory allocating MAL descriptors !\n", - ocpdev->def->index); - err = -ENOMEM; - goto fail; - } - - /* God, oh, god, I hate DCRs */ - set_mal_dcrn(mal, DCRN_MALTXCTP0R, mal->tx_phys_addr); -#ifdef DCRN_MALTXCTP1R - if (maldata->num_tx_chans > 1) - set_mal_dcrn(mal, DCRN_MALTXCTP1R, - mal->tx_phys_addr + MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP1R */ -#ifdef DCRN_MALTXCTP2R - if (maldata->num_tx_chans > 2) - set_mal_dcrn(mal, DCRN_MALTXCTP2R, - mal->tx_phys_addr + 2 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP2R */ -#ifdef DCRN_MALTXCTP3R - if (maldata->num_tx_chans > 3) - set_mal_dcrn(mal, DCRN_MALTXCTP3R, - mal->tx_phys_addr + 3 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP3R */ -#ifdef DCRN_MALTXCTP4R - if (maldata->num_tx_chans > 4) - set_mal_dcrn(mal, DCRN_MALTXCTP4R, - mal->tx_phys_addr + 4 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP4R */ -#ifdef DCRN_MALTXCTP5R - if (maldata->num_tx_chans > 5) - set_mal_dcrn(mal, DCRN_MALTXCTP5R, - mal->tx_phys_addr + 5 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP5R */ -#ifdef DCRN_MALTXCTP6R - if (maldata->num_tx_chans > 6) - set_mal_dcrn(mal, DCRN_MALTXCTP6R, - mal->tx_phys_addr + 6 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP6R */ -#ifdef DCRN_MALTXCTP7R - if (maldata->num_tx_chans > 7) - set_mal_dcrn(mal, DCRN_MALTXCTP7R, - mal->tx_phys_addr + 7 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP7R */ - - mal->rx_virt_addr = dma_alloc_coherent(&ocpdev->dev, - MAL_DT_ALIGN * - maldata->num_rx_chans, - &mal->rx_phys_addr, GFP_KERNEL); - - set_mal_dcrn(mal, DCRN_MALRXCTP0R, mal->rx_phys_addr); -#ifdef DCRN_MALRXCTP1R - if (maldata->num_rx_chans > 1) - set_mal_dcrn(mal, DCRN_MALRXCTP1R, - mal->rx_phys_addr + MAL_DT_ALIGN); -#endif /* DCRN_MALRXCTP1R */ -#ifdef DCRN_MALRXCTP2R - if (maldata->num_rx_chans > 2) - set_mal_dcrn(mal, DCRN_MALRXCTP2R, - mal->rx_phys_addr + 2 * MAL_DT_ALIGN); -#endif /* DCRN_MALRXCTP2R */ -#ifdef DCRN_MALRXCTP3R - if (maldata->num_rx_chans > 3) - set_mal_dcrn(mal, DCRN_MALRXCTP3R, - mal->rx_phys_addr + 3 * MAL_DT_ALIGN); -#endif /* DCRN_MALRXCTP3R */ - - err = request_irq(maldata->serr_irq, mal_serr, 0, "MAL SERR", mal); - if (err) - goto fail; - err = request_irq(maldata->txde_irq, mal_txde, 0, "MAL TX DE ", mal); - if (err) - goto fail; - err = request_irq(maldata->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); - if (err) - goto fail; - err = request_irq(maldata->rxde_irq, mal_rxde, 0, "MAL RX DE", mal); - if (err) - goto fail; - err = request_irq(maldata->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); - if (err) - goto fail; - - set_mal_dcrn(mal, DCRN_MALIER, - MALIER_DE | MALIER_NE | MALIER_TE | - MALIER_OPBE | MALIER_PLBE); - - /* Advertise me to the rest of the world */ - ocp_set_drvdata(ocpdev, mal); - - printk(KERN_INFO "mal%d: Initialized, %d tx channels, %d rx channels\n", - ocpdev->def->index, maldata->num_tx_chans, - maldata->num_rx_chans); - - return 0; - - fail: - /* FIXME: dispose requested IRQs ! */ - if (err && mal) - kfree(mal); - return err; -} - -static void __exit mal_remove(struct ocp_device *ocpdev) -{ - struct ibm_ocp_mal *mal = ocp_get_drvdata(ocpdev); - struct ocp_func_mal_data *maldata = ocpdev->def->additions; - - BUG_ON(!maldata); - - ocp_set_drvdata(ocpdev, NULL); - - /* FIXME: shut down the MAL, deal with dependency with emac */ - free_irq(maldata->serr_irq, mal); - free_irq(maldata->txde_irq, mal); - free_irq(maldata->txeob_irq, mal); - free_irq(maldata->rxde_irq, mal); - free_irq(maldata->rxeob_irq, mal); - - if (mal->tx_virt_addr) - dma_free_coherent(&ocpdev->dev, - MAL_DT_ALIGN * maldata->num_tx_chans, - mal->tx_virt_addr, mal->tx_phys_addr); - - if (mal->rx_virt_addr) - dma_free_coherent(&ocpdev->dev, - MAL_DT_ALIGN * maldata->num_rx_chans, - mal->rx_virt_addr, mal->rx_phys_addr); - - kfree(mal); -} - -/* Structure for a device driver */ -static struct ocp_device_id mal_ids[] = { - {.vendor = OCP_ANY_ID,.function = OCP_FUNC_MAL}, - {.vendor = OCP_VENDOR_INVALID} -}; - -static struct ocp_driver mal_driver = { - .name = "mal", - .id_table = mal_ids, - - .probe = mal_probe, - .remove = mal_remove, -}; - -static int __init init_mals(void) -{ - int rc; - - rc = ocp_register_driver(&mal_driver); - if (rc < 0) { - ocp_unregister_driver(&mal_driver); - return -ENODEV; - } - - return 0; -} - -static void __exit exit_mals(void) -{ - ocp_unregister_driver(&mal_driver); -} - -module_init(init_mals); -module_exit(exit_mals); |
