diff --git a/[refs] b/[refs] index 16edddcd3eaa..f8b61bd6f429 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 955c5038823748e529a49f0e33ab635d92843500 +refs/heads/master: b59a9504cb93db7fae31e60760725d48652a1fc3 diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 251a28e2d4cc..770155a01523 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -1945,14 +1945,6 @@ M: george@mvista.com L: netdev@vger.kernel.org S: Supported -POWERPC 4xx EMAC DRIVER -P: Eugene Surovegin -M: ebs@ebshome.net -W: http://kernel.ebshome.net/emac/ -L: linuxppc-embedded@ozlabs.org -L: netdev@vger.kernel.org -S: Maintained - PNP SUPPORT P: Adam Belay M: ambx1@neo.rr.com diff --git a/trunk/arch/mips/kernel/entry.S b/trunk/arch/mips/kernel/entry.S index 5eb429137e06..5e9a44168681 100644 --- a/trunk/arch/mips/kernel/entry.S +++ b/trunk/arch/mips/kernel/entry.S @@ -128,28 +128,25 @@ FEXPORT(syscall_exit_work) /* * Common spurious interrupt handler. */ - .text - .align 5 LEAF(spurious_interrupt) /* * Someone tried to fool us by sending an interrupt but we * couldn't find a cause for it. */ + PTR_LA t1, irq_err_count #ifdef CONFIG_SMP - lui t1, %hi(irq_err_count) -1: ll t0, %lo(irq_err_count)(t1) +1: ll t0, (t1) addiu t0, 1 - sc t0, %lo(irq_err_count)(t1) + sc t0, (t1) #if R10000_LLSC_WAR beqzl t0, 1b #else beqz t0, 1b #endif #else - lui t1, %hi(irq_err_count) - lw t0, %lo(irq_err_count)(t1) + lw t0, (t1) addiu t0, 1 - sw t0, %lo(irq_err_count)(t1) + sw t0, (t1) #endif j ret_from_irq END(spurious_interrupt) diff --git a/trunk/drivers/net/Kconfig b/trunk/drivers/net/Kconfig index 6d4f9ceb0a32..fee8c5cf1f3a 100644 --- a/trunk/drivers/net/Kconfig +++ b/trunk/drivers/net/Kconfig @@ -1163,74 +1163,38 @@ config IBMVETH be called ibmveth. config IBM_EMAC - tristate "PowerPC 4xx on-chip Ethernet support" + bool "IBM PPC4xx EMAC driver support" depends on 4xx - help - This driver supports the PowerPC 4xx EMAC family of on-chip - Ethernet controllers. + select CRC32 + ---help--- + This driver supports the IBM PPC4xx EMAC family of on-chip + Ethernet controllers. + +config IBM_EMAC_ERRMSG + bool "Verbose error messages" + depends on IBM_EMAC && BROKEN config IBM_EMAC_RXB int "Number of receive buffers" depends on IBM_EMAC - default "128" + default "128" if IBM_EMAC4 + default "64" config IBM_EMAC_TXB int "Number of transmit buffers" depends on IBM_EMAC - default "64" - -config IBM_EMAC_POLL_WEIGHT - int "MAL NAPI polling weight" - depends on IBM_EMAC - default "32" + default "128" if IBM_EMAC4 + default "8" -config IBM_EMAC_RX_COPY_THRESHOLD - int "RX skb copy threshold (bytes)" +config IBM_EMAC_FGAP + int "Frame gap" depends on IBM_EMAC - default "256" + default "8" -config IBM_EMAC_RX_SKB_HEADROOM - int "Additional RX skb headroom (bytes)" +config IBM_EMAC_SKBRES + int "Skb reserve amount" depends on IBM_EMAC default "0" - help - Additional receive skb headroom. Note, that driver - will always reserve at least 2 bytes to make IP header - aligned, so usualy there is no need to add any additional - headroom. - - If unsure, set to 0. - -config IBM_EMAC_PHY_RX_CLK_FIX - bool "PHY Rx clock workaround" - depends on IBM_EMAC && (405EP || 440GX || 440EP) - help - Enable this if EMAC attached to a PHY which doesn't generate - RX clock if there is no link, if this is the case, you will - see "TX disable timeout" or "RX disable timeout" in the system - log. - - If unsure, say N. - -config IBM_EMAC_DEBUG - bool "Debugging" - depends on IBM_EMAC - default n - -config IBM_EMAC_ZMII - bool - depends on IBM_EMAC && (NP405H || NP405L || 44x) - default y - -config IBM_EMAC_RGMII - bool - depends on IBM_EMAC && 440GX - default y - -config IBM_EMAC_TAH - bool - depends on IBM_EMAC && 440GX - default y config NET_PCI bool "EISA, VLB, PCI and on board controllers" @@ -1811,7 +1775,6 @@ config NE_H8300 controller on the Renesas H8/300 processor. source "drivers/net/fec_8xx/Kconfig" -source "drivers/net/fs_enet/Kconfig" endmenu @@ -2238,8 +2201,8 @@ config S2IO depends on PCI ---help--- This driver supports the 10Gbe XFrame NIC of S2IO. - More specific information on configuring the driver is in - . + For help regarding driver compilation, installation and + tuning please look into ~/drivers/net/s2io/README.txt. config S2IO_NAPI bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" diff --git a/trunk/drivers/net/Makefile b/trunk/drivers/net/Makefile index 7c313cb341b8..1a84e0435f64 100644 --- a/trunk/drivers/net/Makefile +++ b/trunk/drivers/net/Makefile @@ -203,6 +203,3 @@ obj-$(CONFIG_IRDA) += irda/ obj-$(CONFIG_ETRAX_ETHERNET) += cris/ obj-$(CONFIG_NETCONSOLE) += netconsole.o - -obj-$(CONFIG_FS_ENET) += fs_enet/ - diff --git a/trunk/drivers/net/acenic.c b/trunk/drivers/net/acenic.c index b8953de5664a..dbecc6bf7851 100644 --- a/trunk/drivers/net/acenic.c +++ b/trunk/drivers/net/acenic.c @@ -871,8 +871,10 @@ static void ace_init_cleanup(struct net_device *dev) if (ap->info) pci_free_consistent(ap->pdev, sizeof(struct ace_info), ap->info, ap->info_dma); - kfree(ap->skb); - kfree(ap->trace_buf); + if (ap->skb) + kfree(ap->skb); + if (ap->trace_buf) + kfree(ap->trace_buf); if (dev->irq) free_irq(dev->irq, dev); diff --git a/trunk/drivers/net/amd8111e.c b/trunk/drivers/net/amd8111e.c old mode 100644 new mode 100755 diff --git a/trunk/drivers/net/amd8111e.h b/trunk/drivers/net/amd8111e.h old mode 100644 new mode 100755 diff --git a/trunk/drivers/net/au1000_eth.c b/trunk/drivers/net/au1000_eth.c index 332e9953c55c..78506911d656 100644 --- a/trunk/drivers/net/au1000_eth.c +++ b/trunk/drivers/net/au1000_eth.c @@ -1606,7 +1606,8 @@ au1000_probe(u32 ioaddr, int irq, int port_num) /* here we should have a valid dev plus aup-> register addresses * so we can reset the mac properly.*/ reset_mac(dev); - kfree(aup->mii); + if (aup->mii) + kfree(aup->mii); for (i = 0; i < NUM_RX_DMA; i++) { if (aup->rx_db_inuse[i]) ReleaseDB(aup, aup->rx_db_inuse[i]); @@ -1805,7 +1806,8 @@ static void __exit au1000_cleanup_module(void) if (dev) { aup = (struct au1000_private *) dev->priv; unregister_netdev(dev); - kfree(aup->mii); + if (aup->mii) + kfree(aup->mii); for (j = 0; j < NUM_RX_DMA; j++) { if (aup->rx_db_inuse[j]) ReleaseDB(aup, aup->rx_db_inuse[j]); diff --git a/trunk/drivers/net/b44.c b/trunk/drivers/net/b44.c index 0ee3e27969c6..282ebd15f011 100644 --- a/trunk/drivers/net/b44.c +++ b/trunk/drivers/net/b44.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -1131,10 +1130,14 @@ static void b44_init_rings(struct b44 *bp) */ static void b44_free_consistent(struct b44 *bp) { - kfree(bp->rx_buffers); - bp->rx_buffers = NULL; - kfree(bp->tx_buffers); - bp->tx_buffers = NULL; + if (bp->rx_buffers) { + kfree(bp->rx_buffers); + bp->rx_buffers = NULL; + } + if (bp->tx_buffers) { + kfree(bp->tx_buffers); + bp->tx_buffers = NULL; + } if (bp->rx_ring) { if (bp->flags & B44_FLAG_RX_RING_HACK) { dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma, @@ -1616,14 +1619,14 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising = 0; if (bp->flags & B44_FLAG_ADV_10HALF) - cmd->advertising |= ADVERTISED_10baseT_Half; + cmd->advertising |= ADVERTISE_10HALF; if (bp->flags & B44_FLAG_ADV_10FULL) - cmd->advertising |= ADVERTISED_10baseT_Full; + cmd->advertising |= ADVERTISE_10FULL; if (bp->flags & B44_FLAG_ADV_100HALF) - cmd->advertising |= ADVERTISED_100baseT_Half; + cmd->advertising |= ADVERTISE_100HALF; if (bp->flags & B44_FLAG_ADV_100FULL) - cmd->advertising |= ADVERTISED_100baseT_Full; - cmd->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; + cmd->advertising |= ADVERTISE_100FULL; + cmd->advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; cmd->speed = (bp->flags & B44_FLAG_100_BASE_T) ? SPEED_100 : SPEED_10; cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ? @@ -2041,8 +2044,6 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) b44_free_rings(bp); spin_unlock_irq(&bp->lock); - - free_irq(dev->irq, dev); pci_disable_device(pdev); return 0; } @@ -2059,9 +2060,6 @@ static int b44_resume(struct pci_dev *pdev) if (!netif_running(dev)) return 0; - if (request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev)) - printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name); - spin_lock_irq(&bp->lock); b44_init_rings(bp); diff --git a/trunk/drivers/net/bmac.c b/trunk/drivers/net/bmac.c index 73f2fcfc557f..60dba4a1ca5c 100644 --- a/trunk/drivers/net/bmac.c +++ b/trunk/drivers/net/bmac.c @@ -1689,8 +1689,10 @@ static void __exit bmac_exit(void) { macio_unregister_driver(&bmac_driver); - kfree(bmac_emergency_rxbuf); - bmac_emergency_rxbuf = NULL; + if (bmac_emergency_rxbuf != NULL) { + kfree(bmac_emergency_rxbuf); + bmac_emergency_rxbuf = NULL; + } } MODULE_AUTHOR("Randy Gobbel/Paul Mackerras"); diff --git a/trunk/drivers/net/bnx2.c b/trunk/drivers/net/bnx2.c index 11d252318221..3a2ace01e444 100644 --- a/trunk/drivers/net/bnx2.c +++ b/trunk/drivers/net/bnx2.c @@ -314,16 +314,20 @@ bnx2_free_mem(struct bnx2 *bp) bp->tx_desc_ring, bp->tx_desc_mapping); bp->tx_desc_ring = NULL; } - kfree(bp->tx_buf_ring); - bp->tx_buf_ring = NULL; + if (bp->tx_buf_ring) { + kfree(bp->tx_buf_ring); + bp->tx_buf_ring = NULL; + } if (bp->rx_desc_ring) { pci_free_consistent(bp->pdev, sizeof(struct rx_bd) * RX_DESC_CNT, bp->rx_desc_ring, bp->rx_desc_mapping); bp->rx_desc_ring = NULL; } - kfree(bp->rx_buf_ring); - bp->rx_buf_ring = NULL; + if (bp->rx_buf_ring) { + kfree(bp->rx_buf_ring); + bp->rx_buf_ring = NULL; + } } static int diff --git a/trunk/drivers/net/e1000/e1000_ethtool.c b/trunk/drivers/net/e1000/e1000_ethtool.c index 9c7feaeaa6a4..6b9acc7f94a3 100644 --- a/trunk/drivers/net/e1000/e1000_ethtool.c +++ b/trunk/drivers/net/e1000/e1000_ethtool.c @@ -965,8 +965,11 @@ e1000_free_desc_rings(struct e1000_adapter *adapter) if(rxdr->desc) pci_free_consistent(pdev, rxdr->size, rxdr->desc, rxdr->dma); - kfree(txdr->buffer_info); - kfree(rxdr->buffer_info); + if(txdr->buffer_info) + kfree(txdr->buffer_info); + if(rxdr->buffer_info) + kfree(rxdr->buffer_info); + return; } diff --git a/trunk/drivers/net/e1000/e1000_main.c b/trunk/drivers/net/e1000/e1000_main.c index efbbda7cbcbf..6b72f6acdd54 100644 --- a/trunk/drivers/net/e1000/e1000_main.c +++ b/trunk/drivers/net/e1000/e1000_main.c @@ -191,8 +191,8 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid); static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid); static void e1000_restore_vlan(struct e1000_adapter *adapter); -#ifdef CONFIG_PM static int e1000_suspend(struct pci_dev *pdev, pm_message_t state); +#ifdef CONFIG_PM static int e1000_resume(struct pci_dev *pdev); #endif @@ -1149,8 +1149,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter, int size; size = sizeof(struct e1000_buffer) * txdr->count; - - txdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus)); + txdr->buffer_info = vmalloc(size); if(!txdr->buffer_info) { DPRINTK(PROBE, ERR, "Unable to allocate memory for the transmit descriptor ring\n"); @@ -1367,7 +1366,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter, int size, desc_len; size = sizeof(struct e1000_buffer) * rxdr->count; - rxdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus)); + rxdr->buffer_info = vmalloc(size); if (!rxdr->buffer_info) { DPRINTK(PROBE, ERR, "Unable to allocate memory for the receive descriptor ring\n"); @@ -4194,7 +4193,6 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx) return 0; } -#ifdef CONFIG_PM static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) { @@ -4291,6 +4289,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } +#ifdef CONFIG_PM static int e1000_resume(struct pci_dev *pdev) { diff --git a/trunk/drivers/net/eepro.c b/trunk/drivers/net/eepro.c index 1ce2c675b8a7..dcb3028bb60f 100644 --- a/trunk/drivers/net/eepro.c +++ b/trunk/drivers/net/eepro.c @@ -1797,9 +1797,10 @@ MODULE_AUTHOR("Pascal Dupuis and others"); MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver"); MODULE_LICENSE("GPL"); -module_param_array(io, int, NULL, 0); -module_param_array(irq, int, NULL, 0); -module_param_array(mem, int, NULL, 0); +static int num_params; +module_param_array(io, int, &num_params, 0); +module_param_array(irq, int, &num_params, 0); +module_param_array(mem, int, &num_params, 0); module_param(autodetect, int, 0); MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base addres(es)"); MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)"); diff --git a/trunk/drivers/net/fs_enet/Kconfig b/trunk/drivers/net/fs_enet/Kconfig deleted file mode 100644 index 6aaee67dd4b7..000000000000 --- a/trunk/drivers/net/fs_enet/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config FS_ENET - tristate "Freescale Ethernet Driver" - depends on NET_ETHERNET && (CPM1 || CPM2) - select MII - -config FS_ENET_HAS_SCC - bool "Chip has an SCC usable for ethernet" - depends on FS_ENET && (CPM1 || CPM2) - default y - -config FS_ENET_HAS_FCC - bool "Chip has an FCC usable for ethernet" - depends on FS_ENET && CPM2 - default y - -config FS_ENET_HAS_FEC - bool "Chip has an FEC usable for ethernet" - depends on FS_ENET && CPM1 - default y - diff --git a/trunk/drivers/net/fs_enet/Makefile b/trunk/drivers/net/fs_enet/Makefile deleted file mode 100644 index d6dd3f2fb43e..000000000000 --- a/trunk/drivers/net/fs_enet/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for the Freescale Ethernet controllers -# - -obj-$(CONFIG_FS_ENET) += fs_enet.o - -obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o -obj-$(CONFIG_8260) += mac-fcc.o - -fs_enet-objs := fs_enet-main.o fs_enet-mii.o mii-bitbang.o mii-fixed.o diff --git a/trunk/drivers/net/fs_enet/fs_enet-main.c b/trunk/drivers/net/fs_enet/fs_enet-main.c deleted file mode 100644 index 44fac7373289..000000000000 --- a/trunk/drivers/net/fs_enet/fs_enet-main.c +++ /dev/null @@ -1,1226 +0,0 @@ -/* - * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * Heavily based on original FEC driver by Dan Malek - * and modifications by Joakim Tjernlund - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include "fs_enet.h" - -/*************************************************/ - -static char version[] __devinitdata = - DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n"; - -MODULE_AUTHOR("Pantelis Antoniou "); -MODULE_DESCRIPTION("Freescale Ethernet Driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_MODULE_VERSION); - -MODULE_PARM(fs_enet_debug, "i"); -MODULE_PARM_DESC(fs_enet_debug, - "Freescale bitmapped debugging message enable value"); - -int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ - -static void fs_set_multicast_list(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - (*fep->ops->set_multicast_list)(dev); -} - -/* NAPI receive function */ -static int fs_enet_rx_napi(struct net_device *dev, int *budget) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - cbd_t *bdp; - struct sk_buff *skb, *skbn, *skbt; - int received = 0; - u16 pkt_len, sc; - int curidx; - int rx_work_limit = 0; /* pacify gcc */ - - rx_work_limit = min(dev->quota, *budget); - - if (!netif_running(dev)) - return 0; - - /* - * First, grab all of the stats for the incoming packet. - * These get messed up if we get called due to a busy condition. - */ - bdp = fep->cur_rx; - - /* clear RX status bits for napi*/ - (*fep->ops->napi_clear_rx_event)(dev); - - while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { - - curidx = bdp - fep->rx_bd_base; - - /* - * Since we have allocated space to hold a complete frame, - * the last indicator should be set. - */ - if ((sc & BD_ENET_RX_LAST) == 0) - printk(KERN_WARNING DRV_MODULE_NAME - ": %s rcv is not +last\n", - dev->name); - - /* - * Check for errors. - */ - if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | - BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { - fep->stats.rx_errors++; - /* Frame too long or too short. */ - if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) - fep->stats.rx_length_errors++; - /* Frame alignment */ - if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) - fep->stats.rx_frame_errors++; - /* CRC Error */ - if (sc & BD_ENET_RX_CR) - fep->stats.rx_crc_errors++; - /* FIFO overrun */ - if (sc & BD_ENET_RX_OV) - fep->stats.rx_crc_errors++; - - skb = fep->rx_skbuff[curidx]; - - dma_unmap_single(fep->dev, skb->data, - L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), - DMA_FROM_DEVICE); - - skbn = skb; - - } else { - - /* napi, got packet but no quota */ - if (--rx_work_limit < 0) - break; - - skb = fep->rx_skbuff[curidx]; - - dma_unmap_single(fep->dev, skb->data, - L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), - DMA_FROM_DEVICE); - - /* - * Process the incoming frame. - */ - fep->stats.rx_packets++; - pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ - fep->stats.rx_bytes += pkt_len + 4; - - if (pkt_len <= fpi->rx_copybreak) { - /* +2 to make IP header L1 cache aligned */ - skbn = dev_alloc_skb(pkt_len + 2); - if (skbn != NULL) { - skb_reserve(skbn, 2); /* align IP header */ - memcpy(skbn->data, skb->data, pkt_len); - /* swap */ - skbt = skb; - skb = skbn; - skbn = skbt; - } - } else - skbn = dev_alloc_skb(ENET_RX_FRSIZE); - - if (skbn != NULL) { - skb->dev = dev; - skb_put(skb, pkt_len); /* Make room */ - skb->protocol = eth_type_trans(skb, dev); - received++; - netif_receive_skb(skb); - } else { - printk(KERN_WARNING DRV_MODULE_NAME - ": %s Memory squeeze, dropping packet.\n", - dev->name); - fep->stats.rx_dropped++; - skbn = skb; - } - } - - fep->rx_skbuff[curidx] = skbn; - CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, - L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), - DMA_FROM_DEVICE)); - CBDW_DATLEN(bdp, 0); - CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); - - /* - * Update BD pointer to next entry. - */ - if ((sc & BD_ENET_RX_WRAP) == 0) - bdp++; - else - bdp = fep->rx_bd_base; - - (*fep->ops->rx_bd_done)(dev); - } - - fep->cur_rx = bdp; - - dev->quota -= received; - *budget -= received; - - if (rx_work_limit < 0) - return 1; /* not done */ - - /* done */ - netif_rx_complete(dev); - - (*fep->ops->napi_enable_rx)(dev); - - return 0; -} - -/* non NAPI receive function */ -static int fs_enet_rx_non_napi(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - cbd_t *bdp; - struct sk_buff *skb, *skbn, *skbt; - int received = 0; - u16 pkt_len, sc; - int curidx; - /* - * First, grab all of the stats for the incoming packet. - * These get messed up if we get called due to a busy condition. - */ - bdp = fep->cur_rx; - - while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { - - curidx = bdp - fep->rx_bd_base; - - /* - * Since we have allocated space to hold a complete frame, - * the last indicator should be set. - */ - if ((sc & BD_ENET_RX_LAST) == 0) - printk(KERN_WARNING DRV_MODULE_NAME - ": %s rcv is not +last\n", - dev->name); - - /* - * Check for errors. - */ - if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | - BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { - fep->stats.rx_errors++; - /* Frame too long or too short. */ - if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) - fep->stats.rx_length_errors++; - /* Frame alignment */ - if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) - fep->stats.rx_frame_errors++; - /* CRC Error */ - if (sc & BD_ENET_RX_CR) - fep->stats.rx_crc_errors++; - /* FIFO overrun */ - if (sc & BD_ENET_RX_OV) - fep->stats.rx_crc_errors++; - - skb = fep->rx_skbuff[curidx]; - - dma_unmap_single(fep->dev, skb->data, - L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), - DMA_FROM_DEVICE); - - skbn = skb; - - } else { - - skb = fep->rx_skbuff[curidx]; - - dma_unmap_single(fep->dev, skb->data, - L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), - DMA_FROM_DEVICE); - - /* - * Process the incoming frame. - */ - fep->stats.rx_packets++; - pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ - fep->stats.rx_bytes += pkt_len + 4; - - if (pkt_len <= fpi->rx_copybreak) { - /* +2 to make IP header L1 cache aligned */ - skbn = dev_alloc_skb(pkt_len + 2); - if (skbn != NULL) { - skb_reserve(skbn, 2); /* align IP header */ - memcpy(skbn->data, skb->data, pkt_len); - /* swap */ - skbt = skb; - skb = skbn; - skbn = skbt; - } - } else - skbn = dev_alloc_skb(ENET_RX_FRSIZE); - - if (skbn != NULL) { - skb->dev = dev; - skb_put(skb, pkt_len); /* Make room */ - skb->protocol = eth_type_trans(skb, dev); - received++; - netif_rx(skb); - } else { - printk(KERN_WARNING DRV_MODULE_NAME - ": %s Memory squeeze, dropping packet.\n", - dev->name); - fep->stats.rx_dropped++; - skbn = skb; - } - } - - fep->rx_skbuff[curidx] = skbn; - CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, - L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), - DMA_FROM_DEVICE)); - CBDW_DATLEN(bdp, 0); - CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); - - /* - * Update BD pointer to next entry. - */ - if ((sc & BD_ENET_RX_WRAP) == 0) - bdp++; - else - bdp = fep->rx_bd_base; - - (*fep->ops->rx_bd_done)(dev); - } - - fep->cur_rx = bdp; - - return 0; -} - -static void fs_enet_tx(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - cbd_t *bdp; - struct sk_buff *skb; - int dirtyidx, do_wake, do_restart; - u16 sc; - - spin_lock(&fep->lock); - bdp = fep->dirty_tx; - - do_wake = do_restart = 0; - while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) { - - dirtyidx = bdp - fep->tx_bd_base; - - if (fep->tx_free == fep->tx_ring) - break; - - skb = fep->tx_skbuff[dirtyidx]; - - /* - * Check for errors. - */ - if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | - BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { - - if (sc & BD_ENET_TX_HB) /* No heartbeat */ - fep->stats.tx_heartbeat_errors++; - if (sc & BD_ENET_TX_LC) /* Late collision */ - fep->stats.tx_window_errors++; - if (sc & BD_ENET_TX_RL) /* Retrans limit */ - fep->stats.tx_aborted_errors++; - if (sc & BD_ENET_TX_UN) /* Underrun */ - fep->stats.tx_fifo_errors++; - if (sc & BD_ENET_TX_CSL) /* Carrier lost */ - fep->stats.tx_carrier_errors++; - - if (sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { - fep->stats.tx_errors++; - do_restart = 1; - } - } else - fep->stats.tx_packets++; - - if (sc & BD_ENET_TX_READY) - printk(KERN_WARNING DRV_MODULE_NAME - ": %s HEY! Enet xmit interrupt and TX_READY.\n", - dev->name); - - /* - * Deferred means some collisions occurred during transmit, - * but we eventually sent the packet OK. - */ - if (sc & BD_ENET_TX_DEF) - fep->stats.collisions++; - - /* unmap */ - dma_unmap_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE); - - /* - * Free the sk buffer associated with this last transmit. - */ - dev_kfree_skb_irq(skb); - fep->tx_skbuff[dirtyidx] = NULL; - - /* - * Update pointer to next buffer descriptor to be transmitted. - */ - if ((sc & BD_ENET_TX_WRAP) == 0) - bdp++; - else - bdp = fep->tx_bd_base; - - /* - * Since we have freed up a buffer, the ring is no longer - * full. - */ - if (!fep->tx_free++) - do_wake = 1; - } - - fep->dirty_tx = bdp; - - if (do_restart) - (*fep->ops->tx_restart)(dev); - - spin_unlock(&fep->lock); - - if (do_wake) - netif_wake_queue(dev); -} - -/* - * The interrupt handler. - * This is called from the MPC core interrupt. - */ -static irqreturn_t -fs_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = dev_id; - struct fs_enet_private *fep; - const struct fs_platform_info *fpi; - u32 int_events; - u32 int_clr_events; - int nr, napi_ok; - int handled; - - fep = netdev_priv(dev); - fpi = fep->fpi; - - nr = 0; - while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) { - - nr++; - - int_clr_events = int_events; - if (fpi->use_napi) - int_clr_events &= ~fep->ev_napi_rx; - - (*fep->ops->clear_int_events)(dev, int_clr_events); - - if (int_events & fep->ev_err) - (*fep->ops->ev_error)(dev, int_events); - - if (int_events & fep->ev_rx) { - if (!fpi->use_napi) - fs_enet_rx_non_napi(dev); - else { - napi_ok = netif_rx_schedule_prep(dev); - - (*fep->ops->napi_disable_rx)(dev); - (*fep->ops->clear_int_events)(dev, fep->ev_napi_rx); - - /* NOTE: it is possible for FCCs in NAPI mode */ - /* to submit a spurious interrupt while in poll */ - if (napi_ok) - __netif_rx_schedule(dev); - } - } - - if (int_events & fep->ev_tx) - fs_enet_tx(dev); - } - - handled = nr > 0; - return IRQ_RETVAL(handled); -} - -void fs_init_bds(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - cbd_t *bdp; - struct sk_buff *skb; - int i; - - fs_cleanup_bds(dev); - - fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; - fep->tx_free = fep->tx_ring; - fep->cur_rx = fep->rx_bd_base; - - /* - * Initialize the receive buffer descriptors. - */ - for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { - skb = dev_alloc_skb(ENET_RX_FRSIZE); - if (skb == NULL) { - printk(KERN_WARNING DRV_MODULE_NAME - ": %s Memory squeeze, unable to allocate skb\n", - dev->name); - break; - } - fep->rx_skbuff[i] = skb; - skb->dev = dev; - CBDW_BUFADDR(bdp, - dma_map_single(fep->dev, skb->data, - L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), - DMA_FROM_DEVICE)); - CBDW_DATLEN(bdp, 0); /* zero */ - CBDW_SC(bdp, BD_ENET_RX_EMPTY | - ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP)); - } - /* - * if we failed, fillup remainder - */ - for (; i < fep->rx_ring; i++, bdp++) { - fep->rx_skbuff[i] = NULL; - CBDW_SC(bdp, (i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP); - } - - /* - * ...and the same for transmit. - */ - for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { - fep->tx_skbuff[i] = NULL; - CBDW_BUFADDR(bdp, 0); - CBDW_DATLEN(bdp, 0); - CBDW_SC(bdp, (i < fep->tx_ring - 1) ? 0 : BD_SC_WRAP); - } -} - -void fs_cleanup_bds(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - struct sk_buff *skb; - int i; - - /* - * Reset SKB transmit buffers. - */ - for (i = 0; i < fep->tx_ring; i++) { - if ((skb = fep->tx_skbuff[i]) == NULL) - continue; - - /* unmap */ - dma_unmap_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE); - - fep->tx_skbuff[i] = NULL; - dev_kfree_skb(skb); - } - - /* - * Reset SKB receive buffers - */ - for (i = 0; i < fep->rx_ring; i++) { - if ((skb = fep->rx_skbuff[i]) == NULL) - continue; - - /* unmap */ - dma_unmap_single(fep->dev, skb->data, - L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), - DMA_FROM_DEVICE); - - fep->rx_skbuff[i] = NULL; - - dev_kfree_skb(skb); - } -} - -/**********************************************************************************/ - -static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - cbd_t *bdp; - int curidx; - u16 sc; - unsigned long flags; - - spin_lock_irqsave(&fep->tx_lock, flags); - - /* - * Fill in a Tx ring entry - */ - bdp = fep->cur_tx; - - if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { - netif_stop_queue(dev); - spin_unlock_irqrestore(&fep->tx_lock, flags); - - /* - * Ooops. All transmit buffers are full. Bail out. - * This should not happen, since the tx queue should be stopped. - */ - printk(KERN_WARNING DRV_MODULE_NAME - ": %s tx queue full!.\n", dev->name); - return NETDEV_TX_BUSY; - } - - curidx = bdp - fep->tx_bd_base; - /* - * Clear all of the status flags. - */ - CBDC_SC(bdp, BD_ENET_TX_STATS); - - /* - * Save skb pointer. - */ - fep->tx_skbuff[curidx] = skb; - - fep->stats.tx_bytes += skb->len; - - /* - * Push the data cache so the CPM does not get stale memory data. - */ - CBDW_BUFADDR(bdp, dma_map_single(fep->dev, - skb->data, skb->len, DMA_TO_DEVICE)); - CBDW_DATLEN(bdp, skb->len); - - dev->trans_start = jiffies; - - /* - * If this was the last BD in the ring, start at the beginning again. - */ - if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) - fep->cur_tx++; - else - fep->cur_tx = fep->tx_bd_base; - - if (!--fep->tx_free) - netif_stop_queue(dev); - - /* Trigger transmission start */ - sc = BD_ENET_TX_READY | BD_ENET_TX_INTR | - BD_ENET_TX_LAST | BD_ENET_TX_TC; - - /* note that while FEC does not have this bit - * it marks it as available for software use - * yay for hw reuse :) */ - if (skb->len <= 60) - sc |= BD_ENET_TX_PAD; - CBDS_SC(bdp, sc); - - (*fep->ops->tx_kickstart)(dev); - - spin_unlock_irqrestore(&fep->tx_lock, flags); - - return NETDEV_TX_OK; -} - -static int fs_request_irq(struct net_device *dev, int irq, const char *name, - irqreturn_t (*irqf)(int irq, void *dev_id, struct pt_regs *regs)) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - (*fep->ops->pre_request_irq)(dev, irq); - return request_irq(irq, irqf, SA_SHIRQ, name, dev); -} - -static void fs_free_irq(struct net_device *dev, int irq) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - free_irq(irq, dev); - (*fep->ops->post_free_irq)(dev, irq); -} - -/**********************************************************************************/ - -/* This interrupt occurs when the PHY detects a link change. */ -static irqreturn_t -fs_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = dev_id; - struct fs_enet_private *fep; - const struct fs_platform_info *fpi; - - fep = netdev_priv(dev); - fpi = fep->fpi; - - /* - * Acknowledge the interrupt if possible. If we have not - * found the PHY yet we can't process or acknowledge the - * interrupt now. Instead we ignore this interrupt for now, - * which we can do since it is edge triggered. It will be - * acknowledged later by fs_enet_open(). - */ - if (!fep->phy) - return IRQ_NONE; - - fs_mii_ack_int(dev); - fs_mii_link_status_change_check(dev, 0); - - return IRQ_HANDLED; -} - -static void fs_timeout(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - unsigned long flags; - int wake = 0; - - fep->stats.tx_errors++; - - spin_lock_irqsave(&fep->lock, flags); - - if (dev->flags & IFF_UP) { - (*fep->ops->stop)(dev); - (*fep->ops->restart)(dev); - } - - wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); - spin_unlock_irqrestore(&fep->lock, flags); - - if (wake) - netif_wake_queue(dev); -} - -static int fs_enet_open(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - int r; - - /* Install our interrupt handler. */ - r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); - if (r != 0) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s Could not allocate FEC IRQ!", dev->name); - return -EINVAL; - } - - /* Install our phy interrupt handler */ - if (fpi->phy_irq != -1) { - - r = fs_request_irq(dev, fpi->phy_irq, "fs_enet-phy", fs_mii_link_interrupt); - if (r != 0) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s Could not allocate PHY IRQ!", dev->name); - fs_free_irq(dev, fep->interrupt); - return -EINVAL; - } - } - - fs_mii_startup(dev); - netif_carrier_off(dev); - fs_mii_link_status_change_check(dev, 1); - - return 0; -} - -static int fs_enet_close(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - unsigned long flags; - - netif_stop_queue(dev); - netif_carrier_off(dev); - fs_mii_shutdown(dev); - - spin_lock_irqsave(&fep->lock, flags); - (*fep->ops->stop)(dev); - spin_unlock_irqrestore(&fep->lock, flags); - - /* release any irqs */ - if (fpi->phy_irq != -1) - fs_free_irq(dev, fpi->phy_irq); - fs_free_irq(dev, fep->interrupt); - - return 0; -} - -static struct net_device_stats *fs_enet_get_stats(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - return &fep->stats; -} - -/*************************************************************************/ - -static void fs_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strcpy(info->driver, DRV_MODULE_NAME); - strcpy(info->version, DRV_MODULE_VERSION); -} - -static int fs_get_regs_len(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - return (*fep->ops->get_regs_len)(dev); -} - -static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs, - void *p) -{ - struct fs_enet_private *fep = netdev_priv(dev); - unsigned long flags; - int r, len; - - len = regs->len; - - spin_lock_irqsave(&fep->lock, flags); - r = (*fep->ops->get_regs)(dev, p, &len); - spin_unlock_irqrestore(&fep->lock, flags); - - if (r == 0) - regs->version = 0; -} - -static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct fs_enet_private *fep = netdev_priv(dev); - unsigned long flags; - int rc; - - spin_lock_irqsave(&fep->lock, flags); - rc = mii_ethtool_gset(&fep->mii_if, cmd); - spin_unlock_irqrestore(&fep->lock, flags); - - return rc; -} - -static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct fs_enet_private *fep = netdev_priv(dev); - unsigned long flags; - int rc; - - spin_lock_irqsave(&fep->lock, flags); - rc = mii_ethtool_sset(&fep->mii_if, cmd); - spin_unlock_irqrestore(&fep->lock, flags); - - return rc; -} - -static int fs_nway_reset(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - return mii_nway_restart(&fep->mii_if); -} - -static u32 fs_get_msglevel(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - return fep->msg_enable; -} - -static void fs_set_msglevel(struct net_device *dev, u32 value) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fep->msg_enable = value; -} - -static struct ethtool_ops fs_ethtool_ops = { - .get_drvinfo = fs_get_drvinfo, - .get_regs_len = fs_get_regs_len, - .get_settings = fs_get_settings, - .set_settings = fs_set_settings, - .nway_reset = fs_nway_reset, - .get_link = ethtool_op_get_link, - .get_msglevel = fs_get_msglevel, - .set_msglevel = fs_set_msglevel, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_regs = fs_get_regs, -}; - -static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct fs_enet_private *fep = netdev_priv(dev); - struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data; - unsigned long flags; - int rc; - - if (!netif_running(dev)) - return -EINVAL; - - spin_lock_irqsave(&fep->lock, flags); - rc = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL); - spin_unlock_irqrestore(&fep->lock, flags); - return rc; -} - -extern int fs_mii_connect(struct net_device *dev); -extern void fs_mii_disconnect(struct net_device *dev); - -static struct net_device *fs_init_instance(struct device *dev, - const struct fs_platform_info *fpi) -{ - struct net_device *ndev = NULL; - struct fs_enet_private *fep = NULL; - int privsize, i, r, err = 0, registered = 0; - - /* guard */ - if ((unsigned int)fpi->fs_no >= FS_MAX_INDEX) - return ERR_PTR(-EINVAL); - - privsize = sizeof(*fep) + (sizeof(struct sk_buff **) * - (fpi->rx_ring + fpi->tx_ring)); - - ndev = alloc_etherdev(privsize); - if (!ndev) { - err = -ENOMEM; - goto err; - } - SET_MODULE_OWNER(ndev); - - fep = netdev_priv(ndev); - memset(fep, 0, privsize); /* clear everything */ - - fep->dev = dev; - dev_set_drvdata(dev, ndev); - fep->fpi = fpi; - if (fpi->init_ioports) - fpi->init_ioports(); - -#ifdef CONFIG_FS_ENET_HAS_FEC - if (fs_get_fec_index(fpi->fs_no) >= 0) - fep->ops = &fs_fec_ops; -#endif - -#ifdef CONFIG_FS_ENET_HAS_SCC - if (fs_get_scc_index(fpi->fs_no) >=0 ) - fep->ops = &fs_scc_ops; -#endif - -#ifdef CONFIG_FS_ENET_HAS_FCC - if (fs_get_fcc_index(fpi->fs_no) >= 0) - fep->ops = &fs_fcc_ops; -#endif - - if (fep->ops == NULL) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s No matching ops found (%d).\n", - ndev->name, fpi->fs_no); - err = -EINVAL; - goto err; - } - - r = (*fep->ops->setup_data)(ndev); - if (r != 0) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s setup_data failed\n", - ndev->name); - err = r; - goto err; - } - - /* point rx_skbuff, tx_skbuff */ - fep->rx_skbuff = (struct sk_buff **)&fep[1]; - fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; - - /* init locks */ - spin_lock_init(&fep->lock); - spin_lock_init(&fep->tx_lock); - - /* - * Set the Ethernet address. - */ - for (i = 0; i < 6; i++) - ndev->dev_addr[i] = fpi->macaddr[i]; - - r = (*fep->ops->allocate_bd)(ndev); - - if (fep->ring_base == NULL) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s buffer descriptor alloc failed (%d).\n", ndev->name, r); - err = r; - goto err; - } - - /* - * Set receive and transmit descriptor base. - */ - fep->rx_bd_base = fep->ring_base; - fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring; - - /* initialize ring size variables */ - fep->tx_ring = fpi->tx_ring; - fep->rx_ring = fpi->rx_ring; - - /* - * The FEC Ethernet specific entries in the device structure. - */ - ndev->open = fs_enet_open; - ndev->hard_start_xmit = fs_enet_start_xmit; - ndev->tx_timeout = fs_timeout; - ndev->watchdog_timeo = 2 * HZ; - ndev->stop = fs_enet_close; - ndev->get_stats = fs_enet_get_stats; - ndev->set_multicast_list = fs_set_multicast_list; - if (fpi->use_napi) { - ndev->poll = fs_enet_rx_napi; - ndev->weight = fpi->napi_weight; - } - ndev->ethtool_ops = &fs_ethtool_ops; - ndev->do_ioctl = fs_ioctl; - - init_timer(&fep->phy_timer_list); - - netif_carrier_off(ndev); - - err = register_netdev(ndev); - if (err != 0) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s register_netdev failed.\n", ndev->name); - goto err; - } - registered = 1; - - err = fs_mii_connect(ndev); - if (err != 0) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s fs_mii_connect failed.\n", ndev->name); - goto err; - } - - return ndev; - - err: - if (ndev != NULL) { - - if (registered) - unregister_netdev(ndev); - - if (fep != NULL) { - (*fep->ops->free_bd)(ndev); - (*fep->ops->cleanup_data)(ndev); - } - - free_netdev(ndev); - } - - dev_set_drvdata(dev, NULL); - - return ERR_PTR(err); -} - -static int fs_cleanup_instance(struct net_device *ndev) -{ - struct fs_enet_private *fep; - const struct fs_platform_info *fpi; - struct device *dev; - - if (ndev == NULL) - return -EINVAL; - - fep = netdev_priv(ndev); - if (fep == NULL) - return -EINVAL; - - fpi = fep->fpi; - - fs_mii_disconnect(ndev); - - unregister_netdev(ndev); - - dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), - fep->ring_base, fep->ring_mem_addr); - - /* reset it */ - (*fep->ops->cleanup_data)(ndev); - - dev = fep->dev; - if (dev != NULL) { - dev_set_drvdata(dev, NULL); - fep->dev = NULL; - } - - free_netdev(ndev); - - return 0; -} - -/**************************************************************************************/ - -/* handy pointer to the immap */ -void *fs_enet_immap = NULL; - -static int setup_immap(void) -{ - phys_addr_t paddr = 0; - unsigned long size = 0; - -#ifdef CONFIG_CPM1 - paddr = IMAP_ADDR; - size = 0x10000; /* map 64K */ -#endif - -#ifdef CONFIG_CPM2 - paddr = CPM_MAP_ADDR; - size = 0x40000; /* map 256 K */ -#endif - fs_enet_immap = ioremap(paddr, size); - if (fs_enet_immap == NULL) - return -EBADF; /* XXX ahem; maybe just BUG_ON? */ - - return 0; -} - -static void cleanup_immap(void) -{ - if (fs_enet_immap != NULL) { - iounmap(fs_enet_immap); - fs_enet_immap = NULL; - } -} - -/**************************************************************************************/ - -static int __devinit fs_enet_probe(struct device *dev) -{ - struct net_device *ndev; - - /* no fixup - no device */ - if (dev->platform_data == NULL) { - printk(KERN_INFO "fs_enet: " - "probe called with no platform data; " - "remove unused devices\n"); - return -ENODEV; - } - - ndev = fs_init_instance(dev, dev->platform_data); - if (IS_ERR(ndev)) - return PTR_ERR(ndev); - return 0; -} - -static int fs_enet_remove(struct device *dev) -{ - return fs_cleanup_instance(dev_get_drvdata(dev)); -} - -static struct device_driver fs_enet_fec_driver = { - .name = "fsl-cpm-fec", - .bus = &platform_bus_type, - .probe = fs_enet_probe, - .remove = fs_enet_remove, -#ifdef CONFIG_PM -/* .suspend = fs_enet_suspend, TODO */ -/* .resume = fs_enet_resume, TODO */ -#endif -}; - -static struct device_driver fs_enet_scc_driver = { - .name = "fsl-cpm-scc", - .bus = &platform_bus_type, - .probe = fs_enet_probe, - .remove = fs_enet_remove, -#ifdef CONFIG_PM -/* .suspend = fs_enet_suspend, TODO */ -/* .resume = fs_enet_resume, TODO */ -#endif -}; - -static struct device_driver fs_enet_fcc_driver = { - .name = "fsl-cpm-fcc", - .bus = &platform_bus_type, - .probe = fs_enet_probe, - .remove = fs_enet_remove, -#ifdef CONFIG_PM -/* .suspend = fs_enet_suspend, TODO */ -/* .resume = fs_enet_resume, TODO */ -#endif -}; - -static int __init fs_init(void) -{ - int r; - - printk(KERN_INFO - "%s", version); - - r = setup_immap(); - if (r != 0) - return r; - r = driver_register(&fs_enet_fec_driver); - if (r != 0) - goto err; - - r = driver_register(&fs_enet_fcc_driver); - if (r != 0) - goto err; - - r = driver_register(&fs_enet_scc_driver); - if (r != 0) - goto err; - - return 0; -err: - cleanup_immap(); - return r; - -} - -static void __exit fs_cleanup(void) -{ - driver_unregister(&fs_enet_fec_driver); - driver_unregister(&fs_enet_fcc_driver); - driver_unregister(&fs_enet_scc_driver); - cleanup_immap(); -} - -/**************************************************************************************/ - -module_init(fs_init); -module_exit(fs_cleanup); diff --git a/trunk/drivers/net/fs_enet/fs_enet-mii.c b/trunk/drivers/net/fs_enet/fs_enet-mii.c deleted file mode 100644 index c6770377ef87..000000000000 --- a/trunk/drivers/net/fs_enet/fs_enet-mii.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * Heavily based on original FEC driver by Dan Malek - * and modifications by Joakim Tjernlund - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "fs_enet.h" - -/*************************************************/ - -/* - * Generic PHY support. - * Should work for all PHYs, but link change is detected by polling - */ - -static void generic_timer_callback(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct fs_enet_private *fep = netdev_priv(dev); - - fep->phy_timer_list.expires = jiffies + HZ / 2; - - add_timer(&fep->phy_timer_list); - - fs_mii_link_status_change_check(dev, 0); -} - -static void generic_startup(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - fep->phy_timer_list.expires = jiffies + HZ / 2; /* every 500ms */ - fep->phy_timer_list.data = (unsigned long)dev; - fep->phy_timer_list.function = generic_timer_callback; - add_timer(&fep->phy_timer_list); -} - -static void generic_shutdown(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - del_timer_sync(&fep->phy_timer_list); -} - -/* ------------------------------------------------------------------------- */ -/* The Davicom DM9161 is used on the NETTA board */ - -/* register definitions */ - -#define MII_DM9161_ANAR 4 /* Aux. Config Register */ -#define MII_DM9161_ACR 16 /* Aux. Config Register */ -#define MII_DM9161_ACSR 17 /* Aux. Config/Status Register */ -#define MII_DM9161_10TCSR 18 /* 10BaseT Config/Status Reg. */ -#define MII_DM9161_INTR 21 /* Interrupt Register */ -#define MII_DM9161_RECR 22 /* Receive Error Counter Reg. */ -#define MII_DM9161_DISCR 23 /* Disconnect Counter Register */ - -static void dm9161_startup(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000); - /* Start autonegotiation */ - fs_mii_write(dev, fep->mii_if.phy_id, MII_BMCR, 0x1200); - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ*8); -} - -static void dm9161_ack_int(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - fs_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR); -} - -static void dm9161_shutdown(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00); -} - -/**********************************************************************************/ - -static const struct phy_info phy_info[] = { - { - .id = 0x00181b88, - .name = "DM9161", - .startup = dm9161_startup, - .ack_int = dm9161_ack_int, - .shutdown = dm9161_shutdown, - }, { - .id = 0, - .name = "GENERIC", - .startup = generic_startup, - .shutdown = generic_shutdown, - }, -}; - -/**********************************************************************************/ - -static int phy_id_detect(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - struct fs_enet_mii_bus *bus = fep->mii_bus; - int i, r, start, end, phytype, physubtype; - const struct phy_info *phy; - int phy_hwid, phy_id; - - phy_hwid = -1; - fep->phy = NULL; - - /* auto-detect? */ - if (fpi->phy_addr == -1) { - start = 1; - end = 32; - } else { /* direct */ - start = fpi->phy_addr; - end = start + 1; - } - - for (phy_id = start; phy_id < end; phy_id++) { - /* skip already used phy addresses on this bus */ - if (bus->usage_map & (1 << phy_id)) - continue; - r = fs_mii_read(dev, phy_id, MII_PHYSID1); - if (r == -1 || (phytype = (r & 0xffff)) == 0xffff) - continue; - r = fs_mii_read(dev, phy_id, MII_PHYSID2); - if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff) - continue; - phy_hwid = (phytype << 16) | physubtype; - if (phy_hwid != -1) - break; - } - - if (phy_hwid == -1) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s No PHY detected! range=0x%02x-0x%02x\n", - dev->name, start, end); - return -1; - } - - for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++) - if (phy->id == (phy_hwid >> 4) || phy->id == 0) - break; - - if (i >= ARRAY_SIZE(phy_info)) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s PHY id 0x%08x is not supported!\n", - dev->name, phy_hwid); - return -1; - } - - fep->phy = phy; - - /* mark this address as used */ - bus->usage_map |= (1 << phy_id); - - printk(KERN_INFO DRV_MODULE_NAME - ": %s Phy @ 0x%x, type %s (0x%08x)%s\n", - dev->name, phy_id, fep->phy->name, phy_hwid, - fpi->phy_addr == -1 ? " (auto-detected)" : ""); - - return phy_id; -} - -void fs_mii_startup(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - if (fep->phy->startup) - (*fep->phy->startup) (dev); -} - -void fs_mii_shutdown(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - if (fep->phy->shutdown) - (*fep->phy->shutdown) (dev); -} - -void fs_mii_ack_int(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - if (fep->phy->ack_int) - (*fep->phy->ack_int) (dev); -} - -#define MII_LINK 0x0001 -#define MII_HALF 0x0002 -#define MII_FULL 0x0004 -#define MII_BASE4 0x0008 -#define MII_10M 0x0010 -#define MII_100M 0x0020 -#define MII_1G 0x0040 -#define MII_10G 0x0080 - -/* return full mii info at one gulp, with a usable form */ -static unsigned int mii_full_status(struct mii_if_info *mii) -{ - unsigned int status; - int bmsr, adv, lpa, neg; - struct fs_enet_private* fep = netdev_priv(mii->dev); - - /* first, a dummy read, needed to latch some MII phys */ - (void)mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); - bmsr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); - - /* no link */ - if ((bmsr & BMSR_LSTATUS) == 0) - return 0; - - status = MII_LINK; - - /* Lets look what ANEG says if it's supported - otherwize we shall - take the right values from the platform info*/ - if(!mii->force_media) { - /* autoneg not completed; don't bother */ - if ((bmsr & BMSR_ANEGCOMPLETE) == 0) - return 0; - - adv = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_ADVERTISE); - lpa = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_LPA); - - neg = lpa & adv; - } else { - neg = fep->fpi->bus_info->lpa; - } - - if (neg & LPA_100FULL) - status |= MII_FULL | MII_100M; - else if (neg & LPA_100BASE4) - status |= MII_FULL | MII_BASE4 | MII_100M; - else if (neg & LPA_100HALF) - status |= MII_HALF | MII_100M; - else if (neg & LPA_10FULL) - status |= MII_FULL | MII_10M; - else - status |= MII_HALF | MII_10M; - - return status; -} - -void fs_mii_link_status_change_check(struct net_device *dev, int init_media) -{ - struct fs_enet_private *fep = netdev_priv(dev); - struct mii_if_info *mii = &fep->mii_if; - unsigned int mii_status; - int ok_to_print, link, duplex, speed; - unsigned long flags; - - ok_to_print = netif_msg_link(fep); - - mii_status = mii_full_status(mii); - - if (!init_media && mii_status == fep->last_mii_status) - return; - - fep->last_mii_status = mii_status; - - link = !!(mii_status & MII_LINK); - duplex = !!(mii_status & MII_FULL); - speed = (mii_status & MII_100M) ? 100 : 10; - - if (link == 0) { - netif_carrier_off(mii->dev); - netif_stop_queue(dev); - if (!init_media) { - spin_lock_irqsave(&fep->lock, flags); - (*fep->ops->stop)(dev); - spin_unlock_irqrestore(&fep->lock, flags); - } - - if (ok_to_print) - printk(KERN_INFO "%s: link down\n", mii->dev->name); - - } else { - - mii->full_duplex = duplex; - - netif_carrier_on(mii->dev); - - spin_lock_irqsave(&fep->lock, flags); - fep->duplex = duplex; - fep->speed = speed; - (*fep->ops->restart)(dev); - spin_unlock_irqrestore(&fep->lock, flags); - - netif_start_queue(dev); - - if (ok_to_print) - printk(KERN_INFO "%s: link up, %dMbps, %s-duplex\n", - dev->name, speed, duplex ? "full" : "half"); - } -} - -/**********************************************************************************/ - -int fs_mii_read(struct net_device *dev, int phy_id, int location) -{ - struct fs_enet_private *fep = netdev_priv(dev); - struct fs_enet_mii_bus *bus = fep->mii_bus; - - unsigned long flags; - int ret; - - spin_lock_irqsave(&bus->mii_lock, flags); - ret = (*bus->mii_read)(bus, phy_id, location); - spin_unlock_irqrestore(&bus->mii_lock, flags); - - return ret; -} - -void fs_mii_write(struct net_device *dev, int phy_id, int location, int value) -{ - struct fs_enet_private *fep = netdev_priv(dev); - struct fs_enet_mii_bus *bus = fep->mii_bus; - unsigned long flags; - - spin_lock_irqsave(&bus->mii_lock, flags); - (*bus->mii_write)(bus, phy_id, location, value); - spin_unlock_irqrestore(&bus->mii_lock, flags); -} - -/*****************************************************************************/ - -/* list of all registered mii buses */ -static LIST_HEAD(fs_mii_bus_list); - -static struct fs_enet_mii_bus *lookup_bus(int method, int id) -{ - struct list_head *ptr; - struct fs_enet_mii_bus *bus; - - list_for_each(ptr, &fs_mii_bus_list) { - bus = list_entry(ptr, struct fs_enet_mii_bus, list); - if (bus->bus_info->method == method && - bus->bus_info->id == id) - return bus; - } - return NULL; -} - -static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi) -{ - struct fs_enet_mii_bus *bus; - int ret = 0; - - bus = kmalloc(sizeof(*bus), GFP_KERNEL); - if (bus == NULL) { - ret = -ENOMEM; - goto err; - } - memset(bus, 0, sizeof(*bus)); - spin_lock_init(&bus->mii_lock); - bus->bus_info = bi; - bus->refs = 0; - bus->usage_map = 0; - - /* perform initialization */ - switch (bi->method) { - - case fsmii_fixed: - ret = fs_mii_fixed_init(bus); - if (ret != 0) - goto err; - break; - - case fsmii_bitbang: - ret = fs_mii_bitbang_init(bus); - if (ret != 0) - goto err; - break; -#ifdef CONFIG_FS_ENET_HAS_FEC - case fsmii_fec: - ret = fs_mii_fec_init(bus); - if (ret != 0) - goto err; - break; -#endif - default: - ret = -EINVAL; - goto err; - } - - list_add(&bus->list, &fs_mii_bus_list); - - return bus; - -err: - if (bus) - kfree(bus); - return ERR_PTR(ret); -} - -static void destroy_bus(struct fs_enet_mii_bus *bus) -{ - /* remove from bus list */ - list_del(&bus->list); - - /* nothing more needed */ - kfree(bus); -} - -int fs_mii_connect(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - struct fs_enet_mii_bus *bus = NULL; - - /* check method validity */ - switch (fpi->bus_info->method) { - case fsmii_fixed: - case fsmii_bitbang: - break; -#ifdef CONFIG_FS_ENET_HAS_FEC - case fsmii_fec: - break; -#endif - default: - printk(KERN_ERR DRV_MODULE_NAME - ": %s Unknown MII bus method (%d)!\n", - dev->name, fpi->bus_info->method); - return -EINVAL; - } - - bus = lookup_bus(fpi->bus_info->method, fpi->bus_info->id); - - /* if not found create new bus */ - if (bus == NULL) { - bus = create_bus(fpi->bus_info); - if (IS_ERR(bus)) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s MII bus creation failure!\n", dev->name); - return PTR_ERR(bus); - } - } - - bus->refs++; - - fep->mii_bus = bus; - - fep->mii_if.dev = dev; - fep->mii_if.phy_id_mask = 0x1f; - fep->mii_if.reg_num_mask = 0x1f; - fep->mii_if.mdio_read = fs_mii_read; - fep->mii_if.mdio_write = fs_mii_write; - fep->mii_if.force_media = fpi->bus_info->disable_aneg; - fep->mii_if.phy_id = phy_id_detect(dev); - - return 0; -} - -void fs_mii_disconnect(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - struct fs_enet_mii_bus *bus = NULL; - - bus = fep->mii_bus; - fep->mii_bus = NULL; - - if (--bus->refs <= 0) - destroy_bus(bus); -} diff --git a/trunk/drivers/net/fs_enet/fs_enet.h b/trunk/drivers/net/fs_enet/fs_enet.h deleted file mode 100644 index 1105543b9d88..000000000000 --- a/trunk/drivers/net/fs_enet/fs_enet.h +++ /dev/null @@ -1,245 +0,0 @@ -#ifndef FS_ENET_H -#define FS_ENET_H - -#include -#include -#include -#include -#include - -#include - -#include - -#ifdef CONFIG_CPM1 -#include -#endif - -#ifdef CONFIG_CPM2 -#include -#endif - -/* hw driver ops */ -struct fs_ops { - int (*setup_data)(struct net_device *dev); - int (*allocate_bd)(struct net_device *dev); - void (*free_bd)(struct net_device *dev); - void (*cleanup_data)(struct net_device *dev); - void (*set_multicast_list)(struct net_device *dev); - void (*restart)(struct net_device *dev); - void (*stop)(struct net_device *dev); - void (*pre_request_irq)(struct net_device *dev, int irq); - void (*post_free_irq)(struct net_device *dev, int irq); - void (*napi_clear_rx_event)(struct net_device *dev); - void (*napi_enable_rx)(struct net_device *dev); - void (*napi_disable_rx)(struct net_device *dev); - void (*rx_bd_done)(struct net_device *dev); - void (*tx_kickstart)(struct net_device *dev); - u32 (*get_int_events)(struct net_device *dev); - void (*clear_int_events)(struct net_device *dev, u32 int_events); - void (*ev_error)(struct net_device *dev, u32 int_events); - int (*get_regs)(struct net_device *dev, void *p, int *sizep); - int (*get_regs_len)(struct net_device *dev); - void (*tx_restart)(struct net_device *dev); -}; - -struct phy_info { - unsigned int id; - const char *name; - void (*startup) (struct net_device * dev); - void (*shutdown) (struct net_device * dev); - void (*ack_int) (struct net_device * dev); -}; - -/* The FEC stores dest/src/type, data, and checksum for receive packets. - */ -#define MAX_MTU 1508 /* Allow fullsized pppoe packets over VLAN */ -#define MIN_MTU 46 /* this is data size */ -#define CRC_LEN 4 - -#define PKT_MAXBUF_SIZE (MAX_MTU+ETH_HLEN+CRC_LEN) -#define PKT_MINBUF_SIZE (MIN_MTU+ETH_HLEN+CRC_LEN) - -/* Must be a multiple of 32 (to cover both FEC & FCC) */ -#define PKT_MAXBLR_SIZE ((PKT_MAXBUF_SIZE + 31) & ~31) -/* This is needed so that invalidate_xxx wont invalidate too much */ -#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE) - -struct fs_enet_mii_bus { - struct list_head list; - spinlock_t mii_lock; - const struct fs_mii_bus_info *bus_info; - int refs; - u32 usage_map; - - int (*mii_read)(struct fs_enet_mii_bus *bus, - int phy_id, int location); - - void (*mii_write)(struct fs_enet_mii_bus *bus, - int phy_id, int location, int value); - - union { - struct { - unsigned int mii_speed; - void *fecp; - } fec; - - struct { - /* note that the actual port size may */ - /* be different; cpm(s) handle it OK */ - u8 mdio_msk; - u8 *mdio_dir; - u8 *mdio_dat; - u8 mdc_msk; - u8 *mdc_dir; - u8 *mdc_dat; - } bitbang; - - struct { - u16 lpa; - } fixed; - }; -}; - -int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus); -int fs_mii_fixed_init(struct fs_enet_mii_bus *bus); -int fs_mii_fec_init(struct fs_enet_mii_bus *bus); - -struct fs_enet_private { - struct device *dev; /* pointer back to the device (must be initialized first) */ - spinlock_t lock; /* during all ops except TX pckt processing */ - spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */ - const struct fs_platform_info *fpi; - const struct fs_ops *ops; - int rx_ring, tx_ring; - dma_addr_t ring_mem_addr; - void *ring_base; - struct sk_buff **rx_skbuff; - struct sk_buff **tx_skbuff; - cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ - cbd_t *tx_bd_base; - cbd_t *dirty_tx; /* ring entries to be free()ed. */ - cbd_t *cur_rx; - cbd_t *cur_tx; - int tx_free; - struct net_device_stats stats; - struct timer_list phy_timer_list; - const struct phy_info *phy; - u32 msg_enable; - struct mii_if_info mii_if; - unsigned int last_mii_status; - struct fs_enet_mii_bus *mii_bus; - int interrupt; - - int duplex, speed; /* current settings */ - - /* event masks */ - u32 ev_napi_rx; /* mask of NAPI rx events */ - u32 ev_rx; /* rx event mask */ - u32 ev_tx; /* tx event mask */ - u32 ev_err; /* error event mask */ - - u16 bd_rx_empty; /* mask of BD rx empty */ - u16 bd_rx_err; /* mask of BD rx errors */ - - union { - struct { - int idx; /* FEC1 = 0, FEC2 = 1 */ - void *fecp; /* hw registers */ - u32 hthi, htlo; /* state for multicast */ - } fec; - - struct { - int idx; /* FCC1-3 = 0-2 */ - void *fccp; /* hw registers */ - void *ep; /* parameter ram */ - void *fcccp; /* hw registers cont. */ - void *mem; /* FCC DPRAM */ - u32 gaddrh, gaddrl; /* group address */ - } fcc; - - struct { - int idx; /* FEC1 = 0, FEC2 = 1 */ - void *sccp; /* hw registers */ - void *ep; /* parameter ram */ - u32 hthi, htlo; /* state for multicast */ - } scc; - - }; -}; - -/***************************************************************************/ - -int fs_mii_read(struct net_device *dev, int phy_id, int location); -void fs_mii_write(struct net_device *dev, int phy_id, int location, int value); - -void fs_mii_startup(struct net_device *dev); -void fs_mii_shutdown(struct net_device *dev); -void fs_mii_ack_int(struct net_device *dev); - -void fs_mii_link_status_change_check(struct net_device *dev, int init_media); - -void fs_init_bds(struct net_device *dev); -void fs_cleanup_bds(struct net_device *dev); - -/***************************************************************************/ - -#define DRV_MODULE_NAME "fs_enet" -#define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.0" -#define DRV_MODULE_RELDATE "Aug 8, 2005" - -/***************************************************************************/ - -int fs_enet_platform_init(void); -void fs_enet_platform_cleanup(void); - -/***************************************************************************/ - -/* buffer descriptor access macros */ - -/* access macros */ -#if defined(CONFIG_CPM1) -/* for a a CPM1 __raw_xxx's are sufficient */ -#define __cbd_out32(addr, x) __raw_writel(x, addr) -#define __cbd_out16(addr, x) __raw_writew(x, addr) -#define __cbd_in32(addr) __raw_readl(addr) -#define __cbd_in16(addr) __raw_readw(addr) -#else -/* for others play it safe */ -#define __cbd_out32(addr, x) out_be32(addr, x) -#define __cbd_out16(addr, x) out_be16(addr, x) -#define __cbd_in32(addr) in_be32(addr) -#define __cbd_in16(addr) in_be16(addr) -#endif - -/* write */ -#define CBDW_SC(_cbd, _sc) __cbd_out16(&(_cbd)->cbd_sc, (_sc)) -#define CBDW_DATLEN(_cbd, _datlen) __cbd_out16(&(_cbd)->cbd_datlen, (_datlen)) -#define CBDW_BUFADDR(_cbd, _bufaddr) __cbd_out32(&(_cbd)->cbd_bufaddr, (_bufaddr)) - -/* read */ -#define CBDR_SC(_cbd) __cbd_in16(&(_cbd)->cbd_sc) -#define CBDR_DATLEN(_cbd) __cbd_in16(&(_cbd)->cbd_datlen) -#define CBDR_BUFADDR(_cbd) __cbd_in32(&(_cbd)->cbd_bufaddr) - -/* set bits */ -#define CBDS_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) | (_sc)) - -/* clear bits */ -#define CBDC_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) & ~(_sc)) - -/*******************************************************************/ - -extern const struct fs_ops fs_fec_ops; -extern const struct fs_ops fs_fcc_ops; -extern const struct fs_ops fs_scc_ops; - -/*******************************************************************/ - -/* handy pointer to the immap */ -extern void *fs_enet_immap; - -/*******************************************************************/ - -#endif diff --git a/trunk/drivers/net/fs_enet/mac-fcc.c b/trunk/drivers/net/fs_enet/mac-fcc.c deleted file mode 100644 index a940b96433c7..000000000000 --- a/trunk/drivers/net/fs_enet/mac-fcc.c +++ /dev/null @@ -1,578 +0,0 @@ -/* - * FCC driver for Motorola MPC82xx (PQ2). - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "fs_enet.h" - -/*************************************************/ - -/* FCC access macros */ - -#define __fcc_out32(addr, x) out_be32((unsigned *)addr, x) -#define __fcc_out16(addr, x) out_be16((unsigned short *)addr, x) -#define __fcc_out8(addr, x) out_8((unsigned char *)addr, x) -#define __fcc_in32(addr) in_be32((unsigned *)addr) -#define __fcc_in16(addr) in_be16((unsigned short *)addr) -#define __fcc_in8(addr) in_8((unsigned char *)addr) - -/* parameter space */ - -/* write, read, set bits, clear bits */ -#define W32(_p, _m, _v) __fcc_out32(&(_p)->_m, (_v)) -#define R32(_p, _m) __fcc_in32(&(_p)->_m) -#define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) -#define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) - -#define W16(_p, _m, _v) __fcc_out16(&(_p)->_m, (_v)) -#define R16(_p, _m) __fcc_in16(&(_p)->_m) -#define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) -#define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) - -#define W8(_p, _m, _v) __fcc_out8(&(_p)->_m, (_v)) -#define R8(_p, _m) __fcc_in8(&(_p)->_m) -#define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) -#define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) - -/*************************************************/ - -#define FCC_MAX_MULTICAST_ADDRS 64 - -#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) -#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) -#define mk_mii_end 0 - -#define MAX_CR_CMD_LOOPS 10000 - -static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op) -{ - const struct fs_platform_info *fpi = fep->fpi; - - cpm2_map_t *immap = fs_enet_immap; - cpm_cpm2_t *cpmp = &immap->im_cpm; - u32 v; - int i; - - /* Currently I don't know what feature call will look like. But - I guess there'd be something like do_cpm_cmd() which will require page & sblock */ - v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op); - W32(cpmp, cp_cpcr, v | CPM_CR_FLG); - for (i = 0; i < MAX_CR_CMD_LOOPS; i++) - if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0) - break; - - if (i >= MAX_CR_CMD_LOOPS) { - printk(KERN_ERR "%s(): Not able to issue CPM command\n", - __FUNCTION__); - return 1; - } - - return 0; -} - -static int do_pd_setup(struct fs_enet_private *fep) -{ - struct platform_device *pdev = to_platform_device(fep->dev); - struct resource *r; - - /* Fill out IRQ field */ - fep->interrupt = platform_get_irq(pdev, 0); - - /* Attach the memory for the FCC Parameter RAM */ - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram"); - fep->fcc.ep = (void *)r->start; - - if (fep->fcc.ep == NULL) - return -EINVAL; - - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs"); - fep->fcc.fccp = (void *)r->start; - - if (fep->fcc.fccp == NULL) - return -EINVAL; - - fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c; - - if (fep->fcc.fcccp == NULL) - return -EINVAL; - - return 0; -} - -#define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB) -#define FCC_RX_EVENT (FCC_ENET_RXF) -#define FCC_TX_EVENT (FCC_ENET_TXB) -#define FCC_ERR_EVENT_MSK (FCC_ENET_TXE | FCC_ENET_BSY) - -static int setup_data(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - - fep->fcc.idx = fs_get_fcc_index(fpi->fs_no); - if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */ - return -EINVAL; - - fep->fcc.mem = (void *)fpi->mem_offset; - - if (do_pd_setup(fep) != 0) - return -EINVAL; - - fep->ev_napi_rx = FCC_NAPI_RX_EVENT_MSK; - fep->ev_rx = FCC_RX_EVENT; - fep->ev_tx = FCC_TX_EVENT; - fep->ev_err = FCC_ERR_EVENT_MSK; - - return 0; -} - -static int allocate_bd(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - - fep->ring_base = dma_alloc_coherent(fep->dev, - (fpi->tx_ring + fpi->rx_ring) * - sizeof(cbd_t), &fep->ring_mem_addr, - GFP_KERNEL); - if (fep->ring_base == NULL) - return -ENOMEM; - - return 0; -} - -static void free_bd(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - - if (fep->ring_base) - dma_free_coherent(fep->dev, - (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), - fep->ring_base, fep->ring_mem_addr); -} - -static void cleanup_data(struct net_device *dev) -{ - /* nothing */ -} - -static void set_promiscuous_mode(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; - - S32(fccp, fcc_fpsmr, FCC_PSMR_PRO); -} - -static void set_multicast_start(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fcc_enet_t *ep = fep->fcc.ep; - - W32(ep, fen_gaddrh, 0); - W32(ep, fen_gaddrl, 0); -} - -static void set_multicast_one(struct net_device *dev, const u8 *mac) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fcc_enet_t *ep = fep->fcc.ep; - u16 taddrh, taddrm, taddrl; - - taddrh = ((u16)mac[5] << 8) | mac[4]; - taddrm = ((u16)mac[3] << 8) | mac[2]; - taddrl = ((u16)mac[1] << 8) | mac[0]; - - W16(ep, fen_taddrh, taddrh); - W16(ep, fen_taddrm, taddrm); - W16(ep, fen_taddrl, taddrl); - fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR); -} - -static void set_multicast_finish(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; - fcc_enet_t *ep = fep->fcc.ep; - - /* clear promiscuous always */ - C32(fccp, fcc_fpsmr, FCC_PSMR_PRO); - - /* if all multi or too many multicasts; just enable all */ - if ((dev->flags & IFF_ALLMULTI) != 0 || - dev->mc_count > FCC_MAX_MULTICAST_ADDRS) { - - W32(ep, fen_gaddrh, 0xffffffff); - W32(ep, fen_gaddrl, 0xffffffff); - } - - /* read back */ - fep->fcc.gaddrh = R32(ep, fen_gaddrh); - fep->fcc.gaddrl = R32(ep, fen_gaddrl); -} - -static void set_multicast_list(struct net_device *dev) -{ - struct dev_mc_list *pmc; - - if ((dev->flags & IFF_PROMISC) == 0) { - set_multicast_start(dev); - for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) - set_multicast_one(dev, pmc->dmi_addr); - set_multicast_finish(dev); - } else - set_promiscuous_mode(dev); -} - -static void restart(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - fcc_t *fccp = fep->fcc.fccp; - fcc_c_t *fcccp = fep->fcc.fcccp; - fcc_enet_t *ep = fep->fcc.ep; - dma_addr_t rx_bd_base_phys, tx_bd_base_phys; - u16 paddrh, paddrm, paddrl; - u16 mem_addr; - const unsigned char *mac; - int i; - - C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); - - /* clear everything (slow & steady does it) */ - for (i = 0; i < sizeof(*ep); i++) - __fcc_out8((char *)ep + i, 0); - - /* get physical address */ - rx_bd_base_phys = fep->ring_mem_addr; - tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; - - /* point to bds */ - W32(ep, fen_genfcc.fcc_rbase, rx_bd_base_phys); - W32(ep, fen_genfcc.fcc_tbase, tx_bd_base_phys); - - /* Set maximum bytes per receive buffer. - * It must be a multiple of 32. - */ - W16(ep, fen_genfcc.fcc_mrblr, PKT_MAXBLR_SIZE); - - W32(ep, fen_genfcc.fcc_rstate, (CPMFCR_GBL | CPMFCR_EB) << 24); - W32(ep, fen_genfcc.fcc_tstate, (CPMFCR_GBL | CPMFCR_EB) << 24); - - /* Allocate space in the reserved FCC area of DPRAM for the - * internal buffers. No one uses this space (yet), so we - * can do this. Later, we will add resource management for - * this area. - */ - - mem_addr = (u32) fep->fcc.mem; /* de-fixup dpram offset */ - - W16(ep, fen_genfcc.fcc_riptr, (mem_addr & 0xffff)); - W16(ep, fen_genfcc.fcc_tiptr, ((mem_addr + 32) & 0xffff)); - W16(ep, fen_padptr, mem_addr + 64); - - /* fill with special symbol... */ - memset(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32); - - W32(ep, fen_genfcc.fcc_rbptr, 0); - W32(ep, fen_genfcc.fcc_tbptr, 0); - W32(ep, fen_genfcc.fcc_rcrc, 0); - W32(ep, fen_genfcc.fcc_tcrc, 0); - W16(ep, fen_genfcc.fcc_res1, 0); - W32(ep, fen_genfcc.fcc_res2, 0); - - /* no CAM */ - W32(ep, fen_camptr, 0); - - /* Set CRC preset and mask */ - W32(ep, fen_cmask, 0xdebb20e3); - W32(ep, fen_cpres, 0xffffffff); - - W32(ep, fen_crcec, 0); /* CRC Error counter */ - W32(ep, fen_alec, 0); /* alignment error counter */ - W32(ep, fen_disfc, 0); /* discard frame counter */ - W16(ep, fen_retlim, 15); /* Retry limit threshold */ - W16(ep, fen_pper, 0); /* Normal persistence */ - - /* set group address */ - W32(ep, fen_gaddrh, fep->fcc.gaddrh); - W32(ep, fen_gaddrl, fep->fcc.gaddrh); - - /* Clear hash filter tables */ - W32(ep, fen_iaddrh, 0); - W32(ep, fen_iaddrl, 0); - - /* Clear the Out-of-sequence TxBD */ - W16(ep, fen_tfcstat, 0); - W16(ep, fen_tfclen, 0); - W32(ep, fen_tfcptr, 0); - - W16(ep, fen_mflr, PKT_MAXBUF_SIZE); /* maximum frame length register */ - W16(ep, fen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ - - /* set address */ - mac = dev->dev_addr; - paddrh = ((u16)mac[5] << 8) | mac[4]; - paddrm = ((u16)mac[3] << 8) | mac[2]; - paddrl = ((u16)mac[1] << 8) | mac[0]; - - W16(ep, fen_paddrh, paddrh); - W16(ep, fen_paddrm, paddrm); - W16(ep, fen_paddrl, paddrl); - - W16(ep, fen_taddrh, 0); - W16(ep, fen_taddrm, 0); - W16(ep, fen_taddrl, 0); - - W16(ep, fen_maxd1, 1520); /* maximum DMA1 length */ - W16(ep, fen_maxd2, 1520); /* maximum DMA2 length */ - - /* Clear stat counters, in case we ever enable RMON */ - W32(ep, fen_octc, 0); - W32(ep, fen_colc, 0); - W32(ep, fen_broc, 0); - W32(ep, fen_mulc, 0); - W32(ep, fen_uspc, 0); - W32(ep, fen_frgc, 0); - W32(ep, fen_ospc, 0); - W32(ep, fen_jbrc, 0); - W32(ep, fen_p64c, 0); - W32(ep, fen_p65c, 0); - W32(ep, fen_p128c, 0); - W32(ep, fen_p256c, 0); - W32(ep, fen_p512c, 0); - W32(ep, fen_p1024c, 0); - - W16(ep, fen_rfthr, 0); /* Suggested by manual */ - W16(ep, fen_rfcnt, 0); - W16(ep, fen_cftype, 0); - - fs_init_bds(dev); - - /* adjust to speed (for RMII mode) */ - if (fpi->use_rmii) { - if (fep->speed == 100) - C8(fcccp, fcc_gfemr, 0x20); - else - S8(fcccp, fcc_gfemr, 0x20); - } - - fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX); - - /* clear events */ - W16(fccp, fcc_fcce, 0xffff); - - /* Enable interrupts we wish to service */ - W16(fccp, fcc_fccm, FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB); - - /* Set GFMR to enable Ethernet operating mode */ - W32(fccp, fcc_gfmr, FCC_GFMR_TCI | FCC_GFMR_MODE_ENET); - - /* set sync/delimiters */ - W16(fccp, fcc_fdsr, 0xd555); - - W32(fccp, fcc_fpsmr, FCC_PSMR_ENCRC); - - if (fpi->use_rmii) - S32(fccp, fcc_fpsmr, FCC_PSMR_RMII); - - /* adjust to duplex mode */ - if (fep->duplex) - S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); - else - C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); - - S32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); -} - -static void stop(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; - - /* stop ethernet */ - C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); - - /* clear events */ - W16(fccp, fcc_fcce, 0xffff); - - /* clear interrupt mask */ - W16(fccp, fcc_fccm, 0); - - fs_cleanup_bds(dev); -} - -static void pre_request_irq(struct net_device *dev, int irq) -{ - /* nothing */ -} - -static void post_free_irq(struct net_device *dev, int irq) -{ - /* nothing */ -} - -static void napi_clear_rx_event(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; - - W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK); -} - -static void napi_enable_rx(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; - - S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); -} - -static void napi_disable_rx(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; - - C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); -} - -static void rx_bd_done(struct net_device *dev) -{ - /* nothing */ -} - -static void tx_kickstart(struct net_device *dev) -{ - /* nothing */ -} - -static u32 get_int_events(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; - - return (u32)R16(fccp, fcc_fcce); -} - -static void clear_int_events(struct net_device *dev, u32 int_events) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; - - W16(fccp, fcc_fcce, int_events & 0xffff); -} - -static void ev_error(struct net_device *dev, u32 int_events) -{ - printk(KERN_WARNING DRV_MODULE_NAME - ": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events); -} - -int get_regs(struct net_device *dev, void *p, int *sizep) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t)) - return -EINVAL; - - memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t)); - p = (char *)p + sizeof(fcc_t); - - memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t)); - p = (char *)p + sizeof(fcc_c_t); - - memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t)); - - return 0; -} - -int get_regs_len(struct net_device *dev) -{ - return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t); -} - -/* Some transmit errors cause the transmitter to shut - * down. We now issue a restart transmit. Since the - * errors close the BD and update the pointers, the restart - * _should_ pick up without having to reset any of our - * pointers either. Also, To workaround 8260 device erratum - * CPM37, we must disable and then re-enable the transmitter - * following a Late Collision, Underrun, or Retry Limit error. - */ -void tx_restart(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; - - C32(fccp, fcc_gfmr, FCC_GFMR_ENT); - udelay(10); - S32(fccp, fcc_gfmr, FCC_GFMR_ENT); - - fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX); -} - -/*************************************************************************/ - -const struct fs_ops fs_fcc_ops = { - .setup_data = setup_data, - .cleanup_data = cleanup_data, - .set_multicast_list = set_multicast_list, - .restart = restart, - .stop = stop, - .pre_request_irq = pre_request_irq, - .post_free_irq = post_free_irq, - .napi_clear_rx_event = napi_clear_rx_event, - .napi_enable_rx = napi_enable_rx, - .napi_disable_rx = napi_disable_rx, - .rx_bd_done = rx_bd_done, - .tx_kickstart = tx_kickstart, - .get_int_events = get_int_events, - .clear_int_events = clear_int_events, - .ev_error = ev_error, - .get_regs = get_regs, - .get_regs_len = get_regs_len, - .tx_restart = tx_restart, - .allocate_bd = allocate_bd, - .free_bd = free_bd, -}; diff --git a/trunk/drivers/net/fs_enet/mac-fec.c b/trunk/drivers/net/fs_enet/mac-fec.c deleted file mode 100644 index 5ef4e845a387..000000000000 --- a/trunk/drivers/net/fs_enet/mac-fec.c +++ /dev/null @@ -1,653 +0,0 @@ -/* - * Freescale Ethernet controllers - * - * Copyright (c) 2005 Intracom S.A. - * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef CONFIG_8xx -#include -#include -#include -#include -#endif - -#include "fs_enet.h" - -/*************************************************/ - -#if defined(CONFIG_CPM1) -/* for a CPM1 __raw_xxx's are sufficient */ -#define __fs_out32(addr, x) __raw_writel(x, addr) -#define __fs_out16(addr, x) __raw_writew(x, addr) -#define __fs_in32(addr) __raw_readl(addr) -#define __fs_in16(addr) __raw_readw(addr) -#else -/* for others play it safe */ -#define __fs_out32(addr, x) out_be32(addr, x) -#define __fs_out16(addr, x) out_be16(addr, x) -#define __fs_in32(addr) in_be32(addr) -#define __fs_in16(addr) in_be16(addr) -#endif - -/* write */ -#define FW(_fecp, _reg, _v) __fs_out32(&(_fecp)->fec_ ## _reg, (_v)) - -/* read */ -#define FR(_fecp, _reg) __fs_in32(&(_fecp)->fec_ ## _reg) - -/* set bits */ -#define FS(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) | (_v)) - -/* clear bits */ -#define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v)) - - -/* CRC polynomium used by the FEC for the multicast group filtering */ -#define FEC_CRC_POLY 0x04C11DB7 - -#define FEC_MAX_MULTICAST_ADDRS 64 - -/* Interrupt events/masks. -*/ -#define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */ -#define FEC_ENET_BABR 0x40000000U /* Babbling receiver */ -#define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */ -#define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */ -#define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */ -#define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */ -#define FEC_ENET_RXF 0x02000000U /* Full frame received */ -#define FEC_ENET_RXB 0x01000000U /* A buffer was received */ -#define FEC_ENET_MII 0x00800000U /* MII interrupt */ -#define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */ - -#define FEC_ECNTRL_PINMUX 0x00000004 -#define FEC_ECNTRL_ETHER_EN 0x00000002 -#define FEC_ECNTRL_RESET 0x00000001 - -#define FEC_RCNTRL_BC_REJ 0x00000010 -#define FEC_RCNTRL_PROM 0x00000008 -#define FEC_RCNTRL_MII_MODE 0x00000004 -#define FEC_RCNTRL_DRT 0x00000002 -#define FEC_RCNTRL_LOOP 0x00000001 - -#define FEC_TCNTRL_FDEN 0x00000004 -#define FEC_TCNTRL_HBC 0x00000002 -#define FEC_TCNTRL_GTS 0x00000001 - - -/* Make MII read/write commands for the FEC. -*/ -#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) -#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) -#define mk_mii_end 0 - -#define FEC_MII_LOOPS 10000 - -/* - * Delay to wait for FEC reset command to complete (in us) - */ -#define FEC_RESET_DELAY 50 - -static int whack_reset(fec_t * fecp) -{ - int i; - - FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET); - for (i = 0; i < FEC_RESET_DELAY; i++) { - if ((FR(fecp, ecntrl) & FEC_ECNTRL_RESET) == 0) - return 0; /* OK */ - udelay(1); - } - - return -1; -} - -static int do_pd_setup(struct fs_enet_private *fep) -{ - struct platform_device *pdev = to_platform_device(fep->dev); - struct resource *r; - - /* Fill out IRQ field */ - fep->interrupt = platform_get_irq_byname(pdev,"interrupt"); - - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); - fep->fec.fecp =(void*)r->start; - - if(fep->fec.fecp == NULL) - return -EINVAL; - - return 0; - -} - -#define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB) -#define FEC_RX_EVENT (FEC_ENET_RXF) -#define FEC_TX_EVENT (FEC_ENET_TXF) -#define FEC_ERR_EVENT_MSK (FEC_ENET_HBERR | FEC_ENET_BABR | \ - FEC_ENET_BABT | FEC_ENET_EBERR) - -static int setup_data(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - if (do_pd_setup(fep) != 0) - return -EINVAL; - - fep->fec.hthi = 0; - fep->fec.htlo = 0; - - fep->ev_napi_rx = FEC_NAPI_RX_EVENT_MSK; - fep->ev_rx = FEC_RX_EVENT; - fep->ev_tx = FEC_TX_EVENT; - fep->ev_err = FEC_ERR_EVENT_MSK; - - return 0; -} - -static int allocate_bd(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - - fep->ring_base = dma_alloc_coherent(fep->dev, - (fpi->tx_ring + fpi->rx_ring) * - sizeof(cbd_t), &fep->ring_mem_addr, - GFP_KERNEL); - if (fep->ring_base == NULL) - return -ENOMEM; - - return 0; -} - -static void free_bd(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - - if(fep->ring_base) - dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) - * sizeof(cbd_t), - fep->ring_base, - fep->ring_mem_addr); -} - -static void cleanup_data(struct net_device *dev) -{ - /* nothing */ -} - -static void set_promiscuous_mode(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; - - FS(fecp, r_cntrl, FEC_RCNTRL_PROM); -} - -static void set_multicast_start(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - fep->fec.hthi = 0; - fep->fec.htlo = 0; -} - -static void set_multicast_one(struct net_device *dev, const u8 *mac) -{ - struct fs_enet_private *fep = netdev_priv(dev); - int temp, hash_index, i, j; - u32 crc, csrVal; - u8 byte, msb; - - crc = 0xffffffff; - for (i = 0; i < 6; i++) { - byte = mac[i]; - for (j = 0; j < 8; j++) { - msb = crc >> 31; - crc <<= 1; - if (msb ^ (byte & 0x1)) - crc ^= FEC_CRC_POLY; - byte >>= 1; - } - } - - temp = (crc & 0x3f) >> 1; - hash_index = ((temp & 0x01) << 4) | - ((temp & 0x02) << 2) | - ((temp & 0x04)) | - ((temp & 0x08) >> 2) | - ((temp & 0x10) >> 4); - csrVal = 1 << hash_index; - if (crc & 1) - fep->fec.hthi |= csrVal; - else - fep->fec.htlo |= csrVal; -} - -static void set_multicast_finish(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; - - /* if all multi or too many multicasts; just enable all */ - if ((dev->flags & IFF_ALLMULTI) != 0 || - dev->mc_count > FEC_MAX_MULTICAST_ADDRS) { - fep->fec.hthi = 0xffffffffU; - fep->fec.htlo = 0xffffffffU; - } - - FC(fecp, r_cntrl, FEC_RCNTRL_PROM); - FW(fecp, hash_table_high, fep->fec.hthi); - FW(fecp, hash_table_low, fep->fec.htlo); -} - -static void set_multicast_list(struct net_device *dev) -{ - struct dev_mc_list *pmc; - - if ((dev->flags & IFF_PROMISC) == 0) { - set_multicast_start(dev); - for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) - set_multicast_one(dev, pmc->dmi_addr); - set_multicast_finish(dev); - } else - set_promiscuous_mode(dev); -} - -static void restart(struct net_device *dev) -{ -#ifdef CONFIG_DUET - immap_t *immap = fs_enet_immap; - u32 cptr; -#endif - struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; - const struct fs_platform_info *fpi = fep->fpi; - dma_addr_t rx_bd_base_phys, tx_bd_base_phys; - int r; - u32 addrhi, addrlo; - - r = whack_reset(fep->fec.fecp); - if (r != 0) - printk(KERN_ERR DRV_MODULE_NAME - ": %s FEC Reset FAILED!\n", dev->name); - - /* - * Set station address. - */ - addrhi = ((u32) dev->dev_addr[0] << 24) | - ((u32) dev->dev_addr[1] << 16) | - ((u32) dev->dev_addr[2] << 8) | - (u32) dev->dev_addr[3]; - addrlo = ((u32) dev->dev_addr[4] << 24) | - ((u32) dev->dev_addr[5] << 16); - FW(fecp, addr_low, addrhi); - FW(fecp, addr_high, addrlo); - - /* - * Reset all multicast. - */ - FW(fecp, hash_table_high, fep->fec.hthi); - FW(fecp, hash_table_low, fep->fec.htlo); - - /* - * Set maximum receive buffer size. - */ - FW(fecp, r_buff_size, PKT_MAXBLR_SIZE); - FW(fecp, r_hash, PKT_MAXBUF_SIZE); - - /* get physical address */ - rx_bd_base_phys = fep->ring_mem_addr; - tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; - - /* - * Set receive and transmit descriptor base. - */ - FW(fecp, r_des_start, rx_bd_base_phys); - FW(fecp, x_des_start, tx_bd_base_phys); - - fs_init_bds(dev); - - /* - * Enable big endian and don't care about SDMA FC. - */ - FW(fecp, fun_code, 0x78000000); - - /* - * Set MII speed. - */ - FW(fecp, mii_speed, fep->mii_bus->fec.mii_speed); - - /* - * Clear any outstanding interrupt. - */ - FW(fecp, ievent, 0xffc0); - FW(fecp, ivec, (fep->interrupt / 2) << 29); - - - /* - * adjust to speed (only for DUET & RMII) - */ -#ifdef CONFIG_DUET - if (fpi->use_rmii) { - cptr = in_be32(&immap->im_cpm.cp_cptr); - switch (fs_get_fec_index(fpi->fs_no)) { - case 0: - cptr |= 0x100; - if (fep->speed == 10) - cptr |= 0x0000010; - else if (fep->speed == 100) - cptr &= ~0x0000010; - break; - case 1: - cptr |= 0x80; - if (fep->speed == 10) - cptr |= 0x0000008; - else if (fep->speed == 100) - cptr &= ~0x0000008; - break; - default: - BUG(); /* should never happen */ - break; - } - out_be32(&immap->im_cpm.cp_cptr, cptr); - } -#endif - - FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ - /* - * adjust to duplex mode - */ - if (fep->duplex) { - FC(fecp, r_cntrl, FEC_RCNTRL_DRT); - FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */ - } else { - FS(fecp, r_cntrl, FEC_RCNTRL_DRT); - FC(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD disable */ - } - - /* - * Enable interrupts we wish to service. - */ - FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB | - FEC_ENET_RXF | FEC_ENET_RXB); - - /* - * And last, enable the transmit and receive processing. - */ - FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); - FW(fecp, r_des_active, 0x01000000); -} - -static void stop(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; - struct fs_enet_mii_bus *bus = fep->mii_bus; - const struct fs_mii_bus_info *bi = bus->bus_info; - int i; - - if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0) - return; /* already down */ - - FW(fecp, x_cntrl, 0x01); /* Graceful transmit stop */ - for (i = 0; ((FR(fecp, ievent) & 0x10000000) == 0) && - i < FEC_RESET_DELAY; i++) - udelay(1); - - if (i == FEC_RESET_DELAY) - printk(KERN_WARNING DRV_MODULE_NAME - ": %s FEC timeout on graceful transmit stop\n", - dev->name); - /* - * Disable FEC. Let only MII interrupts. - */ - FW(fecp, imask, 0); - FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN); - - fs_cleanup_bds(dev); - - /* shut down FEC1? that's where the mii bus is */ - if (fep->fec.idx == 0 && bus->refs > 1 && bi->method == fsmii_fec) { - FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ - FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); - FW(fecp, ievent, FEC_ENET_MII); - FW(fecp, mii_speed, bus->fec.mii_speed); - } -} - -static void pre_request_irq(struct net_device *dev, int irq) -{ - immap_t *immap = fs_enet_immap; - u32 siel; - - /* SIU interrupt */ - if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) { - - siel = in_be32(&immap->im_siu_conf.sc_siel); - if ((irq & 1) == 0) - siel |= (0x80000000 >> irq); - else - siel &= ~(0x80000000 >> (irq & ~1)); - out_be32(&immap->im_siu_conf.sc_siel, siel); - } -} - -static void post_free_irq(struct net_device *dev, int irq) -{ - /* nothing */ -} - -static void napi_clear_rx_event(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; - - FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK); -} - -static void napi_enable_rx(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; - - FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK); -} - -static void napi_disable_rx(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; - - FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK); -} - -static void rx_bd_done(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; - - FW(fecp, r_des_active, 0x01000000); -} - -static void tx_kickstart(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; - - FW(fecp, x_des_active, 0x01000000); -} - -static u32 get_int_events(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; - - return FR(fecp, ievent) & FR(fecp, imask); -} - -static void clear_int_events(struct net_device *dev, u32 int_events) -{ - struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; - - FW(fecp, ievent, int_events); -} - -static void ev_error(struct net_device *dev, u32 int_events) -{ - printk(KERN_WARNING DRV_MODULE_NAME - ": %s FEC ERROR(s) 0x%x\n", dev->name, int_events); -} - -int get_regs(struct net_device *dev, void *p, int *sizep) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - if (*sizep < sizeof(fec_t)) - return -EINVAL; - - memcpy_fromio(p, fep->fec.fecp, sizeof(fec_t)); - - return 0; -} - -int get_regs_len(struct net_device *dev) -{ - return sizeof(fec_t); -} - -void tx_restart(struct net_device *dev) -{ - /* nothing */ -} - -/*************************************************************************/ - -const struct fs_ops fs_fec_ops = { - .setup_data = setup_data, - .cleanup_data = cleanup_data, - .set_multicast_list = set_multicast_list, - .restart = restart, - .stop = stop, - .pre_request_irq = pre_request_irq, - .post_free_irq = post_free_irq, - .napi_clear_rx_event = napi_clear_rx_event, - .napi_enable_rx = napi_enable_rx, - .napi_disable_rx = napi_disable_rx, - .rx_bd_done = rx_bd_done, - .tx_kickstart = tx_kickstart, - .get_int_events = get_int_events, - .clear_int_events = clear_int_events, - .ev_error = ev_error, - .get_regs = get_regs, - .get_regs_len = get_regs_len, - .tx_restart = tx_restart, - .allocate_bd = allocate_bd, - .free_bd = free_bd, -}; - -/***********************************************************************/ - -static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) -{ - fec_t *fecp = bus->fec.fecp; - int i, ret = -1; - - if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) - BUG(); - - /* Add PHY address to register command. */ - FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location)); - - for (i = 0; i < FEC_MII_LOOPS; i++) - if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) - break; - - if (i < FEC_MII_LOOPS) { - FW(fecp, ievent, FEC_ENET_MII); - ret = FR(fecp, mii_data) & 0xffff; - } - - return ret; -} - -static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int value) -{ - fec_t *fecp = bus->fec.fecp; - int i; - - /* this must never happen */ - if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) - BUG(); - - /* Add PHY address to register command. */ - FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value)); - - for (i = 0; i < FEC_MII_LOOPS; i++) - if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) - break; - - if (i < FEC_MII_LOOPS) - FW(fecp, ievent, FEC_ENET_MII); -} - -int fs_mii_fec_init(struct fs_enet_mii_bus *bus) -{ - bd_t *bd = (bd_t *)__res; - const struct fs_mii_bus_info *bi = bus->bus_info; - fec_t *fecp; - - if (bi->id != 0) - return -1; - - bus->fec.fecp = &((immap_t *)fs_enet_immap)->im_cpm.cp_fec; - bus->fec.mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) - & 0x3F) << 1; - - fecp = bus->fec.fecp; - - FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ - FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); - FW(fecp, ievent, FEC_ENET_MII); - FW(fecp, mii_speed, bus->fec.mii_speed); - - bus->mii_read = mii_read; - bus->mii_write = mii_write; - - return 0; -} diff --git a/trunk/drivers/net/fs_enet/mac-scc.c b/trunk/drivers/net/fs_enet/mac-scc.c deleted file mode 100644 index d8c6e9cadcf5..000000000000 --- a/trunk/drivers/net/fs_enet/mac-scc.c +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Ethernet on Serial Communications Controller (SCC) driver for Motorola MPC8xx and MPC82xx. - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef CONFIG_8xx -#include -#include -#include -#include -#endif - -#include "fs_enet.h" - -/*************************************************/ - -#if defined(CONFIG_CPM1) -/* for a 8xx __raw_xxx's are sufficient */ -#define __fs_out32(addr, x) __raw_writel(x, addr) -#define __fs_out16(addr, x) __raw_writew(x, addr) -#define __fs_out8(addr, x) __raw_writeb(x, addr) -#define __fs_in32(addr) __raw_readl(addr) -#define __fs_in16(addr) __raw_readw(addr) -#define __fs_in8(addr) __raw_readb(addr) -#else -/* for others play it safe */ -#define __fs_out32(addr, x) out_be32(addr, x) -#define __fs_out16(addr, x) out_be16(addr, x) -#define __fs_in32(addr) in_be32(addr) -#define __fs_in16(addr) in_be16(addr) -#endif - -/* write, read, set bits, clear bits */ -#define W32(_p, _m, _v) __fs_out32(&(_p)->_m, (_v)) -#define R32(_p, _m) __fs_in32(&(_p)->_m) -#define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) -#define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) - -#define W16(_p, _m, _v) __fs_out16(&(_p)->_m, (_v)) -#define R16(_p, _m) __fs_in16(&(_p)->_m) -#define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) -#define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) - -#define W8(_p, _m, _v) __fs_out8(&(_p)->_m, (_v)) -#define R8(_p, _m) __fs_in8(&(_p)->_m) -#define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) -#define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) - -#define SCC_MAX_MULTICAST_ADDRS 64 - -/* - * Delay to wait for SCC reset command to complete (in us) - */ -#define SCC_RESET_DELAY 50 -#define MAX_CR_CMD_LOOPS 10000 - -static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op) -{ - cpm8xx_t *cpmp = &((immap_t *)fs_enet_immap)->im_cpm; - u32 v, ch; - int i = 0; - - ch = fep->scc.idx << 2; - v = mk_cr_cmd(ch, op); - W16(cpmp, cp_cpcr, v | CPM_CR_FLG); - for (i = 0; i < MAX_CR_CMD_LOOPS; i++) - if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0) - break; - - if (i >= MAX_CR_CMD_LOOPS) { - printk(KERN_ERR "%s(): Not able to issue CPM command\n", - __FUNCTION__); - return 1; - } - return 0; -} - -static int do_pd_setup(struct fs_enet_private *fep) -{ - struct platform_device *pdev = to_platform_device(fep->dev); - struct resource *r; - - /* Fill out IRQ field */ - fep->interrupt = platform_get_irq_byname(pdev, "interrupt"); - - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); - fep->scc.sccp = (void *)r->start; - - if (fep->scc.sccp == NULL) - return -EINVAL; - - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram"); - fep->scc.ep = (void *)r->start; - - if (fep->scc.ep == NULL) - return -EINVAL; - - return 0; -} - -#define SCC_NAPI_RX_EVENT_MSK (SCCE_ENET_RXF | SCCE_ENET_RXB) -#define SCC_RX_EVENT (SCCE_ENET_RXF) -#define SCC_TX_EVENT (SCCE_ENET_TXB) -#define SCC_ERR_EVENT_MSK (SCCE_ENET_TXE | SCCE_ENET_BSY) - -static int setup_data(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - - fep->scc.idx = fs_get_scc_index(fpi->fs_no); - if ((unsigned int)fep->fcc.idx > 4) /* max 4 SCCs */ - return -EINVAL; - - do_pd_setup(fep); - - fep->scc.hthi = 0; - fep->scc.htlo = 0; - - fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK; - fep->ev_rx = SCC_RX_EVENT; - fep->ev_tx = SCC_TX_EVENT; - fep->ev_err = SCC_ERR_EVENT_MSK; - - return 0; -} - -static int allocate_bd(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - - fep->ring_mem_addr = cpm_dpalloc((fpi->tx_ring + fpi->rx_ring) * - sizeof(cbd_t), 8); - if (IS_DPERR(fep->ring_mem_addr)) - return -ENOMEM; - - fep->ring_base = cpm_dpram_addr(fep->ring_mem_addr); - - return 0; -} - -static void free_bd(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - if (fep->ring_base) - cpm_dpfree(fep->ring_mem_addr); -} - -static void cleanup_data(struct net_device *dev) -{ - /* nothing */ -} - -static void set_promiscuous_mode(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; - - S16(sccp, scc_psmr, SCC_PSMR_PRO); -} - -static void set_multicast_start(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - scc_enet_t *ep = fep->scc.ep; - - W16(ep, sen_gaddr1, 0); - W16(ep, sen_gaddr2, 0); - W16(ep, sen_gaddr3, 0); - W16(ep, sen_gaddr4, 0); -} - -static void set_multicast_one(struct net_device *dev, const u8 * mac) -{ - struct fs_enet_private *fep = netdev_priv(dev); - scc_enet_t *ep = fep->scc.ep; - u16 taddrh, taddrm, taddrl; - - taddrh = ((u16) mac[5] << 8) | mac[4]; - taddrm = ((u16) mac[3] << 8) | mac[2]; - taddrl = ((u16) mac[1] << 8) | mac[0]; - - W16(ep, sen_taddrh, taddrh); - W16(ep, sen_taddrm, taddrm); - W16(ep, sen_taddrl, taddrl); - scc_cr_cmd(fep, CPM_CR_SET_GADDR); -} - -static void set_multicast_finish(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; - scc_enet_t *ep = fep->scc.ep; - - /* clear promiscuous always */ - C16(sccp, scc_psmr, SCC_PSMR_PRO); - - /* if all multi or too many multicasts; just enable all */ - if ((dev->flags & IFF_ALLMULTI) != 0 || - dev->mc_count > SCC_MAX_MULTICAST_ADDRS) { - - W16(ep, sen_gaddr1, 0xffff); - W16(ep, sen_gaddr2, 0xffff); - W16(ep, sen_gaddr3, 0xffff); - W16(ep, sen_gaddr4, 0xffff); - } -} - -static void set_multicast_list(struct net_device *dev) -{ - struct dev_mc_list *pmc; - - if ((dev->flags & IFF_PROMISC) == 0) { - set_multicast_start(dev); - for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) - set_multicast_one(dev, pmc->dmi_addr); - set_multicast_finish(dev); - } else - set_promiscuous_mode(dev); -} - -/* - * This function is called to start or restart the FEC during a link - * change. This only happens when switching between half and full - * duplex. - */ -static void restart(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; - scc_enet_t *ep = fep->scc.ep; - const struct fs_platform_info *fpi = fep->fpi; - u16 paddrh, paddrm, paddrl; - const unsigned char *mac; - int i; - - C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - /* clear everything (slow & steady does it) */ - for (i = 0; i < sizeof(*ep); i++) - __fs_out8((char *)ep + i, 0); - - /* point to bds */ - W16(ep, sen_genscc.scc_rbase, fep->ring_mem_addr); - W16(ep, sen_genscc.scc_tbase, - fep->ring_mem_addr + sizeof(cbd_t) * fpi->rx_ring); - - /* Initialize function code registers for big-endian. - */ - W8(ep, sen_genscc.scc_rfcr, SCC_EB); - W8(ep, sen_genscc.scc_tfcr, SCC_EB); - - /* Set maximum bytes per receive buffer. - * This appears to be an Ethernet frame size, not the buffer - * fragment size. It must be a multiple of four. - */ - W16(ep, sen_genscc.scc_mrblr, 0x5f0); - - /* Set CRC preset and mask. - */ - W32(ep, sen_cpres, 0xffffffff); - W32(ep, sen_cmask, 0xdebb20e3); - - W32(ep, sen_crcec, 0); /* CRC Error counter */ - W32(ep, sen_alec, 0); /* alignment error counter */ - W32(ep, sen_disfc, 0); /* discard frame counter */ - - W16(ep, sen_pads, 0x8888); /* Tx short frame pad character */ - W16(ep, sen_retlim, 15); /* Retry limit threshold */ - - W16(ep, sen_maxflr, 0x5ee); /* maximum frame length register */ - - W16(ep, sen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ - - W16(ep, sen_maxd1, 0x000005f0); /* maximum DMA1 length */ - W16(ep, sen_maxd2, 0x000005f0); /* maximum DMA2 length */ - - /* Clear hash tables. - */ - W16(ep, sen_gaddr1, 0); - W16(ep, sen_gaddr2, 0); - W16(ep, sen_gaddr3, 0); - W16(ep, sen_gaddr4, 0); - W16(ep, sen_iaddr1, 0); - W16(ep, sen_iaddr2, 0); - W16(ep, sen_iaddr3, 0); - W16(ep, sen_iaddr4, 0); - - /* set address - */ - mac = dev->dev_addr; - paddrh = ((u16) mac[5] << 8) | mac[4]; - paddrm = ((u16) mac[3] << 8) | mac[2]; - paddrl = ((u16) mac[1] << 8) | mac[0]; - - W16(ep, sen_paddrh, paddrh); - W16(ep, sen_paddrm, paddrm); - W16(ep, sen_paddrl, paddrl); - - W16(ep, sen_pper, 0); - W16(ep, sen_taddrl, 0); - W16(ep, sen_taddrm, 0); - W16(ep, sen_taddrh, 0); - - fs_init_bds(dev); - - scc_cr_cmd(fep, CPM_CR_INIT_TRX); - - W16(sccp, scc_scce, 0xffff); - - /* Enable interrupts we wish to service. - */ - W16(sccp, scc_sccm, SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); - - /* Set GSMR_H to enable all normal operating modes. - * Set GSMR_L to enable Ethernet to MC68160. - */ - W32(sccp, scc_gsmrh, 0); - W32(sccp, scc_gsmrl, - SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | - SCC_GSMRL_MODE_ENET); - - /* Set sync/delimiters. - */ - W16(sccp, scc_dsr, 0xd555); - - /* Set processing mode. Use Ethernet CRC, catch broadcast, and - * start frame search 22 bit times after RENA. - */ - W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22); - - /* Set full duplex mode if needed */ - if (fep->duplex) - S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE); - - S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); -} - -static void stop(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; - int i; - - for (i = 0; (R16(sccp, scc_sccm) == 0) && i < SCC_RESET_DELAY; i++) - udelay(1); - - if (i == SCC_RESET_DELAY) - printk(KERN_WARNING DRV_MODULE_NAME - ": %s SCC timeout on graceful transmit stop\n", - dev->name); - - W16(sccp, scc_sccm, 0); - C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - fs_cleanup_bds(dev); -} - -static void pre_request_irq(struct net_device *dev, int irq) -{ - immap_t *immap = fs_enet_immap; - u32 siel; - - /* SIU interrupt */ - if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) { - - siel = in_be32(&immap->im_siu_conf.sc_siel); - if ((irq & 1) == 0) - siel |= (0x80000000 >> irq); - else - siel &= ~(0x80000000 >> (irq & ~1)); - out_be32(&immap->im_siu_conf.sc_siel, siel); - } -} - -static void post_free_irq(struct net_device *dev, int irq) -{ - /* nothing */ -} - -static void napi_clear_rx_event(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; - - W16(sccp, scc_scce, SCC_NAPI_RX_EVENT_MSK); -} - -static void napi_enable_rx(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; - - S16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); -} - -static void napi_disable_rx(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; - - C16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); -} - -static void rx_bd_done(struct net_device *dev) -{ - /* nothing */ -} - -static void tx_kickstart(struct net_device *dev) -{ - /* nothing */ -} - -static u32 get_int_events(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; - - return (u32) R16(sccp, scc_scce); -} - -static void clear_int_events(struct net_device *dev, u32 int_events) -{ - struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; - - W16(sccp, scc_scce, int_events & 0xffff); -} - -static void ev_error(struct net_device *dev, u32 int_events) -{ - printk(KERN_WARNING DRV_MODULE_NAME - ": %s SCC ERROR(s) 0x%x\n", dev->name, int_events); -} - -static int get_regs(struct net_device *dev, void *p, int *sizep) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t)) - return -EINVAL; - - memcpy_fromio(p, fep->scc.sccp, sizeof(scc_t)); - p = (char *)p + sizeof(scc_t); - - memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t)); - - return 0; -} - -static int get_regs_len(struct net_device *dev) -{ - return sizeof(scc_t) + sizeof(scc_enet_t); -} - -static void tx_restart(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - scc_cr_cmd(fep, CPM_CR_RESTART_TX); -} - -/*************************************************************************/ - -const struct fs_ops fs_scc_ops = { - .setup_data = setup_data, - .cleanup_data = cleanup_data, - .set_multicast_list = set_multicast_list, - .restart = restart, - .stop = stop, - .pre_request_irq = pre_request_irq, - .post_free_irq = post_free_irq, - .napi_clear_rx_event = napi_clear_rx_event, - .napi_enable_rx = napi_enable_rx, - .napi_disable_rx = napi_disable_rx, - .rx_bd_done = rx_bd_done, - .tx_kickstart = tx_kickstart, - .get_int_events = get_int_events, - .clear_int_events = clear_int_events, - .ev_error = ev_error, - .get_regs = get_regs, - .get_regs_len = get_regs_len, - .tx_restart = tx_restart, - .allocate_bd = allocate_bd, - .free_bd = free_bd, -}; diff --git a/trunk/drivers/net/fs_enet/mii-bitbang.c b/trunk/drivers/net/fs_enet/mii-bitbang.c deleted file mode 100644 index 24a5e2e23d18..000000000000 --- a/trunk/drivers/net/fs_enet/mii-bitbang.c +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "fs_enet.h" - -#ifdef CONFIG_8xx -static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) -{ - immap_t *im = (immap_t *)fs_enet_immap; - void *dir, *dat, *ppar; - int adv; - u8 msk; - - switch (port) { - case fsiop_porta: - dir = &im->im_ioport.iop_padir; - dat = &im->im_ioport.iop_padat; - ppar = &im->im_ioport.iop_papar; - break; - - case fsiop_portb: - dir = &im->im_cpm.cp_pbdir; - dat = &im->im_cpm.cp_pbdat; - ppar = &im->im_cpm.cp_pbpar; - break; - - case fsiop_portc: - dir = &im->im_ioport.iop_pcdir; - dat = &im->im_ioport.iop_pcdat; - ppar = &im->im_ioport.iop_pcpar; - break; - - case fsiop_portd: - dir = &im->im_ioport.iop_pddir; - dat = &im->im_ioport.iop_pddat; - ppar = &im->im_ioport.iop_pdpar; - break; - - case fsiop_porte: - dir = &im->im_cpm.cp_pedir; - dat = &im->im_cpm.cp_pedat; - ppar = &im->im_cpm.cp_pepar; - break; - - default: - printk(KERN_ERR DRV_MODULE_NAME - "Illegal port value %d!\n", port); - return -EINVAL; - } - - adv = bit >> 3; - dir = (char *)dir + adv; - dat = (char *)dat + adv; - ppar = (char *)ppar + adv; - - msk = 1 << (7 - (bit & 7)); - if ((in_8(ppar) & msk) != 0) { - printk(KERN_ERR DRV_MODULE_NAME - "pin %d on port %d is not general purpose!\n", bit, port); - return -EINVAL; - } - - *dirp = dir; - *datp = dat; - *mskp = msk; - - return 0; -} -#endif - -#ifdef CONFIG_8260 -static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) -{ - iop_cpm2_t *io = &((cpm2_map_t *)fs_enet_immap)->im_ioport; - void *dir, *dat, *ppar; - int adv; - u8 msk; - - switch (port) { - case fsiop_porta: - dir = &io->iop_pdira; - dat = &io->iop_pdata; - ppar = &io->iop_ppara; - break; - - case fsiop_portb: - dir = &io->iop_pdirb; - dat = &io->iop_pdatb; - ppar = &io->iop_pparb; - break; - - case fsiop_portc: - dir = &io->iop_pdirc; - dat = &io->iop_pdatc; - ppar = &io->iop_pparc; - break; - - case fsiop_portd: - dir = &io->iop_pdird; - dat = &io->iop_pdatd; - ppar = &io->iop_ppard; - break; - - default: - printk(KERN_ERR DRV_MODULE_NAME - "Illegal port value %d!\n", port); - return -EINVAL; - } - - adv = bit >> 3; - dir = (char *)dir + adv; - dat = (char *)dat + adv; - ppar = (char *)ppar + adv; - - msk = 1 << (7 - (bit & 7)); - if ((in_8(ppar) & msk) != 0) { - printk(KERN_ERR DRV_MODULE_NAME - "pin %d on port %d is not general purpose!\n", bit, port); - return -EINVAL; - } - - *dirp = dir; - *datp = dat; - *mskp = msk; - - return 0; -} -#endif - -static inline void bb_set(u8 *p, u8 m) -{ - out_8(p, in_8(p) | m); -} - -static inline void bb_clr(u8 *p, u8 m) -{ - out_8(p, in_8(p) & ~m); -} - -static inline int bb_read(u8 *p, u8 m) -{ - return (in_8(p) & m) != 0; -} - -static inline void mdio_active(struct fs_enet_mii_bus *bus) -{ - bb_set(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); -} - -static inline void mdio_tristate(struct fs_enet_mii_bus *bus) -{ - bb_clr(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); -} - -static inline int mdio_read(struct fs_enet_mii_bus *bus) -{ - return bb_read(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); -} - -static inline void mdio(struct fs_enet_mii_bus *bus, int what) -{ - if (what) - bb_set(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); - else - bb_clr(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); -} - -static inline void mdc(struct fs_enet_mii_bus *bus, int what) -{ - if (what) - bb_set(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); - else - bb_clr(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); -} - -static inline void mii_delay(struct fs_enet_mii_bus *bus) -{ - udelay(bus->bus_info->i.bitbang.delay); -} - -/* Utility to send the preamble, address, and register (common to read and write). */ -static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg) -{ - int j; - - /* - * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure. - * The IEEE spec says this is a PHY optional requirement. The AMD - * 79C874 requires one after power up and one after a MII communications - * error. This means that we are doing more preambles than we need, - * but it is safer and will be much more robust. - */ - - mdio_active(bus); - mdio(bus, 1); - for (j = 0; j < 32; j++) { - mdc(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - } - - /* send the start bit (01) and the read opcode (10) or write (10) */ - mdc(bus, 0); - mdio(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - mdc(bus, 0); - mdio(bus, 1); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - mdc(bus, 0); - mdio(bus, read); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - mdc(bus, 0); - mdio(bus, !read); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - - /* send the PHY address */ - for (j = 0; j < 5; j++) { - mdc(bus, 0); - mdio(bus, (addr & 0x10) != 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - addr <<= 1; - } - - /* send the register address */ - for (j = 0; j < 5; j++) { - mdc(bus, 0); - mdio(bus, (reg & 0x10) != 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - reg <<= 1; - } -} - -static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) -{ - u16 rdreg; - int ret, j; - u8 addr = phy_id & 0xff; - u8 reg = location & 0xff; - - bitbang_pre(bus, 1, addr, reg); - - /* tri-state our MDIO I/O pin so we can read */ - mdc(bus, 0); - mdio_tristate(bus); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - - /* check the turnaround bit: the PHY should be driving it to zero */ - if (mdio_read(bus) != 0) { - /* PHY didn't drive TA low */ - for (j = 0; j < 32; j++) { - mdc(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - } - ret = -1; - goto out; - } - - mdc(bus, 0); - mii_delay(bus); - - /* read 16 bits of register data, MSB first */ - rdreg = 0; - for (j = 0; j < 16; j++) { - mdc(bus, 1); - mii_delay(bus); - rdreg <<= 1; - rdreg |= mdio_read(bus); - mdc(bus, 0); - mii_delay(bus); - } - - mdc(bus, 1); - mii_delay(bus); - mdc(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - - ret = rdreg; -out: - return ret; -} - -static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val) -{ - int j; - u8 addr = phy_id & 0xff; - u8 reg = location & 0xff; - u16 value = val & 0xffff; - - bitbang_pre(bus, 0, addr, reg); - - /* send the turnaround (10) */ - mdc(bus, 0); - mdio(bus, 1); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - mdc(bus, 0); - mdio(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - - /* write 16 bits of register data, MSB first */ - for (j = 0; j < 16; j++) { - mdc(bus, 0); - mdio(bus, (value & 0x8000) != 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - value <<= 1; - } - - /* - * Tri-state the MDIO line. - */ - mdio_tristate(bus); - mdc(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); -} - -int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus) -{ - const struct fs_mii_bus_info *bi = bus->bus_info; - int r; - - r = bitbang_prep_bit(&bus->bitbang.mdio_dir, - &bus->bitbang.mdio_dat, - &bus->bitbang.mdio_msk, - bi->i.bitbang.mdio_port, - bi->i.bitbang.mdio_bit); - if (r != 0) - return r; - - r = bitbang_prep_bit(&bus->bitbang.mdc_dir, - &bus->bitbang.mdc_dat, - &bus->bitbang.mdc_msk, - bi->i.bitbang.mdc_port, - bi->i.bitbang.mdc_bit); - if (r != 0) - return r; - - bus->mii_read = mii_read; - bus->mii_write = mii_write; - - return 0; -} diff --git a/trunk/drivers/net/fs_enet/mii-fixed.c b/trunk/drivers/net/fs_enet/mii-fixed.c deleted file mode 100644 index b3e192d612e5..000000000000 --- a/trunk/drivers/net/fs_enet/mii-fixed.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "fs_enet.h" - -static const u16 mii_regs[7] = { - 0x3100, - 0x786d, - 0x0fff, - 0x0fff, - 0x01e1, - 0x45e1, - 0x0003, -}; - -static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) -{ - int ret = 0; - - if ((unsigned int)location >= ARRAY_SIZE(mii_regs)) - return -1; - - if (location != 5) - ret = mii_regs[location]; - else - ret = bus->fixed.lpa; - - return ret; -} - -static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val) -{ - /* do nothing */ -} - -int fs_mii_fixed_init(struct fs_enet_mii_bus *bus) -{ - const struct fs_mii_bus_info *bi = bus->bus_info; - - bus->fixed.lpa = 0x45e1; /* default 100Mb, full duplex */ - - /* if speed is fixed at 10Mb, remove 100Mb modes */ - if (bi->i.fixed.speed == 10) - bus->fixed.lpa &= ~LPA_100; - - /* if duplex is half, remove full duplex modes */ - if (bi->i.fixed.duplex == 0) - bus->fixed.lpa &= ~LPA_DUPLEX; - - bus->mii_read = mii_read; - bus->mii_write = mii_write; - - return 0; -} diff --git a/trunk/drivers/net/hamradio/mkiss.c b/trunk/drivers/net/hamradio/mkiss.c index 3e9accf137e7..85d6dc005be0 100644 --- a/trunk/drivers/net/hamradio/mkiss.c +++ b/trunk/drivers/net/hamradio/mkiss.c @@ -390,8 +390,10 @@ static void ax_changedmtu(struct mkiss *ax) "MTU change cancelled.\n", ax->dev->name); dev->mtu = ax->mtu; - kfree(xbuff); - kfree(rbuff); + if (xbuff != NULL) + kfree(xbuff); + if (rbuff != NULL) + kfree(rbuff); return; } diff --git a/trunk/drivers/net/ibm_emac/Makefile b/trunk/drivers/net/ibm_emac/Makefile index f98ddf0e807a..7f583a333c24 100644 --- a/trunk/drivers/net/ibm_emac/Makefile +++ b/trunk/drivers/net/ibm_emac/Makefile @@ -1,11 +1,12 @@ # -# Makefile for the PowerPC 4xx on-chip ethernet driver +# Makefile for the IBM PPC4xx EMAC controllers # obj-$(CONFIG_IBM_EMAC) += ibm_emac.o -ibm_emac-objs := ibm_emac_mal.o ibm_emac_core.o ibm_emac_phy.o -ibm_emac-$(CONFIG_IBM_EMAC_ZMII) += ibm_emac_zmii.o -ibm_emac-$(CONFIG_IBM_EMAC_RGMII) += ibm_emac_rgmii.o -ibm_emac-$(CONFIG_IBM_EMAC_TAH) += ibm_emac_tah.o -ibm_emac-$(CONFIG_IBM_EMAC_DEBUG) += ibm_emac_debug.o +ibm_emac-objs := ibm_emac_mal.o ibm_emac_core.o ibm_emac_phy.o + +# Only need this if you want to see additional debug messages +ifeq ($(CONFIG_IBM_EMAC_ERRMSG), y) +ibm_emac-objs += ibm_emac_debug.o +endif diff --git a/trunk/drivers/net/ibm_emac/ibm_emac.h b/trunk/drivers/net/ibm_emac/ibm_emac.h index 28c476f28c20..15d5a0e82862 100644 --- a/trunk/drivers/net/ibm_emac/ibm_emac.h +++ b/trunk/drivers/net/ibm_emac/ibm_emac.h @@ -1,142 +1,110 @@ /* - * drivers/net/ibm_emac/ibm_emac.h + * ibm_emac.h * - * Register definitions for PowerPC 4xx on-chip ethernet contoller * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin or + * Armin Kuster akuster@mvista.com + * June, 2002 * - * Based on original work by - * Matt Porter - * Armin Kuster - * Copyright 2002-2004 MontaVista Software Inc. + * 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. - * */ -#ifndef __IBM_EMAC_H_ -#define __IBM_EMAC_H_ - -#include -#include - -/* This is a simple check to prevent use of this driver on non-tested SoCs */ -#if !defined(CONFIG_405GP) && !defined(CONFIG_405GPR) && !defined(CONFIG_405EP) && \ - !defined(CONFIG_440GP) && !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && \ - !defined(CONFIG_440EP) && !defined(CONFIG_NP405H) -#error "Unknown SoC. Please, check chip user manual and make sure EMAC defines are OK" -#endif - -/* EMAC registers Write Access rules */ -struct emac_regs { - u32 mr0; /* special */ - u32 mr1; /* Reset */ - u32 tmr0; /* special */ - u32 tmr1; /* special */ - u32 rmr; /* Reset */ - u32 isr; /* Always */ - u32 iser; /* Reset */ - u32 iahr; /* Reset, R, T */ - u32 ialr; /* Reset, R, T */ - u32 vtpid; /* Reset, R, T */ - u32 vtci; /* Reset, R, T */ - u32 ptr; /* Reset, T */ - u32 iaht1; /* Reset, R */ - u32 iaht2; /* Reset, R */ - u32 iaht3; /* Reset, R */ - u32 iaht4; /* Reset, R */ - u32 gaht1; /* Reset, R */ - u32 gaht2; /* Reset, R */ - u32 gaht3; /* Reset, R */ - u32 gaht4; /* Reset, R */ - u32 lsah; - u32 lsal; - u32 ipgvr; /* Reset, T */ - u32 stacr; /* special */ - u32 trtr; /* special */ - u32 rwmr; /* Reset */ - u32 octx; - u32 ocrx; - u32 ipcr; -}; - -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_ETHTOOL_REGS_VER 0 -#define EMAC_ETHTOOL_REGS_SIZE (sizeof(struct emac_regs) - sizeof(u32)) -#else -#define EMAC_ETHTOOL_REGS_VER 1 -#define EMAC_ETHTOOL_REGS_SIZE sizeof(struct emac_regs) -#endif -/* EMACx_MR0 */ -#define EMAC_MR0_RXI 0x80000000 -#define EMAC_MR0_TXI 0x40000000 -#define EMAC_MR0_SRST 0x20000000 -#define EMAC_MR0_TXE 0x10000000 -#define EMAC_MR0_RXE 0x08000000 -#define EMAC_MR0_WKE 0x04000000 +#ifndef _IBM_EMAC_H_ +#define _IBM_EMAC_H_ +/* General defines needed for the driver */ -/* EMACx_MR1 */ -#define EMAC_MR1_FDE 0x80000000 -#define EMAC_MR1_ILE 0x40000000 -#define EMAC_MR1_VLE 0x20000000 -#define EMAC_MR1_EIFC 0x10000000 -#define EMAC_MR1_APP 0x08000000 -#define EMAC_MR1_IST 0x01000000 +/* Emac */ +typedef struct emac_regs { + u32 em0mr0; + u32 em0mr1; + u32 em0tmr0; + u32 em0tmr1; + u32 em0rmr; + u32 em0isr; + u32 em0iser; + u32 em0iahr; + u32 em0ialr; + u32 em0vtpid; + u32 em0vtci; + u32 em0ptr; + u32 em0iaht1; + u32 em0iaht2; + u32 em0iaht3; + u32 em0iaht4; + u32 em0gaht1; + u32 em0gaht2; + u32 em0gaht3; + u32 em0gaht4; + u32 em0lsah; + u32 em0lsal; + u32 em0ipgvr; + u32 em0stacr; + u32 em0trtr; + u32 em0rwmr; +} emac_t; -#define EMAC_MR1_MF_MASK 0x00c00000 -#define EMAC_MR1_MF_10 0x00000000 -#define EMAC_MR1_MF_100 0x00400000 -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_MR1_MF_1000 0x00000000 -#define EMAC_MR1_MF_1000GPCS 0x00000000 -#define EMAC_MR1_MF_IPPA(id) 0x00000000 -#else -#define EMAC_MR1_MF_1000 0x00800000 -#define EMAC_MR1_MF_1000GPCS 0x00c00000 -#define EMAC_MR1_MF_IPPA(id) (((id) & 0x1f) << 6) -#endif +/* MODE REG 0 */ +#define EMAC_M0_RXI 0x80000000 +#define EMAC_M0_TXI 0x40000000 +#define EMAC_M0_SRST 0x20000000 +#define EMAC_M0_TXE 0x10000000 +#define EMAC_M0_RXE 0x08000000 +#define EMAC_M0_WKE 0x04000000 -#define EMAC_TX_FIFO_SIZE 2048 +/* MODE Reg 1 */ +#define EMAC_M1_FDE 0x80000000 +#define EMAC_M1_ILE 0x40000000 +#define EMAC_M1_VLE 0x20000000 +#define EMAC_M1_EIFC 0x10000000 +#define EMAC_M1_APP 0x08000000 +#define EMAC_M1_AEMI 0x02000000 +#define EMAC_M1_IST 0x01000000 +#define EMAC_M1_MF_1000GPCS 0x00c00000 /* Internal GPCS */ +#define EMAC_M1_MF_1000MBPS 0x00800000 /* External GPCS */ +#define EMAC_M1_MF_100MBPS 0x00400000 +#define EMAC_M1_RFS_16K 0x00280000 /* 000 for 512 byte */ +#define EMAC_M1_TR 0x00008000 +#ifdef CONFIG_IBM_EMAC4 +#define EMAC_M1_RFS_8K 0x00200000 +#define EMAC_M1_RFS_4K 0x00180000 +#define EMAC_M1_RFS_2K 0x00100000 +#define EMAC_M1_RFS_1K 0x00080000 +#define EMAC_M1_TX_FIFO_16K 0x00050000 /* 0's for 512 byte */ +#define EMAC_M1_TX_FIFO_8K 0x00040000 +#define EMAC_M1_TX_FIFO_4K 0x00030000 +#define EMAC_M1_TX_FIFO_2K 0x00020000 +#define EMAC_M1_TX_FIFO_1K 0x00010000 +#define EMAC_M1_TX_TR 0x00008000 +#define EMAC_M1_TX_MWSW 0x00001000 /* 0 wait for status */ +#define EMAC_M1_JUMBO_ENABLE 0x00000800 /* Upt to 9Kr status */ +#define EMAC_M1_OPB_CLK_66 0x00000008 /* 66Mhz */ +#define EMAC_M1_OPB_CLK_83 0x00000010 /* 83Mhz */ +#define EMAC_M1_OPB_CLK_100 0x00000018 /* 100Mhz */ +#define EMAC_M1_OPB_CLK_100P 0x00000020 /* 100Mhz+ */ +#else /* CONFIG_IBM_EMAC4 */ +#define EMAC_M1_RFS_4K 0x00300000 /* ~4k for 512 byte */ +#define EMAC_M1_RFS_2K 0x00200000 +#define EMAC_M1_RFS_1K 0x00100000 +#define EMAC_M1_TX_FIFO_2K 0x00080000 /* 0's for 512 byte */ +#define EMAC_M1_TX_FIFO_1K 0x00040000 +#define EMAC_M1_TR0_DEPEND 0x00010000 /* 0'x for single packet */ +#define EMAC_M1_TR1_DEPEND 0x00004000 +#define EMAC_M1_TR1_MULTI 0x00002000 +#define EMAC_M1_JUMBO_ENABLE 0x00001000 +#endif /* CONFIG_IBM_EMAC4 */ +#define EMAC_M1_BASE (EMAC_M1_TX_FIFO_2K | \ + EMAC_M1_APP | \ + EMAC_M1_TR | EMAC_M1_VLE) -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_MR1_RFS_4K 0x00300000 -#define EMAC_MR1_RFS_16K 0x00000000 -#define EMAC_RX_FIFO_SIZE(gige) 4096 -#define EMAC_MR1_TFS_2K 0x00080000 -#define EMAC_MR1_TR0_MULT 0x00008000 -#define EMAC_MR1_JPSM 0x00000000 -#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT) -#else -#define EMAC_MR1_RFS_4K 0x00180000 -#define EMAC_MR1_RFS_16K 0x00280000 -#define EMAC_RX_FIFO_SIZE(gige) ((gige) ? 16384 : 4096) -#define EMAC_MR1_TFS_2K 0x00020000 -#define EMAC_MR1_TR 0x00008000 -#define EMAC_MR1_MWSW_001 0x00001000 -#define EMAC_MR1_JPSM 0x00000800 -#define EMAC_MR1_OBCI_MASK 0x00000038 -#define EMAC_MR1_OBCI_50 0x00000000 -#define EMAC_MR1_OBCI_66 0x00000008 -#define EMAC_MR1_OBCI_83 0x00000010 -#define EMAC_MR1_OBCI_100 0x00000018 -#define EMAC_MR1_OBCI_100P 0x00000020 -#define EMAC_MR1_OBCI(freq) ((freq) <= 50 ? EMAC_MR1_OBCI_50 : \ - (freq) <= 66 ? EMAC_MR1_OBCI_66 : \ - (freq) <= 83 ? EMAC_MR1_OBCI_83 : \ - (freq) <= 100 ? EMAC_MR1_OBCI_100 : EMAC_MR1_OBCI_100P) -#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR | \ - EMAC_MR1_MWSW_001 | EMAC_MR1_OBCI(opb)) -#endif - -/* EMACx_TMR0 */ -#define EMAC_TMR0_GNP 0x80000000 -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_TMR0_DEFAULT 0x00000000 -#else +/* Transmit Mode Register 0 */ +#define EMAC_TMR0_GNP0 0x80000000 +#define EMAC_TMR0_GNP1 0x40000000 +#define EMAC_TMR0_GNPD 0x20000000 +#define EMAC_TMR0_FC 0x10000000 #define EMAC_TMR0_TFAE_2_32 0x00000001 #define EMAC_TMR0_TFAE_4_64 0x00000002 #define EMAC_TMR0_TFAE_8_128 0x00000003 @@ -144,36 +112,14 @@ struct emac_regs { #define EMAC_TMR0_TFAE_32_512 0x00000005 #define EMAC_TMR0_TFAE_64_1024 0x00000006 #define EMAC_TMR0_TFAE_128_2048 0x00000007 -#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_2_32 -#endif -#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP | EMAC_TMR0_DEFAULT) - -/* EMACx_TMR1 */ - -/* IBM manuals are not very clear here. - * This is my interpretation of how things are. --ebs - */ -#if defined(CONFIG_40x) -#define EMAC_FIFO_ENTRY_SIZE 8 -#define EMAC_MAL_BURST_SIZE (16 * 4) -#else -#define EMAC_FIFO_ENTRY_SIZE 16 -#define EMAC_MAL_BURST_SIZE (64 * 4) -#endif - -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_TMR1(l,h) (((l) << 27) | (((h) & 0xff) << 16)) -#else -#define EMAC_TMR1(l,h) (((l) << 27) | (((h) & 0x3ff) << 14)) -#endif -/* EMACx_RMR */ +/* Receive Mode Register */ #define EMAC_RMR_SP 0x80000000 #define EMAC_RMR_SFCS 0x40000000 -#define EMAC_RMR_RRP 0x20000000 -#define EMAC_RMR_RFP 0x10000000 -#define EMAC_RMR_ROP 0x08000000 -#define EMAC_RMR_RPIR 0x04000000 +#define EMAC_RMR_ARRP 0x20000000 +#define EMAC_RMR_ARP 0x10000000 +#define EMAC_RMR_AROP 0x08000000 +#define EMAC_RMR_ARPI 0x04000000 #define EMAC_RMR_PPP 0x02000000 #define EMAC_RMR_PME 0x01000000 #define EMAC_RMR_PMME 0x00800000 @@ -181,9 +127,6 @@ struct emac_regs { #define EMAC_RMR_MIAE 0x00200000 #define EMAC_RMR_BAE 0x00100000 #define EMAC_RMR_MAE 0x00080000 -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_RMR_BASE 0x00000000 -#else #define EMAC_RMR_RFAF_2_32 0x00000001 #define EMAC_RMR_RFAF_4_64 0x00000002 #define EMAC_RMR_RFAF_8_128 0x00000003 @@ -191,21 +134,9 @@ struct emac_regs { #define EMAC_RMR_RFAF_32_512 0x00000005 #define EMAC_RMR_RFAF_64_1024 0x00000006 #define EMAC_RMR_RFAF_128_2048 0x00000007 -#define EMAC_RMR_BASE EMAC_RMR_RFAF_128_2048 -#endif +#define EMAC_RMR_BASE (EMAC_RMR_IAE | EMAC_RMR_BAE) -/* EMACx_ISR & EMACx_ISER */ -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_ISR_TXPE 0x00000000 -#define EMAC_ISR_RXPE 0x00000000 -#define EMAC_ISR_TXUE 0x00000000 -#define EMAC_ISR_RXOE 0x00000000 -#else -#define EMAC_ISR_TXPE 0x20000000 -#define EMAC_ISR_RXPE 0x10000000 -#define EMAC_ISR_TXUE 0x08000000 -#define EMAC_ISR_RXOE 0x04000000 -#endif +/* Interrupt Status & enable Regs */ #define EMAC_ISR_OVR 0x02000000 #define EMAC_ISR_PP 0x01000000 #define EMAC_ISR_BP 0x00800000 @@ -216,62 +147,53 @@ struct emac_regs { #define EMAC_ISR_PTLE 0x00040000 #define EMAC_ISR_ORE 0x00020000 #define EMAC_ISR_IRE 0x00010000 -#define EMAC_ISR_SQE 0x00000080 -#define EMAC_ISR_TE 0x00000040 +#define EMAC_ISR_DBDM 0x00000200 +#define EMAC_ISR_DB0 0x00000100 +#define EMAC_ISR_SE0 0x00000080 +#define EMAC_ISR_TE0 0x00000040 +#define EMAC_ISR_DB1 0x00000020 +#define EMAC_ISR_SE1 0x00000010 +#define EMAC_ISR_TE1 0x00000008 #define EMAC_ISR_MOS 0x00000002 #define EMAC_ISR_MOF 0x00000001 -/* EMACx_STACR */ -#define EMAC_STACR_PHYD_MASK 0xffff -#define EMAC_STACR_PHYD_SHIFT 16 +/* STA CONTROL REG */ #define EMAC_STACR_OC 0x00008000 #define EMAC_STACR_PHYE 0x00004000 -#define EMAC_STACR_STAC_MASK 0x00003000 -#define EMAC_STACR_STAC_READ 0x00001000 -#define EMAC_STACR_STAC_WRITE 0x00002000 -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_STACR_OPBC_MASK 0x00000C00 -#define EMAC_STACR_OPBC_50 0x00000000 -#define EMAC_STACR_OPBC_66 0x00000400 -#define EMAC_STACR_OPBC_83 0x00000800 -#define EMAC_STACR_OPBC_100 0x00000C00 -#define EMAC_STACR_OPBC(freq) ((freq) <= 50 ? EMAC_STACR_OPBC_50 : \ - (freq) <= 66 ? EMAC_STACR_OPBC_66 : \ - (freq) <= 83 ? EMAC_STACR_OPBC_83 : EMAC_STACR_OPBC_100) -#define EMAC_STACR_BASE(opb) EMAC_STACR_OPBC(opb) -#else -#define EMAC_STACR_BASE(opb) 0x00000000 -#endif -#define EMAC_STACR_PCDA_MASK 0x1f -#define EMAC_STACR_PCDA_SHIFT 5 -#define EMAC_STACR_PRA_MASK 0x1f - -/* EMACx_TRTR */ -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_TRTR_SHIFT 27 -#else -#define EMAC_TRTR_SHIFT 24 -#endif -#define EMAC_TRTR(size) ((((size) >> 6) - 1) << EMAC_TRTR_SHIFT) +#define EMAC_STACR_WRITE 0x00002000 +#define EMAC_STACR_READ 0x00001000 +#define EMAC_STACR_CLK_83MHZ 0x00000800 /* 0's for 50Mhz */ +#define EMAC_STACR_CLK_66MHZ 0x00000400 +#define EMAC_STACR_CLK_100MHZ 0x00000C00 -/* EMACx_RWMR */ -#if !defined(CONFIG_IBM_EMAC4) -#define EMAC_RWMR(l,h) (((l) << 23) | ( ((h) & 0x1ff) << 7)) -#else -#define EMAC_RWMR(l,h) (((l) << 22) | ( ((h) & 0x3ff) << 6)) -#endif +/* Transmit Request Threshold Register */ +#define EMAC_TRTR_1600 0x18000000 /* 0's for 64 Bytes */ +#define EMAC_TRTR_1024 0x0f000000 +#define EMAC_TRTR_512 0x07000000 +#define EMAC_TRTR_256 0x03000000 +#define EMAC_TRTR_192 0x10000000 +#define EMAC_TRTR_128 0x01000000 -/* EMAC specific TX descriptor control fields (write access) */ #define EMAC_TX_CTRL_GFCS 0x0200 #define EMAC_TX_CTRL_GP 0x0100 #define EMAC_TX_CTRL_ISA 0x0080 #define EMAC_TX_CTRL_RSA 0x0040 #define EMAC_TX_CTRL_IVT 0x0020 #define EMAC_TX_CTRL_RVT 0x0010 -#define EMAC_TX_CTRL_TAH_CSUM 0x000e +#define EMAC_TX_CTRL_TAH_CSUM 0x000e /* TAH only */ +#define EMAC_TX_CTRL_TAH_SEG4 0x000a /* TAH only */ +#define EMAC_TX_CTRL_TAH_SEG3 0x0008 /* TAH only */ +#define EMAC_TX_CTRL_TAH_SEG2 0x0006 /* TAH only */ +#define EMAC_TX_CTRL_TAH_SEG1 0x0004 /* TAH only */ +#define EMAC_TX_CTRL_TAH_SEG0 0x0002 /* TAH only */ +#define EMAC_TX_CTRL_TAH_DIS 0x0000 /* TAH only */ -/* EMAC specific TX descriptor status fields (read access) */ +#define EMAC_TX_CTRL_DFLT ( \ + MAL_TX_CTRL_INTR | EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP ) + +/* madmal transmit status / Control bits */ #define EMAC_TX_ST_BFCS 0x0200 +#define EMAC_TX_ST_BPP 0x0100 #define EMAC_TX_ST_LCS 0x0080 #define EMAC_TX_ST_ED 0x0040 #define EMAC_TX_ST_EC 0x0020 @@ -280,16 +202,8 @@ struct emac_regs { #define EMAC_TX_ST_SC 0x0004 #define EMAC_TX_ST_UR 0x0002 #define EMAC_TX_ST_SQE 0x0001 -#if !defined(CONFIG_IBM_EMAC_TAH) -#define EMAC_IS_BAD_TX(v) ((v) & (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \ - EMAC_TX_ST_EC | EMAC_TX_ST_LC | \ - EMAC_TX_ST_MC | EMAC_TX_ST_UR)) -#else -#define EMAC_IS_BAD_TX(v) ((v) & (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \ - EMAC_TX_ST_EC | EMAC_TX_ST_LC)) -#endif -/* EMAC specific RX descriptor status fields (read access) */ +/* madmal receive status / Control bits */ #define EMAC_RX_ST_OE 0x0200 #define EMAC_RX_ST_PP 0x0100 #define EMAC_RX_ST_BP 0x0080 @@ -300,10 +214,54 @@ struct emac_regs { #define EMAC_RX_ST_PTL 0x0004 #define EMAC_RX_ST_ORE 0x0002 #define EMAC_RX_ST_IRE 0x0001 -#define EMAC_RX_TAH_BAD_CSUM 0x0003 -#define EMAC_BAD_RX_MASK (EMAC_RX_ST_OE | EMAC_RX_ST_BP | \ - EMAC_RX_ST_RP | EMAC_RX_ST_SE | \ - EMAC_RX_ST_AE | EMAC_RX_ST_BFCS | \ - EMAC_RX_ST_PTL | EMAC_RX_ST_ORE | \ - EMAC_RX_ST_IRE ) -#endif /* __IBM_EMAC_H_ */ +#define EMAC_BAD_RX_PACKET 0x02ff +#define EMAC_CSUM_VER_ERROR 0x0003 + +/* identify a bad rx packet dependent on emac features */ +#ifdef CONFIG_IBM_EMAC4 +#define EMAC_IS_BAD_RX_PACKET(desc) \ + (((desc & (EMAC_BAD_RX_PACKET & ~EMAC_CSUM_VER_ERROR)) || \ + ((desc & EMAC_CSUM_VER_ERROR) == EMAC_RX_ST_ORE) || \ + ((desc & EMAC_CSUM_VER_ERROR) == EMAC_RX_ST_IRE))) +#else +#define EMAC_IS_BAD_RX_PACKET(desc) \ + (desc & EMAC_BAD_RX_PACKET) +#endif + +/* SoC implementation specific EMAC register defaults */ +#if defined(CONFIG_440GP) +#define EMAC_RWMR_DEFAULT 0x80009000 +#define EMAC_TMR0_DEFAULT 0x00000000 +#define EMAC_TMR1_DEFAULT 0xf8640000 +#elif defined(CONFIG_440GX) +#define EMAC_RWMR_DEFAULT 0x1000a200 +#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_2_32 +#define EMAC_TMR1_DEFAULT 0xa00f0000 +#elif defined(CONFIG_440SP) +#define EMAC_RWMR_DEFAULT 0x08002000 +#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_128_2048 +#define EMAC_TMR1_DEFAULT 0xf8200000 +#else +#define EMAC_RWMR_DEFAULT 0x0f002000 +#define EMAC_TMR0_DEFAULT 0x00000000 +#define EMAC_TMR1_DEFAULT 0x380f0000 +#endif /* CONFIG_440GP */ + +/* Revision specific EMAC register defaults */ +#ifdef CONFIG_IBM_EMAC4 +#define EMAC_M1_DEFAULT (EMAC_M1_BASE | \ + EMAC_M1_OPB_CLK_83 | \ + EMAC_M1_TX_MWSW) +#define EMAC_RMR_DEFAULT (EMAC_RMR_BASE | \ + EMAC_RMR_RFAF_128_2048) +#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP0 | \ + EMAC_TMR0_DEFAULT) +#define EMAC_TRTR_DEFAULT EMAC_TRTR_1024 +#else /* !CONFIG_IBM_EMAC4 */ +#define EMAC_M1_DEFAULT EMAC_M1_BASE +#define EMAC_RMR_DEFAULT EMAC_RMR_BASE +#define EMAC_TMR0_XMIT EMAC_TMR0_GNP0 +#define EMAC_TRTR_DEFAULT EMAC_TRTR_1600 +#endif /* CONFIG_IBM_EMAC4 */ + +#endif diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_core.c b/trunk/drivers/net/ibm_emac/ibm_emac_core.c index 943fbd1546ff..14e9b6315f20 100644 --- a/trunk/drivers/net/ibm_emac/ibm_emac_core.c +++ b/trunk/drivers/net/ibm_emac/ibm_emac_core.c @@ -1,14 +1,13 @@ /* - * drivers/net/ibm_emac/ibm_emac_core.c + * ibm_emac_core.c * - * Driver for PowerPC 4xx on-chip ethernet controller. - * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin or + * Ethernet driver for the built in ethernet on the IBM 4xx PowerPC + * processors. + * + * (c) 2003 Benjamin Herrenschmidt * * Based on original work by - * Matt Porter - * (c) 2003 Benjamin Herrenschmidt + * * Armin Kuster * Johnnie Peters * @@ -16,24 +15,29 @@ * 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. - * + * TODO + * - Check for races in the "remove" code path + * - Add some Power Management to the MAC and the PHY + * - Audit remaining of non-rewritten code (--BenH) + * - Cleanup message display using msglevel mecanism + * - Address all errata + * - Audit all register update paths to ensure they + * are being written post soft reset if required. */ - -#include #include #include #include #include +#include +#include #include +#include +#include #include #include #include #include -#include -#include -#include -#include -#include +#include #include #include #include @@ -41,1893 +45,1691 @@ #include #include #include +#include #include #include +#include +#include +#include +#include + #include "ibm_emac_core.h" -#include "ibm_emac_debug.h" -/* - * Lack of dma_unmap_???? calls is intentional. - * - * API-correct usage requires additional support state information to be - * maintained for every RX and TX buffer descriptor (BD). Unfortunately, due to - * EMAC design (e.g. TX buffer passed from network stack can be split into - * several BDs, dma_map_single/dma_map_page can be used to map particular BD), - * maintaining such information will add additional overhead. - * Current DMA API implementation for 4xx processors only ensures cache coherency - * and dma_unmap_???? routines are empty and are likely to stay this way. - * I decided to omit dma_unmap_??? calls because I don't want to add additional - * complexity just for the sake of following some abstract API, when it doesn't - * add any real benefit to the driver. I understand that this decision maybe - * controversial, but I really tried to make code API-correct and efficient - * at the same time and didn't come up with code I liked :(. --ebs - */ +//#define MDIO_DEBUG(fmt) printk fmt +#define MDIO_DEBUG(fmt) + +//#define LINK_DEBUG(fmt) printk fmt +#define LINK_DEBUG(fmt) + +//#define PKT_DEBUG(fmt) printk fmt +#define PKT_DEBUG(fmt) #define DRV_NAME "emac" -#define DRV_VERSION "3.53" -#define DRV_DESC "PPC 4xx OCP EMAC driver" +#define DRV_VERSION "2.0" +#define DRV_AUTHOR "Benjamin Herrenschmidt " +#define DRV_DESC "IBM EMAC Ethernet driver" +/* + * When mdio_idx >= 0, contains a list of emac ocp_devs + * that have had their initialization deferred until the + * common MDIO controller has been initialized. + */ +LIST_HEAD(emac_init_list); + +MODULE_AUTHOR(DRV_AUTHOR); MODULE_DESCRIPTION(DRV_DESC); -MODULE_AUTHOR - ("Eugene Surovegin or "); MODULE_LICENSE("GPL"); -/* minimum number of free TX descriptors required to wake up TX process */ -#define EMAC_TX_WAKEUP_THRESH (NUM_TX_BUFF / 4) +static int skb_res = SKB_RES; +module_param(skb_res, int, 0444); +MODULE_PARM_DESC(skb_res, "Amount of data to reserve on skb buffs\n" + "The 405 handles a misaligned IP header fine but\n" + "this can help if you are routing to a tunnel or a\n" + "device that needs aligned data. 0..2"); -/* If packet size is less than this number, we allocate small skb and copy packet - * contents into it instead of just sending original big skb up - */ -#define EMAC_RX_COPY_THRESH CONFIG_IBM_EMAC_RX_COPY_THRESHOLD +#define RGMII_PRIV(ocpdev) ((struct ibm_ocp_rgmii*)ocp_get_drvdata(ocpdev)) -/* Since multiple EMACs share MDIO lines in various ways, we need - * to avoid re-using the same PHY ID in cases where the arch didn't - * setup precise phy_map entries - */ -static u32 busy_phy_map; +static unsigned int rgmii_enable[] = { + RGMII_RTBI, + RGMII_RGMII, + RGMII_TBI, + RGMII_GMII +}; -#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) && (defined(CONFIG_405EP) || defined(CONFIG_440EP)) -/* 405EP has "EMAC to PHY Control Register" (CPC0_EPCTL) which can help us - * with PHY RX clock problem. - * 440EP has more sane SDR0_MFR register implementation than 440GX, which - * also allows controlling each EMAC clock - */ -static inline void EMAC_RX_CLK_TX(int idx) -{ - unsigned long flags; - local_irq_save(flags); +static unsigned int rgmii_speed_mask[] = { + RGMII_MII2_SPDMASK, + RGMII_MII3_SPDMASK +}; -#if defined(CONFIG_405EP) - mtdcr(0xf3, mfdcr(0xf3) | (1 << idx)); -#else /* CONFIG_440EP */ - SDR_WRITE(DCRN_SDR_MFR, SDR_READ(DCRN_SDR_MFR) | (0x08000000 >> idx)); -#endif +static unsigned int rgmii_speed100[] = { + RGMII_MII2_100MB, + RGMII_MII3_100MB +}; - local_irq_restore(flags); -} +static unsigned int rgmii_speed1000[] = { + RGMII_MII2_1000MB, + RGMII_MII3_1000MB +}; -static inline void EMAC_RX_CLK_DEFAULT(int idx) -{ - unsigned long flags; - local_irq_save(flags); +#define ZMII_PRIV(ocpdev) ((struct ibm_ocp_zmii*)ocp_get_drvdata(ocpdev)) -#if defined(CONFIG_405EP) - mtdcr(0xf3, mfdcr(0xf3) & ~(1 << idx)); -#else /* CONFIG_440EP */ - SDR_WRITE(DCRN_SDR_MFR, SDR_READ(DCRN_SDR_MFR) & ~(0x08000000 >> idx)); -#endif +static unsigned int zmii_enable[][4] = { + {ZMII_SMII0, ZMII_RMII0, ZMII_MII0, + ~(ZMII_MDI1 | ZMII_MDI2 | ZMII_MDI3)}, + {ZMII_SMII1, ZMII_RMII1, ZMII_MII1, + ~(ZMII_MDI0 | ZMII_MDI2 | ZMII_MDI3)}, + {ZMII_SMII2, ZMII_RMII2, ZMII_MII2, + ~(ZMII_MDI0 | ZMII_MDI1 | ZMII_MDI3)}, + {ZMII_SMII3, ZMII_RMII3, ZMII_MII3, ~(ZMII_MDI0 | ZMII_MDI1 | ZMII_MDI2)} +}; - local_irq_restore(flags); -} -#else -#define EMAC_RX_CLK_TX(idx) ((void)0) -#define EMAC_RX_CLK_DEFAULT(idx) ((void)0) -#endif +static unsigned int mdi_enable[] = { + ZMII_MDI0, + ZMII_MDI1, + ZMII_MDI2, + ZMII_MDI3 +}; -#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) && defined(CONFIG_440GX) -/* We can switch Ethernet clock to the internal source through SDR0_MFR[ECS], - * unfortunately this is less flexible than 440EP case, because it's a global - * setting for all EMACs, therefore we do this clock trick only during probe. - */ -#define EMAC_CLK_INTERNAL SDR_WRITE(DCRN_SDR_MFR, \ - SDR_READ(DCRN_SDR_MFR) | 0x08000000) -#define EMAC_CLK_EXTERNAL SDR_WRITE(DCRN_SDR_MFR, \ - SDR_READ(DCRN_SDR_MFR) & ~0x08000000) -#else -#define EMAC_CLK_INTERNAL ((void)0) -#define EMAC_CLK_EXTERNAL ((void)0) -#endif +static unsigned int zmii_speed = 0x0; +static unsigned int zmii_speed100[] = { + ZMII_MII0_100MB, + ZMII_MII1_100MB, + ZMII_MII2_100MB, + ZMII_MII3_100MB +}; -/* I don't want to litter system log with timeout errors - * when we have brain-damaged PHY. +/* Since multiple EMACs share MDIO lines in various ways, we need + * to avoid re-using the same PHY ID in cases where the arch didn't + * setup precise phy_map entries */ -static inline void emac_report_timeout_error(struct ocp_enet_private *dev, - const char *error) -{ -#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) - DBG("%d: %s" NL, dev->def->index, error); -#else - if (net_ratelimit()) - printk(KERN_ERR "emac%d: %s\n", dev->def->index, error); -#endif -} - -/* PHY polling intervals */ -#define PHY_POLL_LINK_ON HZ -#define PHY_POLL_LINK_OFF (HZ / 5) - -/* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */ -static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = { - "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum", - "tx_packets_csum", "tx_undo", "rx_dropped_stack", "rx_dropped_oom", - "rx_dropped_error", "rx_dropped_resize", "rx_dropped_mtu", - "rx_stopped", "rx_bd_errors", "rx_bd_overrun", "rx_bd_bad_packet", - "rx_bd_runt_packet", "rx_bd_short_event", "rx_bd_alignment_error", - "rx_bd_bad_fcs", "rx_bd_packet_too_long", "rx_bd_out_of_range", - "rx_bd_in_range", "rx_parity", "rx_fifo_overrun", "rx_overrun", - "rx_bad_packet", "rx_runt_packet", "rx_short_event", - "rx_alignment_error", "rx_bad_fcs", "rx_packet_too_long", - "rx_out_of_range", "rx_in_range", "tx_dropped", "tx_bd_errors", - "tx_bd_bad_fcs", "tx_bd_carrier_loss", "tx_bd_excessive_deferral", - "tx_bd_excessive_collisions", "tx_bd_late_collision", - "tx_bd_multple_collisions", "tx_bd_single_collision", - "tx_bd_underrun", "tx_bd_sqe", "tx_parity", "tx_underrun", "tx_sqe", - "tx_errors" -}; +static u32 busy_phy_map = 0; -static irqreturn_t emac_irq(int irq, void *dev_instance, struct pt_regs *regs); -static void emac_clean_tx_ring(struct ocp_enet_private *dev); +/* If EMACs share a common MDIO device, this points to it */ +static struct net_device *mdio_ndev = NULL; -static inline int emac_phy_supports_gige(int phy_mode) -{ - return phy_mode == PHY_MODE_GMII || - phy_mode == PHY_MODE_RGMII || - phy_mode == PHY_MODE_TBI || - phy_mode == PHY_MODE_RTBI; -} +struct emac_def_dev { + struct list_head link; + struct ocp_device *ocpdev; + struct ibm_ocp_mal *mal; +}; -static inline int emac_phy_gpcs(int phy_mode) +static struct net_device_stats *emac_stats(struct net_device *dev) { - return phy_mode == PHY_MODE_TBI || - phy_mode == PHY_MODE_RTBI; -} + struct ocp_enet_private *fep = dev->priv; + return &fep->stats; +}; -static inline void emac_tx_enable(struct ocp_enet_private *dev) +static int +emac_init_rgmii(struct ocp_device *rgmii_dev, int input, int phy_mode) { - struct emac_regs *p = dev->emacp; - unsigned long flags; - u32 r; - - local_irq_save(flags); + struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(rgmii_dev); + const char *mode_name[] = { "RTBI", "RGMII", "TBI", "GMII" }; + int mode = -1; - DBG("%d: tx_enable" NL, dev->def->index); + if (!rgmii) { + rgmii = kmalloc(sizeof(struct ibm_ocp_rgmii), GFP_KERNEL); - r = in_be32(&p->mr0); - if (!(r & EMAC_MR0_TXE)) - out_be32(&p->mr0, r | EMAC_MR0_TXE); - local_irq_restore(flags); -} + if (rgmii == NULL) { + printk(KERN_ERR + "rgmii%d: Out of memory allocating RGMII structure!\n", + rgmii_dev->def->index); + return -ENOMEM; + } -static void emac_tx_disable(struct ocp_enet_private *dev) -{ - struct emac_regs *p = dev->emacp; - unsigned long flags; - u32 r; + memset(rgmii, 0, sizeof(*rgmii)); - local_irq_save(flags); + rgmii->base = + (struct rgmii_regs *)ioremap(rgmii_dev->def->paddr, + sizeof(*rgmii->base)); + if (rgmii->base == NULL) { + printk(KERN_ERR + "rgmii%d: Cannot ioremap bridge registers!\n", + rgmii_dev->def->index); - DBG("%d: tx_disable" NL, dev->def->index); + kfree(rgmii); + return -ENOMEM; + } + ocp_set_drvdata(rgmii_dev, rgmii); + } - r = in_be32(&p->mr0); - if (r & EMAC_MR0_TXE) { - int n = 300; - out_be32(&p->mr0, r & ~EMAC_MR0_TXE); - while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) - --n; - if (unlikely(!n)) - emac_report_timeout_error(dev, "TX disable timeout"); + if (phy_mode) { + switch (phy_mode) { + case PHY_MODE_GMII: + mode = GMII; + break; + case PHY_MODE_TBI: + mode = TBI; + break; + case PHY_MODE_RTBI: + mode = RTBI; + break; + case PHY_MODE_RGMII: + default: + mode = RGMII; + } + rgmii->base->fer &= ~RGMII_FER_MASK(input); + rgmii->base->fer |= rgmii_enable[mode] << (4 * input); + } else { + switch ((rgmii->base->fer & RGMII_FER_MASK(input)) >> (4 * + input)) { + case RGMII_RTBI: + mode = RTBI; + break; + case RGMII_RGMII: + mode = RGMII; + break; + case RGMII_TBI: + mode = TBI; + break; + case RGMII_GMII: + mode = GMII; + } } - local_irq_restore(flags); -} -static void emac_rx_enable(struct ocp_enet_private *dev) -{ - struct emac_regs *p = dev->emacp; - unsigned long flags; - u32 r; + /* Set mode to RGMII if nothing valid is detected */ + if (mode < 0) + mode = RGMII; - local_irq_save(flags); - if (unlikely(dev->commac.rx_stopped)) - goto out; + printk(KERN_NOTICE "rgmii%d: input %d in %s mode\n", + rgmii_dev->def->index, input, mode_name[mode]); - DBG("%d: rx_enable" NL, dev->def->index); - - r = in_be32(&p->mr0); - if (!(r & EMAC_MR0_RXE)) { - if (unlikely(!(r & EMAC_MR0_RXI))) { - /* Wait if previous async disable is still in progress */ - int n = 100; - while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) - --n; - if (unlikely(!n)) - emac_report_timeout_error(dev, - "RX disable timeout"); - } - out_be32(&p->mr0, r | EMAC_MR0_RXE); - } - out: - local_irq_restore(flags); + rgmii->mode[input] = mode; + rgmii->users++; + + return 0; } -static void emac_rx_disable(struct ocp_enet_private *dev) +static void +emac_rgmii_port_speed(struct ocp_device *ocpdev, int input, int speed) { - struct emac_regs *p = dev->emacp; - unsigned long flags; - u32 r; + struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(ocpdev); + unsigned int rgmii_speed; - local_irq_save(flags); + rgmii_speed = in_be32(&rgmii->base->ssr); - DBG("%d: rx_disable" NL, dev->def->index); + rgmii_speed &= ~rgmii_speed_mask[input]; - r = in_be32(&p->mr0); - if (r & EMAC_MR0_RXE) { - int n = 300; - out_be32(&p->mr0, r & ~EMAC_MR0_RXE); - while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) - --n; - if (unlikely(!n)) - emac_report_timeout_error(dev, "RX disable timeout"); - } - local_irq_restore(flags); + if (speed == 1000) + rgmii_speed |= rgmii_speed1000[input]; + else if (speed == 100) + rgmii_speed |= rgmii_speed100[input]; + + out_be32(&rgmii->base->ssr, rgmii_speed); } -static inline void emac_rx_disable_async(struct ocp_enet_private *dev) +static void emac_close_rgmii(struct ocp_device *ocpdev) { - struct emac_regs *p = dev->emacp; - unsigned long flags; - u32 r; - - local_irq_save(flags); - - DBG("%d: rx_disable_async" NL, dev->def->index); + struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(ocpdev); + BUG_ON(!rgmii || rgmii->users == 0); - r = in_be32(&p->mr0); - if (r & EMAC_MR0_RXE) - out_be32(&p->mr0, r & ~EMAC_MR0_RXE); - local_irq_restore(flags); + if (!--rgmii->users) { + ocp_set_drvdata(ocpdev, NULL); + iounmap((void *)rgmii->base); + kfree(rgmii); + } } -static int emac_reset(struct ocp_enet_private *dev) +static int emac_init_zmii(struct ocp_device *zmii_dev, int input, int phy_mode) { - struct emac_regs *p = dev->emacp; - unsigned long flags; - int n = 20; + struct ibm_ocp_zmii *zmii = ZMII_PRIV(zmii_dev); + const char *mode_name[] = { "SMII", "RMII", "MII" }; + int mode = -1; - DBG("%d: reset" NL, dev->def->index); + if (!zmii) { + zmii = kmalloc(sizeof(struct ibm_ocp_zmii), GFP_KERNEL); + if (zmii == NULL) { + printk(KERN_ERR + "zmii%d: Out of memory allocating ZMII structure!\n", + zmii_dev->def->index); + return -ENOMEM; + } + memset(zmii, 0, sizeof(*zmii)); - local_irq_save(flags); + zmii->base = + (struct zmii_regs *)ioremap(zmii_dev->def->paddr, + sizeof(*zmii->base)); + if (zmii->base == NULL) { + printk(KERN_ERR + "zmii%d: Cannot ioremap bridge registers!\n", + zmii_dev->def->index); - if (!dev->reset_failed) { - /* 40x erratum suggests stopping RX channel before reset, - * we stop TX as well - */ - emac_rx_disable(dev); - emac_tx_disable(dev); + kfree(zmii); + return -ENOMEM; + } + ocp_set_drvdata(zmii_dev, zmii); } - out_be32(&p->mr0, EMAC_MR0_SRST); - while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n) - --n; - local_irq_restore(flags); - - if (n) { - dev->reset_failed = 0; - return 0; + if (phy_mode) { + switch (phy_mode) { + case PHY_MODE_MII: + mode = MII; + break; + case PHY_MODE_RMII: + mode = RMII; + break; + case PHY_MODE_SMII: + default: + mode = SMII; + } + zmii->base->fer &= ~ZMII_FER_MASK(input); + zmii->base->fer |= zmii_enable[input][mode]; } else { - emac_report_timeout_error(dev, "reset timeout"); - dev->reset_failed = 1; - return -ETIMEDOUT; + switch ((zmii->base->fer & ZMII_FER_MASK(input)) << (4 * input)) { + case ZMII_MII0: + mode = MII; + break; + case ZMII_RMII0: + mode = RMII; + break; + case ZMII_SMII0: + mode = SMII; + } } -} -static void emac_hash_mc(struct ocp_enet_private *dev) -{ - struct emac_regs *p = dev->emacp; - u16 gaht[4] = { 0 }; - struct dev_mc_list *dmi; + /* Set mode to SMII if nothing valid is detected */ + if (mode < 0) + mode = SMII; - DBG("%d: hash_mc %d" NL, dev->def->index, dev->ndev->mc_count); + printk(KERN_NOTICE "zmii%d: input %d in %s mode\n", + zmii_dev->def->index, input, mode_name[mode]); - for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) { - int bit; - DBG2("%d: mc %02x:%02x:%02x:%02x:%02x:%02x" NL, - dev->def->index, - dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], - dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); + zmii->mode[input] = mode; + zmii->users++; - bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26); - gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f); - } - out_be32(&p->gaht1, gaht[0]); - out_be32(&p->gaht2, gaht[1]); - out_be32(&p->gaht3, gaht[2]); - out_be32(&p->gaht4, gaht[3]); + return 0; } -static inline u32 emac_iff2rmr(struct net_device *ndev) +static void emac_enable_zmii_port(struct ocp_device *ocpdev, int input) { - u32 r = EMAC_RMR_SP | EMAC_RMR_SFCS | EMAC_RMR_IAE | EMAC_RMR_BAE | - EMAC_RMR_BASE; - - if (ndev->flags & IFF_PROMISC) - r |= EMAC_RMR_PME; - else if (ndev->flags & IFF_ALLMULTI || ndev->mc_count > 32) - r |= EMAC_RMR_PMME; - else if (ndev->mc_count > 0) - r |= EMAC_RMR_MAE; + u32 mask; + struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev); - return r; + mask = in_be32(&zmii->base->fer); + mask &= zmii_enable[input][MDI]; /* turn all non enabled MDI's off */ + mask |= zmii_enable[input][zmii->mode[input]] | mdi_enable[input]; + out_be32(&zmii->base->fer, mask); } -static inline int emac_opb_mhz(void) +static void +emac_zmii_port_speed(struct ocp_device *ocpdev, int input, int speed) { - return (ocp_sys_info.opb_bus_freq + 500000) / 1000000; -} - -/* BHs disabled */ -static int emac_configure(struct ocp_enet_private *dev) -{ - struct emac_regs *p = dev->emacp; - struct net_device *ndev = dev->ndev; - int gige; - u32 r; - - DBG("%d: configure" NL, dev->def->index); - - if (emac_reset(dev) < 0) - return -ETIMEDOUT; + struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev); - tah_reset(dev->tah_dev); - - /* Mode register */ - r = EMAC_MR1_BASE(emac_opb_mhz()) | EMAC_MR1_VLE | EMAC_MR1_IST; - if (dev->phy.duplex == DUPLEX_FULL) - r |= EMAC_MR1_FDE; - switch (dev->phy.speed) { - case SPEED_1000: - if (emac_phy_gpcs(dev->phy.mode)) { - r |= EMAC_MR1_MF_1000GPCS | - EMAC_MR1_MF_IPPA(dev->phy.address); - - /* Put some arbitrary OUI, Manuf & Rev IDs so we can - * identify this GPCS PHY later. - */ - out_be32(&p->ipcr, 0xdeadbeef); - } else - r |= EMAC_MR1_MF_1000; - r |= EMAC_MR1_RFS_16K; - gige = 1; - - if (dev->ndev->mtu > ETH_DATA_LEN) - r |= EMAC_MR1_JPSM; - break; - case SPEED_100: - r |= EMAC_MR1_MF_100; - /* Fall through */ - default: - r |= EMAC_MR1_RFS_4K; - gige = 0; - break; - } - - if (dev->rgmii_dev) - rgmii_set_speed(dev->rgmii_dev, dev->rgmii_input, - dev->phy.speed); + if (speed == 100) + zmii_speed |= zmii_speed100[input]; else - zmii_set_speed(dev->zmii_dev, dev->zmii_input, dev->phy.speed); + zmii_speed &= ~zmii_speed100[input]; -#if !defined(CONFIG_40x) - /* on 40x erratum forces us to NOT use integrated flow control, - * let's hope it works on 44x ;) - */ - if (dev->phy.duplex == DUPLEX_FULL) { - if (dev->phy.pause) - r |= EMAC_MR1_EIFC | EMAC_MR1_APP; - else if (dev->phy.asym_pause) - r |= EMAC_MR1_APP; - } -#endif - out_be32(&p->mr1, r); - - /* Set individual MAC address */ - out_be32(&p->iahr, (ndev->dev_addr[0] << 8) | ndev->dev_addr[1]); - out_be32(&p->ialr, (ndev->dev_addr[2] << 24) | - (ndev->dev_addr[3] << 16) | (ndev->dev_addr[4] << 8) | - ndev->dev_addr[5]); - - /* VLAN Tag Protocol ID */ - out_be32(&p->vtpid, 0x8100); - - /* Receive mode register */ - r = emac_iff2rmr(ndev); - if (r & EMAC_RMR_MAE) - emac_hash_mc(dev); - out_be32(&p->rmr, r); - - /* FIFOs thresholds */ - r = EMAC_TMR1((EMAC_MAL_BURST_SIZE / EMAC_FIFO_ENTRY_SIZE) + 1, - EMAC_TX_FIFO_SIZE / 2 / EMAC_FIFO_ENTRY_SIZE); - out_be32(&p->tmr1, r); - out_be32(&p->trtr, EMAC_TRTR(EMAC_TX_FIFO_SIZE / 2)); - - /* PAUSE frame is sent when RX FIFO reaches its high-water mark, - there should be still enough space in FIFO to allow the our link - partner time to process this frame and also time to send PAUSE - frame itself. - - Here is the worst case scenario for the RX FIFO "headroom" - (from "The Switch Book") (100Mbps, without preamble, inter-frame gap): - - 1) One maximum-length frame on TX 1522 bytes - 2) One PAUSE frame time 64 bytes - 3) PAUSE frame decode time allowance 64 bytes - 4) One maximum-length frame on RX 1522 bytes - 5) Round-trip propagation delay of the link (100Mb) 15 bytes - ---------- - 3187 bytes - - I chose to set high-water mark to RX_FIFO_SIZE / 4 (1024 bytes) - low-water mark to RX_FIFO_SIZE / 8 (512 bytes) - */ - r = EMAC_RWMR(EMAC_RX_FIFO_SIZE(gige) / 8 / EMAC_FIFO_ENTRY_SIZE, - EMAC_RX_FIFO_SIZE(gige) / 4 / EMAC_FIFO_ENTRY_SIZE); - out_be32(&p->rwmr, r); - - /* Set PAUSE timer to the maximum */ - out_be32(&p->ptr, 0xffff); - - /* IRQ sources */ - out_be32(&p->iser, EMAC_ISR_TXPE | EMAC_ISR_RXPE | /* EMAC_ISR_TXUE | - EMAC_ISR_RXOE | */ EMAC_ISR_OVR | EMAC_ISR_BP | EMAC_ISR_SE | - EMAC_ISR_ALE | EMAC_ISR_BFCS | EMAC_ISR_PTLE | EMAC_ISR_ORE | - EMAC_ISR_IRE | EMAC_ISR_TE); - - /* We need to take GPCS PHY out of isolate mode after EMAC reset */ - if (emac_phy_gpcs(dev->phy.mode)) - mii_reset_phy(&dev->phy); - - return 0; + out_be32(&zmii->base->ssr, zmii_speed); } -/* BHs disabled */ -static void emac_reinitialize(struct ocp_enet_private *dev) +static void emac_close_zmii(struct ocp_device *ocpdev) { - DBG("%d: reinitialize" NL, dev->def->index); + struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev); + BUG_ON(!zmii || zmii->users == 0); - if (!emac_configure(dev)) { - emac_tx_enable(dev); - emac_rx_enable(dev); + if (!--zmii->users) { + ocp_set_drvdata(ocpdev, NULL); + iounmap((void *)zmii->base); + kfree(zmii); } } -/* BHs disabled */ -static void emac_full_tx_reset(struct net_device *ndev) +int emac_phy_read(struct net_device *dev, int mii_id, int reg) { - struct ocp_enet_private *dev = ndev->priv; - struct ocp_func_emac_data *emacdata = dev->def->additions; + int count; + uint32_t stacr; + struct ocp_enet_private *fep = dev->priv; + emac_t *emacp = fep->emacp; - DBG("%d: full_tx_reset" NL, dev->def->index); + MDIO_DEBUG(("%s: phy_read, id: 0x%x, reg: 0x%x\n", dev->name, mii_id, + reg)); - emac_tx_disable(dev); - mal_disable_tx_channel(dev->mal, emacdata->mal_tx_chan); - emac_clean_tx_ring(dev); - dev->tx_cnt = dev->tx_slot = dev->ack_slot = 0; + /* Enable proper ZMII port */ + if (fep->zmii_dev) + emac_enable_zmii_port(fep->zmii_dev, fep->zmii_input); - emac_configure(dev); - - mal_enable_tx_channel(dev->mal, emacdata->mal_tx_chan); - emac_tx_enable(dev); - emac_rx_enable(dev); + /* Use the EMAC that has the MDIO port */ + if (fep->mdio_dev) { + dev = fep->mdio_dev; + fep = dev->priv; + emacp = fep->emacp; + } - netif_wake_queue(ndev); -} + count = 0; + while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) + && (count++ < MDIO_DELAY)) + udelay(1); + MDIO_DEBUG((" (count was %d)\n", count)); -static int __emac_mdio_read(struct ocp_enet_private *dev, u8 id, u8 reg) -{ - struct emac_regs *p = dev->emacp; - u32 r; - int n; + if ((stacr & EMAC_STACR_OC) == 0) { + printk(KERN_WARNING "%s: PHY read timeout #1!\n", dev->name); + return -1; + } - DBG2("%d: mdio_read(%02x,%02x)" NL, dev->def->index, id, reg); + /* Clear the speed bits and make a read request to the PHY */ + stacr = ((EMAC_STACR_READ | (reg & 0x1f)) & ~EMAC_STACR_CLK_100MHZ); + stacr |= ((mii_id & 0x1F) << 5); - /* Enable proper MDIO port */ - zmii_enable_mdio(dev->zmii_dev, dev->zmii_input); + out_be32(&emacp->em0stacr, stacr); - /* Wait for management interface to become idle */ - n = 10; - while (!(in_be32(&p->stacr) & EMAC_STACR_OC)) { + count = 0; + while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) + && (count++ < MDIO_DELAY)) udelay(1); - if (!--n) - goto to; - } - - /* Issue read command */ - out_be32(&p->stacr, - EMAC_STACR_BASE(emac_opb_mhz()) | EMAC_STACR_STAC_READ | - (reg & EMAC_STACR_PRA_MASK) - | ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT)); + MDIO_DEBUG((" (count was %d)\n", count)); - /* Wait for read to complete */ - n = 100; - while (!((r = in_be32(&p->stacr)) & EMAC_STACR_OC)) { - udelay(1); - if (!--n) - goto to; + if ((stacr & EMAC_STACR_OC) == 0) { + printk(KERN_WARNING "%s: PHY read timeout #2!\n", dev->name); + return -1; } - if (unlikely(r & EMAC_STACR_PHYE)) { - DBG("%d: mdio_read(%02x, %02x) failed" NL, dev->def->index, - id, reg); - return -EREMOTEIO; + /* Check for a read error */ + if (stacr & EMAC_STACR_PHYE) { + MDIO_DEBUG(("EMAC MDIO PHY error !\n")); + return -1; } - r = ((r >> EMAC_STACR_PHYD_SHIFT) & EMAC_STACR_PHYD_MASK); - DBG2("%d: mdio_read -> %04x" NL, dev->def->index, r); - return r; - to: - DBG("%d: MII management interface timeout (read)" NL, dev->def->index); - return -ETIMEDOUT; + MDIO_DEBUG((" -> 0x%x\n", stacr >> 16)); + + return (stacr >> 16); } -static void __emac_mdio_write(struct ocp_enet_private *dev, u8 id, u8 reg, - u16 val) +void emac_phy_write(struct net_device *dev, int mii_id, int reg, int data) { - struct emac_regs *p = dev->emacp; - int n; + int count; + uint32_t stacr; + struct ocp_enet_private *fep = dev->priv; + emac_t *emacp = fep->emacp; - DBG2("%d: mdio_write(%02x,%02x,%04x)" NL, dev->def->index, id, reg, - val); + MDIO_DEBUG(("%s phy_write, id: 0x%x, reg: 0x%x, data: 0x%x\n", + dev->name, mii_id, reg, data)); - /* Enable proper MDIO port */ - zmii_enable_mdio(dev->zmii_dev, dev->zmii_input); + /* Enable proper ZMII port */ + if (fep->zmii_dev) + emac_enable_zmii_port(fep->zmii_dev, fep->zmii_input); - /* Wait for management interface to be idle */ - n = 10; - while (!(in_be32(&p->stacr) & EMAC_STACR_OC)) { - udelay(1); - if (!--n) - goto to; + /* Use the EMAC that has the MDIO port */ + if (fep->mdio_dev) { + dev = fep->mdio_dev; + fep = dev->priv; + emacp = fep->emacp; } - /* Issue write command */ - out_be32(&p->stacr, - EMAC_STACR_BASE(emac_opb_mhz()) | EMAC_STACR_STAC_WRITE | - (reg & EMAC_STACR_PRA_MASK) | - ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT) | - (val << EMAC_STACR_PHYD_SHIFT)); - - /* Wait for write to complete */ - n = 100; - while (!(in_be32(&p->stacr) & EMAC_STACR_OC)) { + count = 0; + while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) + && (count++ < MDIO_DELAY)) udelay(1); - if (!--n) - goto to; + MDIO_DEBUG((" (count was %d)\n", count)); + + if ((stacr & EMAC_STACR_OC) == 0) { + printk(KERN_WARNING "%s: PHY write timeout #2!\n", dev->name); + return; } - return; - to: - DBG("%d: MII management interface timeout (write)" NL, dev->def->index); -} -static int emac_mdio_read(struct net_device *ndev, int id, int reg) -{ - struct ocp_enet_private *dev = ndev->priv; - int res; - - local_bh_disable(); - res = __emac_mdio_read(dev->mdio_dev ? dev->mdio_dev : dev, (u8) id, - (u8) reg); - local_bh_enable(); - return res; -} + /* Clear the speed bits and make a read request to the PHY */ -static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val) -{ - struct ocp_enet_private *dev = ndev->priv; + stacr = ((EMAC_STACR_WRITE | (reg & 0x1f)) & ~EMAC_STACR_CLK_100MHZ); + stacr |= ((mii_id & 0x1f) << 5) | ((data & 0xffff) << 16); - local_bh_disable(); - __emac_mdio_write(dev->mdio_dev ? dev->mdio_dev : dev, (u8) id, - (u8) reg, (u16) val); - local_bh_enable(); -} + out_be32(&emacp->em0stacr, stacr); -/* BHs disabled */ -static void emac_set_multicast_list(struct net_device *ndev) -{ - struct ocp_enet_private *dev = ndev->priv; - struct emac_regs *p = dev->emacp; - u32 rmr = emac_iff2rmr(ndev); - - DBG("%d: multicast %08x" NL, dev->def->index, rmr); - BUG_ON(!netif_running(dev->ndev)); - - /* I decided to relax register access rules here to avoid - * full EMAC reset. - * - * There is a real problem with EMAC4 core if we use MWSW_001 bit - * in MR1 register and do a full EMAC reset. - * One TX BD status update is delayed and, after EMAC reset, it - * never happens, resulting in TX hung (it'll be recovered by TX - * timeout handler eventually, but this is just gross). - * So we either have to do full TX reset or try to cheat here :) - * - * The only required change is to RX mode register, so I *think* all - * we need is just to stop RX channel. This seems to work on all - * tested SoCs. --ebs - */ - emac_rx_disable(dev); - if (rmr & EMAC_RMR_MAE) - emac_hash_mc(dev); - out_be32(&p->rmr, rmr); - emac_rx_enable(dev); + count = 0; + while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) + && (count++ < MDIO_DELAY)) + udelay(1); + MDIO_DEBUG((" (count was %d)\n", count)); + + if ((stacr & EMAC_STACR_OC) == 0) + printk(KERN_WARNING "%s: PHY write timeout #2!\n", dev->name); + + /* Check for a write error */ + if ((stacr & EMAC_STACR_PHYE) != 0) { + MDIO_DEBUG(("EMAC MDIO PHY error !\n")); + } } -/* BHs disabled */ -static int emac_resize_rx_ring(struct ocp_enet_private *dev, int new_mtu) +static void emac_txeob_dev(void *param, u32 chanmask) { - struct ocp_func_emac_data *emacdata = dev->def->additions; - int rx_sync_size = emac_rx_sync_size(new_mtu); - int rx_skb_size = emac_rx_skb_size(new_mtu); - int i, ret = 0; - - emac_rx_disable(dev); - mal_disable_rx_channel(dev->mal, emacdata->mal_rx_chan); - - if (dev->rx_sg_skb) { - ++dev->estats.rx_dropped_resize; - dev_kfree_skb(dev->rx_sg_skb); - dev->rx_sg_skb = NULL; - } + struct net_device *dev = param; + struct ocp_enet_private *fep = dev->priv; + unsigned long flags; - /* Make a first pass over RX ring and mark BDs ready, dropping - * non-processed packets on the way. We need this as a separate pass - * to simplify error recovery in the case of allocation failure later. - */ - for (i = 0; i < NUM_RX_BUFF; ++i) { - if (dev->rx_desc[i].ctrl & MAL_RX_CTRL_FIRST) - ++dev->estats.rx_dropped_resize; + spin_lock_irqsave(&fep->lock, flags); - dev->rx_desc[i].data_len = 0; - dev->rx_desc[i].ctrl = MAL_RX_CTRL_EMPTY | - (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); - } + PKT_DEBUG(("emac_txeob_dev() entry, tx_cnt: %d\n", fep->tx_cnt)); - /* Reallocate RX ring only if bigger skb buffers are required */ - if (rx_skb_size <= dev->rx_skb_size) - goto skip; + while (fep->tx_cnt && + !(fep->tx_desc[fep->ack_slot].ctrl & MAL_TX_CTRL_READY)) { - /* Second pass, allocate new skbs */ - for (i = 0; i < NUM_RX_BUFF; ++i) { - struct sk_buff *skb = alloc_skb(rx_skb_size, GFP_ATOMIC); - if (!skb) { - ret = -ENOMEM; - goto oom; + if (fep->tx_desc[fep->ack_slot].ctrl & MAL_TX_CTRL_LAST) { + /* Tell the system the transmit completed. */ + dma_unmap_single(&fep->ocpdev->dev, + fep->tx_desc[fep->ack_slot].data_ptr, + fep->tx_desc[fep->ack_slot].data_len, + DMA_TO_DEVICE); + dev_kfree_skb_irq(fep->tx_skb[fep->ack_slot]); + + if (fep->tx_desc[fep->ack_slot].ctrl & + (EMAC_TX_ST_EC | EMAC_TX_ST_MC | EMAC_TX_ST_SC)) + fep->stats.collisions++; } - BUG_ON(!dev->rx_skb[i]); - dev_kfree_skb(dev->rx_skb[i]); + fep->tx_skb[fep->ack_slot] = (struct sk_buff *)NULL; + if (++fep->ack_slot == NUM_TX_BUFF) + fep->ack_slot = 0; - skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2); - dev->rx_desc[i].data_ptr = - dma_map_single(dev->ldev, skb->data - 2, rx_sync_size, - DMA_FROM_DEVICE) + 2; - dev->rx_skb[i] = skb; - } - skip: - /* Check if we need to change "Jumbo" bit in MR1 */ - if ((new_mtu > ETH_DATA_LEN) ^ (dev->ndev->mtu > ETH_DATA_LEN)) { - /* This is to prevent starting RX channel in emac_rx_enable() */ - dev->commac.rx_stopped = 1; - - dev->ndev->mtu = new_mtu; - emac_full_tx_reset(dev->ndev); + fep->tx_cnt--; } + if (fep->tx_cnt < NUM_TX_BUFF) + netif_wake_queue(dev); - mal_set_rcbs(dev->mal, emacdata->mal_rx_chan, emac_rx_size(new_mtu)); - oom: - /* Restart RX */ - dev->commac.rx_stopped = dev->rx_slot = 0; - mal_enable_rx_channel(dev->mal, emacdata->mal_rx_chan); - emac_rx_enable(dev); + PKT_DEBUG(("emac_txeob_dev() exit, tx_cnt: %d\n", fep->tx_cnt)); - return ret; + spin_unlock_irqrestore(&fep->lock, flags); } -/* Process ctx, rtnl_lock semaphore */ -static int emac_change_mtu(struct net_device *ndev, int new_mtu) +/* + Fill/Re-fill the rx chain with valid ctrl/ptrs. + This function will fill from rx_slot up to the parm end. + So to completely fill the chain pre-set rx_slot to 0 and + pass in an end of 0. + */ +static void emac_rx_fill(struct net_device *dev, int end) { - struct ocp_enet_private *dev = ndev->priv; - int ret = 0; + int i; + struct ocp_enet_private *fep = dev->priv; + + i = fep->rx_slot; + do { + /* We don't want the 16 bytes skb_reserve done by dev_alloc_skb, + * it breaks our cache line alignement. However, we still allocate + * +16 so that we end up allocating the exact same size as + * dev_alloc_skb() would do. + * Also, because of the skb_res, the max DMA size we give to EMAC + * is slighly wrong, causing it to potentially DMA 2 more bytes + * from a broken/oversized packet. These 16 bytes will take care + * that we don't walk on somebody else toes with that. + */ + fep->rx_skb[i] = + alloc_skb(fep->rx_buffer_size + 16, GFP_ATOMIC); + + if (fep->rx_skb[i] == NULL) { + /* Keep rx_slot here, the next time clean/fill is called + * we will try again before the MAL wraps back here + * If the MAL tries to use this descriptor with + * the EMPTY bit off it will cause the + * rxde interrupt. That is where we will + * try again to allocate an sk_buff. + */ + break; - if (new_mtu < EMAC_MIN_MTU || new_mtu > EMAC_MAX_MTU) - return -EINVAL; + } - DBG("%d: change_mtu(%d)" NL, dev->def->index, new_mtu); + if (skb_res) + skb_reserve(fep->rx_skb[i], skb_res); - local_bh_disable(); - if (netif_running(ndev)) { - /* Check if we really need to reinitalize RX ring */ - if (emac_rx_skb_size(ndev->mtu) != emac_rx_skb_size(new_mtu)) - ret = emac_resize_rx_ring(dev, new_mtu); - } + /* We must NOT dma_map_single the cache line right after the + * buffer, so we must crop our sync size to account for the + * reserved space + */ + fep->rx_desc[i].data_ptr = + (unsigned char *)dma_map_single(&fep->ocpdev->dev, + (void *)fep->rx_skb[i]-> + data, + fep->rx_buffer_size - + skb_res, DMA_FROM_DEVICE); + + /* + * Some 4xx implementations use the previously + * reserved bits in data_len to encode the MS + * 4-bits of a 36-bit physical address (ERPN) + * This must be initialized. + */ + fep->rx_desc[i].data_len = 0; + fep->rx_desc[i].ctrl = MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR | + (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); - if (!ret) { - ndev->mtu = new_mtu; - dev->rx_skb_size = emac_rx_skb_size(new_mtu); - dev->rx_sync_size = emac_rx_sync_size(new_mtu); - } - local_bh_enable(); + } while ((i = (i + 1) % NUM_RX_BUFF) != end); - return ret; + fep->rx_slot = i; } -static void emac_clean_tx_ring(struct ocp_enet_private *dev) +static void +emac_rx_csum(struct net_device *dev, unsigned short ctrl, struct sk_buff *skb) { - int i; - for (i = 0; i < NUM_TX_BUFF; ++i) { - if (dev->tx_skb[i]) { - dev_kfree_skb(dev->tx_skb[i]); - dev->tx_skb[i] = NULL; - if (dev->tx_desc[i].ctrl & MAL_TX_CTRL_READY) - ++dev->estats.tx_dropped; - } - dev->tx_desc[i].ctrl = 0; - dev->tx_desc[i].data_ptr = 0; + struct ocp_enet_private *fep = dev->priv; + + /* Exit if interface has no TAH engine */ + if (!fep->tah_dev) { + skb->ip_summed = CHECKSUM_NONE; + return; + } + + /* Check for TCP/UDP/IP csum error */ + if (ctrl & EMAC_CSUM_VER_ERROR) { + /* Let the stack verify checksum errors */ + skb->ip_summed = CHECKSUM_NONE; +/* adapter->hw_csum_err++; */ + } else { + /* Csum is good */ + skb->ip_summed = CHECKSUM_UNNECESSARY; +/* adapter->hw_csum_good++; */ } } -static void emac_clean_rx_ring(struct ocp_enet_private *dev) +static int emac_rx_clean(struct net_device *dev) { - int i; - for (i = 0; i < NUM_RX_BUFF; ++i) - if (dev->rx_skb[i]) { - dev->rx_desc[i].ctrl = 0; - dev_kfree_skb(dev->rx_skb[i]); - dev->rx_skb[i] = NULL; - dev->rx_desc[i].data_ptr = 0; + int i, b, bnum = 0, buf[6]; + int error, frame_length; + struct ocp_enet_private *fep = dev->priv; + unsigned short ctrl; + + i = fep->rx_slot; + + PKT_DEBUG(("emac_rx_clean() entry, rx_slot: %d\n", fep->rx_slot)); + + do { + if (fep->rx_skb[i] == NULL) + continue; /*we have already handled the packet but haved failed to alloc */ + /* + since rx_desc is in uncached mem we don't keep reading it directly + we pull out a local copy of ctrl and do the checks on the copy. + */ + ctrl = fep->rx_desc[i].ctrl; + if (ctrl & MAL_RX_CTRL_EMPTY) + break; /*we don't have any more ready packets */ + + if (EMAC_IS_BAD_RX_PACKET(ctrl)) { + fep->stats.rx_errors++; + fep->stats.rx_dropped++; + + if (ctrl & EMAC_RX_ST_OE) + fep->stats.rx_fifo_errors++; + if (ctrl & EMAC_RX_ST_AE) + fep->stats.rx_frame_errors++; + if (ctrl & EMAC_RX_ST_BFCS) + fep->stats.rx_crc_errors++; + if (ctrl & (EMAC_RX_ST_RP | EMAC_RX_ST_PTL | + EMAC_RX_ST_ORE | EMAC_RX_ST_IRE)) + fep->stats.rx_length_errors++; + } else { + if ((ctrl & (MAL_RX_CTRL_FIRST | MAL_RX_CTRL_LAST)) == + (MAL_RX_CTRL_FIRST | MAL_RX_CTRL_LAST)) { + /* Single descriptor packet */ + emac_rx_csum(dev, ctrl, fep->rx_skb[i]); + /* Send the skb up the chain. */ + frame_length = fep->rx_desc[i].data_len - 4; + skb_put(fep->rx_skb[i], frame_length); + fep->rx_skb[i]->dev = dev; + fep->rx_skb[i]->protocol = + eth_type_trans(fep->rx_skb[i], dev); + error = netif_rx(fep->rx_skb[i]); + + if ((error == NET_RX_DROP) || + (error == NET_RX_BAD)) { + fep->stats.rx_dropped++; + } else { + fep->stats.rx_packets++; + fep->stats.rx_bytes += frame_length; + } + fep->rx_skb[i] = NULL; + } else { + /* Multiple descriptor packet */ + if (ctrl & MAL_RX_CTRL_FIRST) { + if (fep->rx_desc[(i + 1) % NUM_RX_BUFF]. + ctrl & MAL_RX_CTRL_EMPTY) + break; + bnum = 0; + buf[bnum] = i; + ++bnum; + continue; + } + if (((ctrl & MAL_RX_CTRL_FIRST) != + MAL_RX_CTRL_FIRST) && + ((ctrl & MAL_RX_CTRL_LAST) != + MAL_RX_CTRL_LAST)) { + if (fep->rx_desc[(i + 1) % + NUM_RX_BUFF].ctrl & + MAL_RX_CTRL_EMPTY) { + i = buf[0]; + break; + } + buf[bnum] = i; + ++bnum; + continue; + } + if (ctrl & MAL_RX_CTRL_LAST) { + buf[bnum] = i; + ++bnum; + skb_put(fep->rx_skb[buf[0]], + fep->rx_desc[buf[0]].data_len); + for (b = 1; b < bnum; b++) { + /* + * MAL is braindead, we need + * to copy the remainder + * of the packet from the + * latter descriptor buffers + * to the first skb. Then + * dispose of the source + * skbs. + * + * Once the stack is fixed + * to handle frags on most + * protocols we can generate + * a fragmented skb with + * no copies. + */ + memcpy(fep->rx_skb[buf[0]]-> + data + + fep->rx_skb[buf[0]]->len, + fep->rx_skb[buf[b]]-> + data, + fep->rx_desc[buf[b]]. + data_len); + skb_put(fep->rx_skb[buf[0]], + fep->rx_desc[buf[b]]. + data_len); + dma_unmap_single(&fep->ocpdev-> + dev, + fep-> + rx_desc[buf + [b]]. + data_ptr, + fep-> + rx_desc[buf + [b]]. + data_len, + DMA_FROM_DEVICE); + dev_kfree_skb(fep-> + rx_skb[buf[b]]); + } + emac_rx_csum(dev, ctrl, + fep->rx_skb[buf[0]]); + + fep->rx_skb[buf[0]]->dev = dev; + fep->rx_skb[buf[0]]->protocol = + eth_type_trans(fep->rx_skb[buf[0]], + dev); + error = netif_rx(fep->rx_skb[buf[0]]); + + if ((error == NET_RX_DROP) + || (error == NET_RX_BAD)) { + fep->stats.rx_dropped++; + } else { + fep->stats.rx_packets++; + fep->stats.rx_bytes += + fep->rx_skb[buf[0]]->len; + } + for (b = 0; b < bnum; b++) + fep->rx_skb[buf[b]] = NULL; + } + } } + } while ((i = (i + 1) % NUM_RX_BUFF) != fep->rx_slot); - if (dev->rx_sg_skb) { - dev_kfree_skb(dev->rx_sg_skb); - dev->rx_sg_skb = NULL; - } + PKT_DEBUG(("emac_rx_clean() exit, rx_slot: %d\n", fep->rx_slot)); + + return i; } -static inline int emac_alloc_rx_skb(struct ocp_enet_private *dev, int slot, - int flags) +static void emac_rxeob_dev(void *param, u32 chanmask) { - struct sk_buff *skb = alloc_skb(dev->rx_skb_size, flags); - if (unlikely(!skb)) - return -ENOMEM; - - dev->rx_skb[slot] = skb; - dev->rx_desc[slot].data_len = 0; - - skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2); - dev->rx_desc[slot].data_ptr = - dma_map_single(dev->ldev, skb->data - 2, dev->rx_sync_size, - DMA_FROM_DEVICE) + 2; - barrier(); - dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY | - (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); + struct net_device *dev = param; + struct ocp_enet_private *fep = dev->priv; + unsigned long flags; + int n; - return 0; + spin_lock_irqsave(&fep->lock, flags); + if ((n = emac_rx_clean(dev)) != fep->rx_slot) + emac_rx_fill(dev, n); + spin_unlock_irqrestore(&fep->lock, flags); } -static void emac_print_link_status(struct ocp_enet_private *dev) +/* + * This interrupt should never occurr, we don't program + * the MAL for contiunous mode. + */ +static void emac_txde_dev(void *param, u32 chanmask) { - if (netif_carrier_ok(dev->ndev)) - printk(KERN_INFO "%s: link is up, %d %s%s\n", - dev->ndev->name, dev->phy.speed, - dev->phy.duplex == DUPLEX_FULL ? "FDX" : "HDX", - dev->phy.pause ? ", pause enabled" : - dev->phy.asym_pause ? ", assymetric pause enabled" : ""); - else - printk(KERN_INFO "%s: link is down\n", dev->ndev->name); + struct net_device *dev = param; + struct ocp_enet_private *fep = dev->priv; + + printk(KERN_WARNING "%s: transmit descriptor error\n", dev->name); + + emac_mac_dump(dev); + emac_mal_dump(dev); + + /* Reenable the transmit channel */ + mal_enable_tx_channels(fep->mal, fep->commac.tx_chan_mask); } -/* Process ctx, rtnl_lock semaphore */ -static int emac_open(struct net_device *ndev) +/* + * 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 void emac_rxde_dev(void *param, u32 chanmask) { - struct ocp_enet_private *dev = ndev->priv; - struct ocp_func_emac_data *emacdata = dev->def->additions; - int err, i; - - DBG("%d: open" NL, dev->def->index); - - /* Setup error IRQ handler */ - err = request_irq(dev->def->irq, emac_irq, 0, "EMAC", dev); - if (err) { - printk(KERN_ERR "%s: failed to request IRQ %d\n", - ndev->name, dev->def->irq); - return err; + struct net_device *dev = param; + struct ocp_enet_private *fep = dev->priv; + unsigned long flags; + + if (net_ratelimit()) { + printk(KERN_WARNING "%s: receive descriptor error\n", + fep->ndev->name); + + emac_mac_dump(dev); + emac_mal_dump(dev); + emac_desc_dump(dev); } - /* Allocate RX ring */ - for (i = 0; i < NUM_RX_BUFF; ++i) - if (emac_alloc_rx_skb(dev, i, GFP_KERNEL)) { - printk(KERN_ERR "%s: failed to allocate RX ring\n", - ndev->name); - goto oom; - } + /* Disable RX channel */ + spin_lock_irqsave(&fep->lock, flags); + mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask); - local_bh_disable(); - dev->tx_cnt = dev->tx_slot = dev->ack_slot = dev->rx_slot = - dev->commac.rx_stopped = 0; - dev->rx_sg_skb = NULL; - - if (dev->phy.address >= 0) { - int link_poll_interval; - if (dev->phy.def->ops->poll_link(&dev->phy)) { - dev->phy.def->ops->read_link(&dev->phy); - EMAC_RX_CLK_DEFAULT(dev->def->index); - netif_carrier_on(dev->ndev); - link_poll_interval = PHY_POLL_LINK_ON; - } else { - EMAC_RX_CLK_TX(dev->def->index); - netif_carrier_off(dev->ndev); - link_poll_interval = PHY_POLL_LINK_OFF; - } - mod_timer(&dev->link_timer, jiffies + link_poll_interval); - emac_print_link_status(dev); - } else - netif_carrier_on(dev->ndev); - - emac_configure(dev); - mal_poll_add(dev->mal, &dev->commac); - mal_enable_tx_channel(dev->mal, emacdata->mal_tx_chan); - mal_set_rcbs(dev->mal, emacdata->mal_rx_chan, emac_rx_size(ndev->mtu)); - mal_enable_rx_channel(dev->mal, emacdata->mal_rx_chan); - emac_tx_enable(dev); - emac_rx_enable(dev); - netif_start_queue(ndev); - local_bh_enable(); + /* For now, charge the error against all emacs */ + fep->stats.rx_errors++; - return 0; - oom: - emac_clean_rx_ring(dev); - free_irq(dev->def->irq, dev); - return -ENOMEM; + /* so do we have any good packets still? */ + emac_rx_clean(dev); + + /* When the interface is restarted it resets processing to the + * first descriptor in the table. + */ + + fep->rx_slot = 0; + emac_rx_fill(dev, 0); + + set_mal_dcrn(fep->mal, DCRN_MALRXEOBISR, fep->commac.rx_chan_mask); + set_mal_dcrn(fep->mal, DCRN_MALRXDEIR, fep->commac.rx_chan_mask); + + /* Reenable the receive channels */ + mal_enable_rx_channels(fep->mal, fep->commac.rx_chan_mask); + spin_unlock_irqrestore(&fep->lock, flags); } -/* BHs disabled */ -static int emac_link_differs(struct ocp_enet_private *dev) +static irqreturn_t +emac_mac_irq(int irq, void *dev_instance, struct pt_regs *regs) { - u32 r = in_be32(&dev->emacp->mr1); + struct net_device *dev = dev_instance; + struct ocp_enet_private *fep = dev->priv; + emac_t *emacp = fep->emacp; + unsigned long tmp_em0isr; - int duplex = r & EMAC_MR1_FDE ? DUPLEX_FULL : DUPLEX_HALF; - int speed, pause, asym_pause; + /* EMAC interrupt */ + tmp_em0isr = in_be32(&emacp->em0isr); + if (tmp_em0isr & (EMAC_ISR_TE0 | EMAC_ISR_TE1)) { + /* This error is a hard transmit error - could retransmit */ + fep->stats.tx_errors++; - if (r & (EMAC_MR1_MF_1000 | EMAC_MR1_MF_1000GPCS)) - speed = SPEED_1000; - else if (r & EMAC_MR1_MF_100) - speed = SPEED_100; - else - speed = SPEED_10; + /* Reenable the transmit channel */ + mal_enable_tx_channels(fep->mal, fep->commac.tx_chan_mask); - switch (r & (EMAC_MR1_EIFC | EMAC_MR1_APP)) { - case (EMAC_MR1_EIFC | EMAC_MR1_APP): - pause = 1; - asym_pause = 0; - break; - case EMAC_MR1_APP: - pause = 0; - asym_pause = 1; - break; - default: - pause = asym_pause = 0; + } else { + fep->stats.rx_errors++; } - return speed != dev->phy.speed || duplex != dev->phy.duplex || - pause != dev->phy.pause || asym_pause != dev->phy.asym_pause; + + if (tmp_em0isr & EMAC_ISR_RP) + fep->stats.rx_length_errors++; + if (tmp_em0isr & EMAC_ISR_ALE) + fep->stats.rx_frame_errors++; + if (tmp_em0isr & EMAC_ISR_BFCS) + fep->stats.rx_crc_errors++; + if (tmp_em0isr & EMAC_ISR_PTLE) + fep->stats.rx_length_errors++; + if (tmp_em0isr & EMAC_ISR_ORE) + fep->stats.rx_length_errors++; + if (tmp_em0isr & EMAC_ISR_TE0) + fep->stats.tx_aborted_errors++; + + emac_err_dump(dev, tmp_em0isr); + + out_be32(&emacp->em0isr, tmp_em0isr); + + return IRQ_HANDLED; } -/* BHs disabled */ -static void emac_link_timer(unsigned long data) +static int emac_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ocp_enet_private *dev = (struct ocp_enet_private *)data; - int link_poll_interval; + unsigned short ctrl; + unsigned long flags; + struct ocp_enet_private *fep = dev->priv; + emac_t *emacp = fep->emacp; + int len = skb->len; + unsigned int offset = 0, size, f, tx_slot_first; + unsigned int nr_frags = skb_shinfo(skb)->nr_frags; - DBG2("%d: link timer" NL, dev->def->index); + spin_lock_irqsave(&fep->lock, flags); + + len -= skb->data_len; - if (dev->phy.def->ops->poll_link(&dev->phy)) { - if (!netif_carrier_ok(dev->ndev)) { - EMAC_RX_CLK_DEFAULT(dev->def->index); + if ((fep->tx_cnt + nr_frags + len / DESC_BUF_SIZE + 1) > NUM_TX_BUFF) { + PKT_DEBUG(("emac_start_xmit() stopping queue\n")); + netif_stop_queue(dev); + spin_unlock_irqrestore(&fep->lock, flags); + return -EBUSY; + } - /* Get new link parameters */ - dev->phy.def->ops->read_link(&dev->phy); + tx_slot_first = fep->tx_slot; - if (dev->tah_dev || emac_link_differs(dev)) - emac_full_tx_reset(dev->ndev); + while (len) { + size = min(len, DESC_BUF_SIZE); - netif_carrier_on(dev->ndev); - emac_print_link_status(dev); - } - link_poll_interval = PHY_POLL_LINK_ON; - } else { - if (netif_carrier_ok(dev->ndev)) { - EMAC_RX_CLK_TX(dev->def->index); -#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) - emac_reinitialize(dev); -#endif - netif_carrier_off(dev->ndev); - emac_print_link_status(dev); + fep->tx_desc[fep->tx_slot].data_len = (short)size; + fep->tx_desc[fep->tx_slot].data_ptr = + (unsigned char *)dma_map_single(&fep->ocpdev->dev, + (void *)((unsigned int)skb-> + data + offset), + size, DMA_TO_DEVICE); + + ctrl = EMAC_TX_CTRL_DFLT; + if (fep->tx_slot != tx_slot_first) + ctrl |= MAL_TX_CTRL_READY; + if ((NUM_TX_BUFF - 1) == fep->tx_slot) + ctrl |= MAL_TX_CTRL_WRAP; + if (!nr_frags && (len == size)) { + ctrl |= MAL_TX_CTRL_LAST; + fep->tx_skb[fep->tx_slot] = skb; } + if (skb->ip_summed == CHECKSUM_HW) + ctrl |= EMAC_TX_CTRL_TAH_CSUM; - /* Retry reset if the previous attempt failed. - * This is needed mostly for CONFIG_IBM_EMAC_PHY_RX_CLK_FIX - * case, but I left it here because it shouldn't trigger for - * sane PHYs anyway. - */ - if (unlikely(dev->reset_failed)) - emac_reinitialize(dev); + fep->tx_desc[fep->tx_slot].ctrl = ctrl; + + len -= size; + offset += size; - link_poll_interval = PHY_POLL_LINK_OFF; + /* Bump tx count */ + if (++fep->tx_cnt == NUM_TX_BUFF) + netif_stop_queue(dev); + + /* Next descriptor */ + if (++fep->tx_slot == NUM_TX_BUFF) + fep->tx_slot = 0; } - mod_timer(&dev->link_timer, jiffies + link_poll_interval); -} -/* BHs disabled */ -static void emac_force_link_update(struct ocp_enet_private *dev) -{ - netif_carrier_off(dev->ndev); - if (timer_pending(&dev->link_timer)) - mod_timer(&dev->link_timer, jiffies + PHY_POLL_LINK_OFF); -} + for (f = 0; f < nr_frags; f++) { + struct skb_frag_struct *frag; -/* Process ctx, rtnl_lock semaphore */ -static int emac_close(struct net_device *ndev) -{ - struct ocp_enet_private *dev = ndev->priv; - struct ocp_func_emac_data *emacdata = dev->def->additions; + frag = &skb_shinfo(skb)->frags[f]; + len = frag->size; + offset = 0; + + while (len) { + size = min(len, DESC_BUF_SIZE); + + dma_map_page(&fep->ocpdev->dev, + frag->page, + frag->page_offset + offset, + size, DMA_TO_DEVICE); + + ctrl = EMAC_TX_CTRL_DFLT | MAL_TX_CTRL_READY; + if ((NUM_TX_BUFF - 1) == fep->tx_slot) + ctrl |= MAL_TX_CTRL_WRAP; + if ((f == (nr_frags - 1)) && (len == size)) { + ctrl |= MAL_TX_CTRL_LAST; + fep->tx_skb[fep->tx_slot] = skb; + } + + if (skb->ip_summed == CHECKSUM_HW) + ctrl |= EMAC_TX_CTRL_TAH_CSUM; + + fep->tx_desc[fep->tx_slot].data_len = (short)size; + fep->tx_desc[fep->tx_slot].data_ptr = + (char *)((page_to_pfn(frag->page) << PAGE_SHIFT) + + frag->page_offset + offset); + fep->tx_desc[fep->tx_slot].ctrl = ctrl; + + len -= size; + offset += size; + + /* Bump tx count */ + if (++fep->tx_cnt == NUM_TX_BUFF) + netif_stop_queue(dev); + + /* Next descriptor */ + if (++fep->tx_slot == NUM_TX_BUFF) + fep->tx_slot = 0; + } + } - DBG("%d: close" NL, dev->def->index); + /* + * Deferred set READY on first descriptor of packet to + * avoid TX MAL race. + */ + fep->tx_desc[tx_slot_first].ctrl |= MAL_TX_CTRL_READY; - local_bh_disable(); + /* Send the packet out. */ + out_be32(&emacp->em0tmr0, EMAC_TMR0_XMIT); - if (dev->phy.address >= 0) - del_timer_sync(&dev->link_timer); + fep->stats.tx_packets++; + fep->stats.tx_bytes += skb->len; - netif_stop_queue(ndev); - emac_rx_disable(dev); - emac_tx_disable(dev); - mal_disable_rx_channel(dev->mal, emacdata->mal_rx_chan); - mal_disable_tx_channel(dev->mal, emacdata->mal_tx_chan); - mal_poll_del(dev->mal, &dev->commac); - local_bh_enable(); + PKT_DEBUG(("emac_start_xmit() exitn")); - emac_clean_tx_ring(dev); - emac_clean_rx_ring(dev); - free_irq(dev->def->irq, dev); + spin_unlock_irqrestore(&fep->lock, flags); return 0; } -static inline u16 emac_tx_csum(struct ocp_enet_private *dev, - struct sk_buff *skb) +static int emac_adjust_to_link(struct ocp_enet_private *fep) { -#if defined(CONFIG_IBM_EMAC_TAH) - if (skb->ip_summed == CHECKSUM_HW) { - ++dev->stats.tx_packets_csum; - return EMAC_TX_CTRL_TAH_CSUM; + emac_t *emacp = fep->emacp; + unsigned long mode_reg; + int full_duplex, speed; + + full_duplex = 0; + speed = SPEED_10; + + /* set mode register 1 defaults */ + mode_reg = EMAC_M1_DEFAULT; + + /* Read link mode on PHY */ + if (fep->phy_mii.def->ops->read_link(&fep->phy_mii) == 0) { + /* If an error occurred, we don't deal with it yet */ + full_duplex = (fep->phy_mii.duplex == DUPLEX_FULL); + speed = fep->phy_mii.speed; } -#endif - return 0; -} -static inline int emac_xmit_finish(struct ocp_enet_private *dev, int len) -{ - struct emac_regs *p = dev->emacp; - struct net_device *ndev = dev->ndev; - /* Send the packet out */ - out_be32(&p->tmr0, EMAC_TMR0_XMIT); + /* set speed (default is 10Mb) */ + switch (speed) { + case SPEED_1000: + mode_reg |= EMAC_M1_RFS_16K; + if (fep->rgmii_dev) { + struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(fep->rgmii_dev); + + if ((rgmii->mode[fep->rgmii_input] == RTBI) + || (rgmii->mode[fep->rgmii_input] == TBI)) + mode_reg |= EMAC_M1_MF_1000GPCS; + else + mode_reg |= EMAC_M1_MF_1000MBPS; + + emac_rgmii_port_speed(fep->rgmii_dev, fep->rgmii_input, + 1000); + } + break; + case SPEED_100: + mode_reg |= EMAC_M1_MF_100MBPS | EMAC_M1_RFS_4K; + if (fep->rgmii_dev) + emac_rgmii_port_speed(fep->rgmii_dev, fep->rgmii_input, + 100); + if (fep->zmii_dev) + emac_zmii_port_speed(fep->zmii_dev, fep->zmii_input, + 100); + break; + case SPEED_10: + default: + mode_reg = (mode_reg & ~EMAC_M1_MF_100MBPS) | EMAC_M1_RFS_4K; + if (fep->rgmii_dev) + emac_rgmii_port_speed(fep->rgmii_dev, fep->rgmii_input, + 10); + if (fep->zmii_dev) + emac_zmii_port_speed(fep->zmii_dev, fep->zmii_input, + 10); + } + + if (full_duplex) + mode_reg |= EMAC_M1_FDE | EMAC_M1_EIFC | EMAC_M1_IST; + else + mode_reg &= ~(EMAC_M1_FDE | EMAC_M1_EIFC | EMAC_M1_ILE); - if (unlikely(++dev->tx_cnt == NUM_TX_BUFF)) { - netif_stop_queue(ndev); - DBG2("%d: stopped TX queue" NL, dev->def->index); - } + LINK_DEBUG(("%s: adjust to link, speed: %d, duplex: %d, opened: %d\n", + fep->ndev->name, speed, full_duplex, fep->opened)); - ndev->trans_start = jiffies; - ++dev->stats.tx_packets; - dev->stats.tx_bytes += len; + printk(KERN_INFO "%s: Speed: %d, %s duplex.\n", + fep->ndev->name, speed, full_duplex ? "Full" : "Half"); + if (fep->opened) + out_be32(&emacp->em0mr1, mode_reg); return 0; } -/* BHs disabled */ -static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static int emac_set_mac_address(struct net_device *ndev, void *p) { - struct ocp_enet_private *dev = ndev->priv; - unsigned int len = skb->len; - int slot; + struct ocp_enet_private *fep = ndev->priv; + emac_t *emacp = fep->emacp; + struct sockaddr *addr = p; - u16 ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY | - MAL_TX_CTRL_LAST | emac_tx_csum(dev, skb); + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; - slot = dev->tx_slot++; - if (dev->tx_slot == NUM_TX_BUFF) { - dev->tx_slot = 0; - ctrl |= MAL_TX_CTRL_WRAP; - } + memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); - DBG2("%d: xmit(%u) %d" NL, dev->def->index, len, slot); + /* set the high address */ + out_be32(&emacp->em0iahr, + (fep->ndev->dev_addr[0] << 8) | fep->ndev->dev_addr[1]); - dev->tx_skb[slot] = skb; - dev->tx_desc[slot].data_ptr = dma_map_single(dev->ldev, skb->data, len, - DMA_TO_DEVICE); - dev->tx_desc[slot].data_len = (u16) len; - barrier(); - dev->tx_desc[slot].ctrl = ctrl; + /* set the low address */ + out_be32(&emacp->em0ialr, + (fep->ndev->dev_addr[2] << 24) | (fep->ndev->dev_addr[3] << 16) + | (fep->ndev->dev_addr[4] << 8) | fep->ndev->dev_addr[5]); - return emac_xmit_finish(dev, len); + return 0; } -#if defined(CONFIG_IBM_EMAC_TAH) -static inline int emac_xmit_split(struct ocp_enet_private *dev, int slot, - u32 pd, int len, int last, u16 base_ctrl) +static int emac_change_mtu(struct net_device *dev, int new_mtu) { - while (1) { - u16 ctrl = base_ctrl; - int chunk = min(len, MAL_MAX_TX_SIZE); - len -= chunk; + struct ocp_enet_private *fep = dev->priv; + int old_mtu = dev->mtu; + unsigned long mode_reg; + emac_t *emacp = fep->emacp; + u32 em0mr0; + int i, full; + unsigned long flags; + + if ((new_mtu < EMAC_MIN_MTU) || (new_mtu > EMAC_MAX_MTU)) { + printk(KERN_ERR + "emac: Invalid MTU setting, MTU must be between %d and %d\n", + EMAC_MIN_MTU, EMAC_MAX_MTU); + return -EINVAL; + } - slot = (slot + 1) % NUM_TX_BUFF; + if (old_mtu != new_mtu && netif_running(dev)) { + /* Stop rx engine */ + em0mr0 = in_be32(&emacp->em0mr0); + out_be32(&emacp->em0mr0, em0mr0 & ~EMAC_M0_RXE); + + /* Wait for descriptors to be empty */ + do { + full = 0; + for (i = 0; i < NUM_RX_BUFF; i++) + if (!(fep->rx_desc[i].ctrl & MAL_RX_CTRL_EMPTY)) { + printk(KERN_NOTICE + "emac: RX ring is still full\n"); + full = 1; + } + } while (full); + + spin_lock_irqsave(&fep->lock, flags); + + mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask); + + /* Destroy all old rx skbs */ + for (i = 0; i < NUM_RX_BUFF; i++) { + dma_unmap_single(&fep->ocpdev->dev, + fep->rx_desc[i].data_ptr, + fep->rx_desc[i].data_len, + DMA_FROM_DEVICE); + dev_kfree_skb(fep->rx_skb[i]); + fep->rx_skb[i] = NULL; + } - if (last && !len) - ctrl |= MAL_TX_CTRL_LAST; - if (slot == NUM_TX_BUFF - 1) - ctrl |= MAL_TX_CTRL_WRAP; + /* Set new rx_buffer_size, jumbo cap, and advertise new mtu */ + mode_reg = in_be32(&emacp->em0mr1); + if (new_mtu > ENET_DEF_MTU_SIZE) { + mode_reg |= EMAC_M1_JUMBO_ENABLE; + fep->rx_buffer_size = EMAC_MAX_FRAME; + } else { + mode_reg &= ~EMAC_M1_JUMBO_ENABLE; + fep->rx_buffer_size = ENET_DEF_BUF_SIZE; + } + dev->mtu = new_mtu; + out_be32(&emacp->em0mr1, mode_reg); - dev->tx_skb[slot] = NULL; - dev->tx_desc[slot].data_ptr = pd; - dev->tx_desc[slot].data_len = (u16) chunk; - dev->tx_desc[slot].ctrl = ctrl; - ++dev->tx_cnt; + /* Re-init rx skbs */ + fep->rx_slot = 0; + emac_rx_fill(dev, 0); - if (!len) - break; + /* Restart the rx engine */ + mal_enable_rx_channels(fep->mal, fep->commac.rx_chan_mask); + out_be32(&emacp->em0mr0, em0mr0 | EMAC_M0_RXE); - pd += chunk; + spin_unlock_irqrestore(&fep->lock, flags); } - return slot; + + return 0; } -/* BHs disabled (SG version for TAH equipped EMACs) */ -static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev) +static void __emac_set_multicast_list(struct net_device *dev) { - struct ocp_enet_private *dev = ndev->priv; - int nr_frags = skb_shinfo(skb)->nr_frags; - int len = skb->len, chunk; - int slot, i; - u16 ctrl; - u32 pd; - - /* This is common "fast" path */ - if (likely(!nr_frags && len <= MAL_MAX_TX_SIZE)) - return emac_start_xmit(skb, ndev); + struct ocp_enet_private *fep = dev->priv; + emac_t *emacp = fep->emacp; + u32 rmr = in_be32(&emacp->em0rmr); - len -= skb->data_len; + /* First clear all special bits, they can be set later */ + rmr &= ~(EMAC_RMR_PME | EMAC_RMR_PMME | EMAC_RMR_MAE); - /* Note, this is only an *estimation*, we can still run out of empty - * slots because of the additional fragmentation into - * MAL_MAX_TX_SIZE-sized chunks - */ - if (unlikely(dev->tx_cnt + nr_frags + mal_tx_chunks(len) > NUM_TX_BUFF)) - goto stop_queue; - - ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY | - emac_tx_csum(dev, skb); - slot = dev->tx_slot; - - /* skb data */ - dev->tx_skb[slot] = NULL; - chunk = min(len, MAL_MAX_TX_SIZE); - dev->tx_desc[slot].data_ptr = pd = - dma_map_single(dev->ldev, skb->data, len, DMA_TO_DEVICE); - dev->tx_desc[slot].data_len = (u16) chunk; - len -= chunk; - if (unlikely(len)) - slot = emac_xmit_split(dev, slot, pd + chunk, len, !nr_frags, - ctrl); - /* skb fragments */ - for (i = 0; i < nr_frags; ++i) { - struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; - len = frag->size; + if (dev->flags & IFF_PROMISC) { + rmr |= EMAC_RMR_PME; + } else if (dev->flags & IFF_ALLMULTI || 32 < dev->mc_count) { + /* + * Must be setting up to use multicast + * Now check for promiscuous multicast + */ + rmr |= EMAC_RMR_PMME; + } else if (dev->flags & IFF_MULTICAST && 0 < dev->mc_count) { + unsigned short em0gaht[4] = { 0, 0, 0, 0 }; + struct dev_mc_list *dmi; + + /* Need to hash on the multicast address. */ + for (dmi = dev->mc_list; dmi; dmi = dmi->next) { + unsigned long mc_crc; + unsigned int bit_number; + + mc_crc = ether_crc(6, (char *)dmi->dmi_addr); + bit_number = 63 - (mc_crc >> 26); /* MSB: 0 LSB: 63 */ + em0gaht[bit_number >> 4] |= + 0x8000 >> (bit_number & 0x0f); + } + emacp->em0gaht1 = em0gaht[0]; + emacp->em0gaht2 = em0gaht[1]; + emacp->em0gaht3 = em0gaht[2]; + emacp->em0gaht4 = em0gaht[3]; - if (unlikely(dev->tx_cnt + mal_tx_chunks(len) >= NUM_TX_BUFF)) - goto undo_frame; + /* Turn on multicast addressing */ + rmr |= EMAC_RMR_MAE; + } + out_be32(&emacp->em0rmr, rmr); +} - pd = dma_map_page(dev->ldev, frag->page, frag->page_offset, len, - DMA_TO_DEVICE); +static int emac_init_tah(struct ocp_enet_private *fep) +{ + tah_t *tahp; - slot = emac_xmit_split(dev, slot, pd, len, i == nr_frags - 1, - ctrl); - } + /* Initialize TAH and enable checksum verification */ + tahp = (tah_t *) ioremap(fep->tah_dev->def->paddr, sizeof(*tahp)); - DBG2("%d: xmit_sg(%u) %d - %d" NL, dev->def->index, skb->len, - dev->tx_slot, slot); + if (tahp == NULL) { + printk(KERN_ERR "tah%d: Cannot ioremap TAH registers!\n", + fep->tah_dev->def->index); - /* Attach skb to the last slot so we don't release it too early */ - dev->tx_skb[slot] = skb; + return -ENOMEM; + } - /* Send the packet out */ - if (dev->tx_slot == NUM_TX_BUFF - 1) - ctrl |= MAL_TX_CTRL_WRAP; - barrier(); - dev->tx_desc[dev->tx_slot].ctrl = ctrl; - dev->tx_slot = (slot + 1) % NUM_TX_BUFF; + out_be32(&tahp->tah_mr, TAH_MR_SR); - return emac_xmit_finish(dev, skb->len); + /* wait for reset to complete */ + while (in_be32(&tahp->tah_mr) & TAH_MR_SR) ; - undo_frame: - /* Well, too bad. Our previous estimation was overly optimistic. - * Undo everything. - */ - while (slot != dev->tx_slot) { - dev->tx_desc[slot].ctrl = 0; - --dev->tx_cnt; - if (--slot < 0) - slot = NUM_TX_BUFF - 1; - } - ++dev->estats.tx_undo; + /* 10KB TAH TX FIFO accomodates the max MTU of 9000 */ + out_be32(&tahp->tah_mr, + TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP | + TAH_MR_DIG); - stop_queue: - netif_stop_queue(ndev); - DBG2("%d: stopped TX queue" NL, dev->def->index); - return 1; -} -#else -# define emac_start_xmit_sg emac_start_xmit -#endif /* !defined(CONFIG_IBM_EMAC_TAH) */ + iounmap(tahp); -/* BHs disabled */ -static void emac_parse_tx_error(struct ocp_enet_private *dev, u16 ctrl) -{ - struct ibm_emac_error_stats *st = &dev->estats; - DBG("%d: BD TX error %04x" NL, dev->def->index, ctrl); - - ++st->tx_bd_errors; - if (ctrl & EMAC_TX_ST_BFCS) - ++st->tx_bd_bad_fcs; - if (ctrl & EMAC_TX_ST_LCS) - ++st->tx_bd_carrier_loss; - if (ctrl & EMAC_TX_ST_ED) - ++st->tx_bd_excessive_deferral; - if (ctrl & EMAC_TX_ST_EC) - ++st->tx_bd_excessive_collisions; - if (ctrl & EMAC_TX_ST_LC) - ++st->tx_bd_late_collision; - if (ctrl & EMAC_TX_ST_MC) - ++st->tx_bd_multple_collisions; - if (ctrl & EMAC_TX_ST_SC) - ++st->tx_bd_single_collision; - if (ctrl & EMAC_TX_ST_UR) - ++st->tx_bd_underrun; - if (ctrl & EMAC_TX_ST_SQE) - ++st->tx_bd_sqe; + return 0; } -static void emac_poll_tx(void *param) +static void emac_init_rings(struct net_device *dev) { - struct ocp_enet_private *dev = param; - DBG2("%d: poll_tx, %d %d" NL, dev->def->index, dev->tx_cnt, - dev->ack_slot); - - if (dev->tx_cnt) { - u16 ctrl; - int slot = dev->ack_slot, n = 0; - again: - ctrl = dev->tx_desc[slot].ctrl; - if (!(ctrl & MAL_TX_CTRL_READY)) { - struct sk_buff *skb = dev->tx_skb[slot]; - ++n; - - if (skb) { - dev_kfree_skb(skb); - dev->tx_skb[slot] = NULL; - } - slot = (slot + 1) % NUM_TX_BUFF; - - if (unlikely(EMAC_IS_BAD_TX(ctrl))) - emac_parse_tx_error(dev, ctrl); + struct ocp_enet_private *ep = dev->priv; + int loop; - if (--dev->tx_cnt) - goto again; - } - if (n) { - dev->ack_slot = slot; - if (netif_queue_stopped(dev->ndev) && - dev->tx_cnt < EMAC_TX_WAKEUP_THRESH) - netif_wake_queue(dev->ndev); + ep->tx_desc = (struct mal_descriptor *)((char *)ep->mal->tx_virt_addr + + (ep->mal_tx_chan * + MAL_DT_ALIGN)); + ep->rx_desc = + (struct mal_descriptor *)((char *)ep->mal->rx_virt_addr + + (ep->mal_rx_chan * MAL_DT_ALIGN)); - DBG2("%d: tx %d pkts" NL, dev->def->index, n); + /* Fill in the transmit descriptor ring. */ + for (loop = 0; loop < NUM_TX_BUFF; loop++) { + if (ep->tx_skb[loop]) { + dma_unmap_single(&ep->ocpdev->dev, + ep->tx_desc[loop].data_ptr, + ep->tx_desc[loop].data_len, + DMA_TO_DEVICE); + dev_kfree_skb_irq(ep->tx_skb[loop]); } + ep->tx_skb[loop] = NULL; + ep->tx_desc[loop].ctrl = 0; + ep->tx_desc[loop].data_len = 0; + ep->tx_desc[loop].data_ptr = NULL; + } + ep->tx_desc[loop - 1].ctrl |= MAL_TX_CTRL_WRAP; + + /* Format the receive descriptor ring. */ + ep->rx_slot = 0; + /* Default is MTU=1500 + Ethernet overhead */ + ep->rx_buffer_size = dev->mtu + ENET_HEADER_SIZE + ENET_FCS_SIZE; + emac_rx_fill(dev, 0); + if (ep->rx_slot != 0) { + printk(KERN_ERR + "%s: Not enough mem for RxChain durning Open?\n", + dev->name); + /*We couldn't fill the ring at startup? + *We could clean up and fail to open but right now we will try to + *carry on. It may be a sign of a bad NUM_RX_BUFF value + */ } -} - -static inline void emac_recycle_rx_skb(struct ocp_enet_private *dev, int slot, - int len) -{ - struct sk_buff *skb = dev->rx_skb[slot]; - DBG2("%d: recycle %d %d" NL, dev->def->index, slot, len); - - if (len) - dma_map_single(dev->ldev, skb->data - 2, - EMAC_DMA_ALIGN(len + 2), DMA_FROM_DEVICE); - dev->rx_desc[slot].data_len = 0; - barrier(); - dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY | - (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); + ep->tx_cnt = 0; + ep->tx_slot = 0; + ep->ack_slot = 0; } -static void emac_parse_rx_error(struct ocp_enet_private *dev, u16 ctrl) +static void emac_reset_configure(struct ocp_enet_private *fep) { - struct ibm_emac_error_stats *st = &dev->estats; - DBG("%d: BD RX error %04x" NL, dev->def->index, ctrl); - - ++st->rx_bd_errors; - if (ctrl & EMAC_RX_ST_OE) - ++st->rx_bd_overrun; - if (ctrl & EMAC_RX_ST_BP) - ++st->rx_bd_bad_packet; - if (ctrl & EMAC_RX_ST_RP) - ++st->rx_bd_runt_packet; - if (ctrl & EMAC_RX_ST_SE) - ++st->rx_bd_short_event; - if (ctrl & EMAC_RX_ST_AE) - ++st->rx_bd_alignment_error; - if (ctrl & EMAC_RX_ST_BFCS) - ++st->rx_bd_bad_fcs; - if (ctrl & EMAC_RX_ST_PTL) - ++st->rx_bd_packet_too_long; - if (ctrl & EMAC_RX_ST_ORE) - ++st->rx_bd_out_of_range; - if (ctrl & EMAC_RX_ST_IRE) - ++st->rx_bd_in_range; -} + emac_t *emacp = fep->emacp; + int i; -static inline void emac_rx_csum(struct ocp_enet_private *dev, - struct sk_buff *skb, u16 ctrl) -{ -#if defined(CONFIG_IBM_EMAC_TAH) - if (!ctrl && dev->tah_dev) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - ++dev->stats.rx_packets_csum; - } -#endif -} + mal_disable_tx_channels(fep->mal, fep->commac.tx_chan_mask); + mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask); -static inline int emac_rx_sg_append(struct ocp_enet_private *dev, int slot) -{ - if (likely(dev->rx_sg_skb != NULL)) { - int len = dev->rx_desc[slot].data_len; - int tot_len = dev->rx_sg_skb->len + len; - - if (unlikely(tot_len + 2 > dev->rx_skb_size)) { - ++dev->estats.rx_dropped_mtu; - dev_kfree_skb(dev->rx_sg_skb); - dev->rx_sg_skb = NULL; - } else { - cacheable_memcpy(dev->rx_sg_skb->tail, - dev->rx_skb[slot]->data, len); - skb_put(dev->rx_sg_skb, len); - emac_recycle_rx_skb(dev, slot, len); - return 0; + /* + * Check for a link, some PHYs don't provide a clock if + * no link is present. Some EMACs will not come out of + * soft reset without a PHY clock present. + */ + if (fep->phy_mii.def->ops->poll_link(&fep->phy_mii)) { + /* Reset the EMAC */ + out_be32(&emacp->em0mr0, EMAC_M0_SRST); + udelay(20); + for (i = 0; i < 100; i++) { + if ((in_be32(&emacp->em0mr0) & EMAC_M0_SRST) == 0) + break; + udelay(10); } - } - emac_recycle_rx_skb(dev, slot, 0); - return -1; -} - -/* BHs disabled */ -static int emac_poll_rx(void *param, int budget) -{ - struct ocp_enet_private *dev = param; - int slot = dev->rx_slot, received = 0; - DBG2("%d: poll_rx(%d)" NL, dev->def->index, budget); + if (i >= 100) { + printk(KERN_ERR "%s: Cannot reset EMAC\n", + fep->ndev->name); + return; + } + } - again: - while (budget > 0) { - int len; - struct sk_buff *skb; - u16 ctrl = dev->rx_desc[slot].ctrl; + /* Switch IRQs off for now */ + out_be32(&emacp->em0iser, 0); - if (ctrl & MAL_RX_CTRL_EMPTY) - break; + /* Configure MAL rx channel */ + mal_set_rcbs(fep->mal, fep->mal_rx_chan, DESC_BUF_SIZE_REG); - skb = dev->rx_skb[slot]; - barrier(); - len = dev->rx_desc[slot].data_len; + /* set the high address */ + out_be32(&emacp->em0iahr, + (fep->ndev->dev_addr[0] << 8) | fep->ndev->dev_addr[1]); - if (unlikely(!MAL_IS_SINGLE_RX(ctrl))) - goto sg; + /* set the low address */ + out_be32(&emacp->em0ialr, + (fep->ndev->dev_addr[2] << 24) | (fep->ndev->dev_addr[3] << 16) + | (fep->ndev->dev_addr[4] << 8) | fep->ndev->dev_addr[5]); - ctrl &= EMAC_BAD_RX_MASK; - if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) { - emac_parse_rx_error(dev, ctrl); - ++dev->estats.rx_dropped_error; - emac_recycle_rx_skb(dev, slot, 0); - len = 0; - goto next; - } + /* Adjust to link */ + if (netif_carrier_ok(fep->ndev)) + emac_adjust_to_link(fep); - if (len && len < EMAC_RX_COPY_THRESH) { - struct sk_buff *copy_skb = - alloc_skb(len + EMAC_RX_SKB_HEADROOM + 2, GFP_ATOMIC); - if (unlikely(!copy_skb)) - goto oom; - - skb_reserve(copy_skb, EMAC_RX_SKB_HEADROOM + 2); - cacheable_memcpy(copy_skb->data - 2, skb->data - 2, - len + 2); - emac_recycle_rx_skb(dev, slot, len); - skb = copy_skb; - } else if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) - goto oom; - - skb_put(skb, len); - push_packet: - skb->dev = dev->ndev; - skb->protocol = eth_type_trans(skb, dev->ndev); - emac_rx_csum(dev, skb, ctrl); - - if (unlikely(netif_receive_skb(skb) == NET_RX_DROP)) - ++dev->estats.rx_dropped_stack; - next: - ++dev->stats.rx_packets; - skip: - dev->stats.rx_bytes += len; - slot = (slot + 1) % NUM_RX_BUFF; - --budget; - ++received; - continue; - sg: - if (ctrl & MAL_RX_CTRL_FIRST) { - BUG_ON(dev->rx_sg_skb); - if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) { - DBG("%d: rx OOM %d" NL, dev->def->index, slot); - ++dev->estats.rx_dropped_oom; - emac_recycle_rx_skb(dev, slot, 0); - } else { - dev->rx_sg_skb = skb; - skb_put(skb, len); - } - } else if (!emac_rx_sg_append(dev, slot) && - (ctrl & MAL_RX_CTRL_LAST)) { - - skb = dev->rx_sg_skb; - dev->rx_sg_skb = NULL; - - ctrl &= EMAC_BAD_RX_MASK; - if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) { - emac_parse_rx_error(dev, ctrl); - ++dev->estats.rx_dropped_error; - dev_kfree_skb(skb); - len = 0; - } else - goto push_packet; - } - goto skip; - oom: - DBG("%d: rx OOM %d" NL, dev->def->index, slot); - /* Drop the packet and recycle skb */ - ++dev->estats.rx_dropped_oom; - emac_recycle_rx_skb(dev, slot, 0); - goto next; - } + /* enable broadcast/individual address and RX FIFO defaults */ + out_be32(&emacp->em0rmr, EMAC_RMR_DEFAULT); - if (received) { - DBG2("%d: rx %d BDs" NL, dev->def->index, received); - dev->rx_slot = slot; - } + /* set transmit request threshold register */ + out_be32(&emacp->em0trtr, EMAC_TRTR_DEFAULT); - if (unlikely(budget && dev->commac.rx_stopped)) { - struct ocp_func_emac_data *emacdata = dev->def->additions; + /* Reconfigure multicast */ + __emac_set_multicast_list(fep->ndev); - barrier(); - if (!(dev->rx_desc[slot].ctrl & MAL_RX_CTRL_EMPTY)) { - DBG2("%d: rx restart" NL, dev->def->index); - received = 0; - goto again; - } + /* Set receiver/transmitter defaults */ + out_be32(&emacp->em0rwmr, EMAC_RWMR_DEFAULT); + out_be32(&emacp->em0tmr0, EMAC_TMR0_DEFAULT); + out_be32(&emacp->em0tmr1, EMAC_TMR1_DEFAULT); - if (dev->rx_sg_skb) { - DBG2("%d: dropping partial rx packet" NL, - dev->def->index); - ++dev->estats.rx_dropped_error; - dev_kfree_skb(dev->rx_sg_skb); - dev->rx_sg_skb = NULL; - } + /* set frame gap */ + out_be32(&emacp->em0ipgvr, CONFIG_IBM_EMAC_FGAP); + + /* set VLAN Tag Protocol Identifier */ + out_be32(&emacp->em0vtpid, 0x8100); - dev->commac.rx_stopped = 0; - mal_enable_rx_channel(dev->mal, emacdata->mal_rx_chan); - emac_rx_enable(dev); - dev->rx_slot = 0; - } - return received; + /* Init ring buffers */ + emac_init_rings(fep->ndev); } -/* BHs disabled */ -static int emac_peek_rx(void *param) +static void emac_kick(struct ocp_enet_private *fep) { - struct ocp_enet_private *dev = param; - return !(dev->rx_desc[dev->rx_slot].ctrl & MAL_RX_CTRL_EMPTY); -} + emac_t *emacp = fep->emacp; + unsigned long emac_ier; -/* BHs disabled */ -static int emac_peek_rx_sg(void *param) -{ - struct ocp_enet_private *dev = param; - int slot = dev->rx_slot; - while (1) { - u16 ctrl = dev->rx_desc[slot].ctrl; - if (ctrl & MAL_RX_CTRL_EMPTY) - return 0; - else if (ctrl & MAL_RX_CTRL_LAST) - return 1; + emac_ier = EMAC_ISR_PP | EMAC_ISR_BP | EMAC_ISR_RP | + EMAC_ISR_SE | EMAC_ISR_PTLE | EMAC_ISR_ALE | + EMAC_ISR_BFCS | EMAC_ISR_ORE | EMAC_ISR_IRE; - slot = (slot + 1) % NUM_RX_BUFF; + out_be32(&emacp->em0iser, emac_ier); - /* I'm just being paranoid here :) */ - if (unlikely(slot == dev->rx_slot)) - return 0; - } -} + /* enable all MAL transmit and receive channels */ + mal_enable_tx_channels(fep->mal, fep->commac.tx_chan_mask); + mal_enable_rx_channels(fep->mal, fep->commac.rx_chan_mask); -/* Hard IRQ */ -static void emac_rxde(void *param) -{ - struct ocp_enet_private *dev = param; - ++dev->estats.rx_stopped; - emac_rx_disable_async(dev); + /* set transmit and receive enable */ + out_be32(&emacp->em0mr0, EMAC_M0_TXE | EMAC_M0_RXE); } -/* Hard IRQ */ -static irqreturn_t emac_irq(int irq, void *dev_instance, struct pt_regs *regs) +static void +emac_start_link(struct ocp_enet_private *fep, struct ethtool_cmd *ep) { - struct ocp_enet_private *dev = dev_instance; - struct emac_regs *p = dev->emacp; - struct ibm_emac_error_stats *st = &dev->estats; - - u32 isr = in_be32(&p->isr); - out_be32(&p->isr, isr); - - DBG("%d: isr = %08x" NL, dev->def->index, isr); - - if (isr & EMAC_ISR_TXPE) - ++st->tx_parity; - if (isr & EMAC_ISR_RXPE) - ++st->rx_parity; - if (isr & EMAC_ISR_TXUE) - ++st->tx_underrun; - if (isr & EMAC_ISR_RXOE) - ++st->rx_fifo_overrun; - if (isr & EMAC_ISR_OVR) - ++st->rx_overrun; - if (isr & EMAC_ISR_BP) - ++st->rx_bad_packet; - if (isr & EMAC_ISR_RP) - ++st->rx_runt_packet; - if (isr & EMAC_ISR_SE) - ++st->rx_short_event; - if (isr & EMAC_ISR_ALE) - ++st->rx_alignment_error; - if (isr & EMAC_ISR_BFCS) - ++st->rx_bad_fcs; - if (isr & EMAC_ISR_PTLE) - ++st->rx_packet_too_long; - if (isr & EMAC_ISR_ORE) - ++st->rx_out_of_range; - if (isr & EMAC_ISR_IRE) - ++st->rx_in_range; - if (isr & EMAC_ISR_SQE) - ++st->tx_sqe; - if (isr & EMAC_ISR_TE) - ++st->tx_errors; + u32 advertise; + int autoneg; + int forced_speed; + int forced_duplex; - return IRQ_HANDLED; -} + /* Default advertise */ + advertise = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full; + autoneg = fep->want_autoneg; + forced_speed = fep->phy_mii.speed; + forced_duplex = fep->phy_mii.duplex; -static struct net_device_stats *emac_stats(struct net_device *ndev) -{ - struct ocp_enet_private *dev = ndev->priv; - struct ibm_emac_stats *st = &dev->stats; - struct ibm_emac_error_stats *est = &dev->estats; - struct net_device_stats *nst = &dev->nstats; - - DBG2("%d: stats" NL, dev->def->index); - - /* Compute "legacy" statistics */ - local_irq_disable(); - nst->rx_packets = (unsigned long)st->rx_packets; - nst->rx_bytes = (unsigned long)st->rx_bytes; - nst->tx_packets = (unsigned long)st->tx_packets; - nst->tx_bytes = (unsigned long)st->tx_bytes; - nst->rx_dropped = (unsigned long)(est->rx_dropped_oom + - est->rx_dropped_error + - est->rx_dropped_resize + - est->rx_dropped_mtu); - nst->tx_dropped = (unsigned long)est->tx_dropped; - - nst->rx_errors = (unsigned long)est->rx_bd_errors; - nst->rx_fifo_errors = (unsigned long)(est->rx_bd_overrun + - est->rx_fifo_overrun + - est->rx_overrun); - nst->rx_frame_errors = (unsigned long)(est->rx_bd_alignment_error + - est->rx_alignment_error); - nst->rx_crc_errors = (unsigned long)(est->rx_bd_bad_fcs + - est->rx_bad_fcs); - nst->rx_length_errors = (unsigned long)(est->rx_bd_runt_packet + - est->rx_bd_short_event + - est->rx_bd_packet_too_long + - est->rx_bd_out_of_range + - est->rx_bd_in_range + - est->rx_runt_packet + - est->rx_short_event + - est->rx_packet_too_long + - est->rx_out_of_range + - est->rx_in_range); - - nst->tx_errors = (unsigned long)(est->tx_bd_errors + est->tx_errors); - nst->tx_fifo_errors = (unsigned long)(est->tx_bd_underrun + - est->tx_underrun); - nst->tx_carrier_errors = (unsigned long)est->tx_bd_carrier_loss; - nst->collisions = (unsigned long)(est->tx_bd_excessive_deferral + - est->tx_bd_excessive_collisions + - est->tx_bd_late_collision + - est->tx_bd_multple_collisions); - local_irq_enable(); - return nst; + /* Setup link parameters */ + if (ep) { + if (ep->autoneg == AUTONEG_ENABLE) { + advertise = ep->advertising; + autoneg = 1; + } else { + autoneg = 0; + forced_speed = ep->speed; + forced_duplex = ep->duplex; + } + } + + /* Configure PHY & start aneg */ + fep->want_autoneg = autoneg; + if (autoneg) { + LINK_DEBUG(("%s: start link aneg, advertise: 0x%x\n", + fep->ndev->name, advertise)); + fep->phy_mii.def->ops->setup_aneg(&fep->phy_mii, advertise); + } else { + LINK_DEBUG(("%s: start link forced, speed: %d, duplex: %d\n", + fep->ndev->name, forced_speed, forced_duplex)); + fep->phy_mii.def->ops->setup_forced(&fep->phy_mii, forced_speed, + forced_duplex); + } + fep->timer_ticks = 0; + mod_timer(&fep->link_timer, jiffies + HZ); } -static void emac_remove(struct ocp_device *ocpdev) +static void emac_link_timer(unsigned long data) { - struct ocp_enet_private *dev = ocp_get_drvdata(ocpdev); - - DBG("%d: remove" NL, dev->def->index); + struct ocp_enet_private *fep = (struct ocp_enet_private *)data; + int link; - ocp_set_drvdata(ocpdev, 0); - unregister_netdev(dev->ndev); + if (fep->going_away) + return; - tah_fini(dev->tah_dev); - rgmii_fini(dev->rgmii_dev, dev->rgmii_input); - zmii_fini(dev->zmii_dev, dev->zmii_input); + spin_lock_irq(&fep->lock); - emac_dbg_register(dev->def->index, 0); + link = fep->phy_mii.def->ops->poll_link(&fep->phy_mii); + LINK_DEBUG(("%s: poll_link: %d\n", fep->ndev->name, link)); - mal_unregister_commac(dev->mal, &dev->commac); - iounmap((void *)dev->emacp); - kfree(dev->ndev); + if (link == netif_carrier_ok(fep->ndev)) { + if (!link && fep->want_autoneg && (++fep->timer_ticks) > 10) + emac_start_link(fep, NULL); + goto out; + } + printk(KERN_INFO "%s: Link is %s\n", fep->ndev->name, + link ? "Up" : "Down"); + if (link) { + netif_carrier_on(fep->ndev); + /* Chip needs a full reset on config change. That sucks, so I + * should ultimately move that to some tasklet to limit + * latency peaks caused by this code + */ + emac_reset_configure(fep); + if (fep->opened) + emac_kick(fep); + } else { + fep->timer_ticks = 0; + netif_carrier_off(fep->ndev); + } + out: + mod_timer(&fep->link_timer, jiffies + HZ); + spin_unlock_irq(&fep->lock); } -static struct mal_commac_ops emac_commac_ops = { - .poll_tx = &emac_poll_tx, - .poll_rx = &emac_poll_rx, - .peek_rx = &emac_peek_rx, - .rxde = &emac_rxde, -}; +static void emac_set_multicast_list(struct net_device *dev) +{ + struct ocp_enet_private *fep = dev->priv; -static struct mal_commac_ops emac_commac_sg_ops = { - .poll_tx = &emac_poll_tx, - .poll_rx = &emac_poll_rx, - .peek_rx = &emac_peek_rx_sg, - .rxde = &emac_rxde, -}; + spin_lock_irq(&fep->lock); + __emac_set_multicast_list(dev); + spin_unlock_irq(&fep->lock); +} -/* Ethtool support */ -static int emac_ethtool_get_settings(struct net_device *ndev, - struct ethtool_cmd *cmd) +static int emac_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) { - struct ocp_enet_private *dev = ndev->priv; + struct ocp_enet_private *fep = ndev->priv; - cmd->supported = dev->phy.features; + cmd->supported = fep->phy_mii.def->features; cmd->port = PORT_MII; - cmd->phy_address = dev->phy.address; - cmd->transceiver = - dev->phy.address >= 0 ? XCVR_EXTERNAL : XCVR_INTERNAL; - - local_bh_disable(); - cmd->advertising = dev->phy.advertising; - cmd->autoneg = dev->phy.autoneg; - cmd->speed = dev->phy.speed; - cmd->duplex = dev->phy.duplex; - local_bh_enable(); - + cmd->transceiver = XCVR_EXTERNAL; + cmd->phy_address = fep->mii_phy_addr; + spin_lock_irq(&fep->lock); + cmd->autoneg = fep->want_autoneg; + cmd->speed = fep->phy_mii.speed; + cmd->duplex = fep->phy_mii.duplex; + spin_unlock_irq(&fep->lock); return 0; } -static int emac_ethtool_set_settings(struct net_device *ndev, - struct ethtool_cmd *cmd) +static int emac_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) { - struct ocp_enet_private *dev = ndev->priv; - u32 f = dev->phy.features; + struct ocp_enet_private *fep = ndev->priv; + unsigned long features = fep->phy_mii.def->features; - DBG("%d: set_settings(%d, %d, %d, 0x%08x)" NL, dev->def->index, - cmd->autoneg, cmd->speed, cmd->duplex, cmd->advertising); + if (!capable(CAP_NET_ADMIN)) + return -EPERM; - /* Basic sanity checks */ - if (dev->phy.address < 0) - return -EOPNOTSUPP; if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE) return -EINVAL; if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0) return -EINVAL; if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) return -EINVAL; - - if (cmd->autoneg == AUTONEG_DISABLE) { + if (cmd->autoneg == AUTONEG_DISABLE) switch (cmd->speed) { case SPEED_10: - if (cmd->duplex == DUPLEX_HALF - && !(f & SUPPORTED_10baseT_Half)) + if (cmd->duplex == DUPLEX_HALF && + (features & SUPPORTED_10baseT_Half) == 0) return -EINVAL; - if (cmd->duplex == DUPLEX_FULL - && !(f & SUPPORTED_10baseT_Full)) + if (cmd->duplex == DUPLEX_FULL && + (features & SUPPORTED_10baseT_Full) == 0) return -EINVAL; break; case SPEED_100: - if (cmd->duplex == DUPLEX_HALF - && !(f & SUPPORTED_100baseT_Half)) + if (cmd->duplex == DUPLEX_HALF && + (features & SUPPORTED_100baseT_Half) == 0) return -EINVAL; - if (cmd->duplex == DUPLEX_FULL - && !(f & SUPPORTED_100baseT_Full)) + if (cmd->duplex == DUPLEX_FULL && + (features & SUPPORTED_100baseT_Full) == 0) return -EINVAL; break; case SPEED_1000: - if (cmd->duplex == DUPLEX_HALF - && !(f & SUPPORTED_1000baseT_Half)) + if (cmd->duplex == DUPLEX_HALF && + (features & SUPPORTED_1000baseT_Half) == 0) return -EINVAL; - if (cmd->duplex == DUPLEX_FULL - && !(f & SUPPORTED_1000baseT_Full)) + if (cmd->duplex == DUPLEX_FULL && + (features & SUPPORTED_1000baseT_Full) == 0) return -EINVAL; break; default: return -EINVAL; - } - - local_bh_disable(); - dev->phy.def->ops->setup_forced(&dev->phy, cmd->speed, - cmd->duplex); - - } else { - if (!(f & SUPPORTED_Autoneg)) - return -EINVAL; - - local_bh_disable(); - dev->phy.def->ops->setup_aneg(&dev->phy, - (cmd->advertising & f) | - (dev->phy.advertising & - (ADVERTISED_Pause | - ADVERTISED_Asym_Pause))); - } - emac_force_link_update(dev); - local_bh_enable(); - + } else if ((features & SUPPORTED_Autoneg) == 0) + return -EINVAL; + spin_lock_irq(&fep->lock); + emac_start_link(fep, cmd); + spin_unlock_irq(&fep->lock); return 0; } -static void emac_ethtool_get_ringparam(struct net_device *ndev, - struct ethtool_ringparam *rp) +static void +emac_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) { - rp->rx_max_pending = rp->rx_pending = NUM_RX_BUFF; - rp->tx_max_pending = rp->tx_pending = NUM_TX_BUFF; -} + struct ocp_enet_private *fep = ndev->priv; -static void emac_ethtool_get_pauseparam(struct net_device *ndev, - struct ethtool_pauseparam *pp) -{ - struct ocp_enet_private *dev = ndev->priv; - - local_bh_disable(); - if ((dev->phy.features & SUPPORTED_Autoneg) && - (dev->phy.advertising & (ADVERTISED_Pause | ADVERTISED_Asym_Pause))) - pp->autoneg = 1; - - if (dev->phy.duplex == DUPLEX_FULL) { - if (dev->phy.pause) - pp->rx_pause = pp->tx_pause = 1; - else if (dev->phy.asym_pause) - pp->tx_pause = 1; - } - local_bh_enable(); + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + info->fw_version[0] = '\0'; + sprintf(info->bus_info, "IBM EMAC %d", fep->ocpdev->def->index); + info->regdump_len = 0; } -static u32 emac_ethtool_get_rx_csum(struct net_device *ndev) +static int emac_nway_reset(struct net_device *ndev) { - struct ocp_enet_private *dev = ndev->priv; - return dev->tah_dev != 0; -} + struct ocp_enet_private *fep = ndev->priv; -static int emac_get_regs_len(struct ocp_enet_private *dev) -{ - return sizeof(struct emac_ethtool_regs_subhdr) + EMAC_ETHTOOL_REGS_SIZE; + if (!fep->want_autoneg) + return -EINVAL; + spin_lock_irq(&fep->lock); + emac_start_link(fep, NULL); + spin_unlock_irq(&fep->lock); + return 0; } -static int emac_ethtool_get_regs_len(struct net_device *ndev) +static u32 emac_get_link(struct net_device *ndev) { - struct ocp_enet_private *dev = ndev->priv; - return sizeof(struct emac_ethtool_regs_hdr) + - emac_get_regs_len(dev) + mal_get_regs_len(dev->mal) + - zmii_get_regs_len(dev->zmii_dev) + - rgmii_get_regs_len(dev->rgmii_dev) + - tah_get_regs_len(dev->tah_dev); + return netif_carrier_ok(ndev); } -static void *emac_dump_regs(struct ocp_enet_private *dev, void *buf) +static struct ethtool_ops emac_ethtool_ops = { + .get_settings = emac_get_settings, + .set_settings = emac_set_settings, + .get_drvinfo = emac_get_drvinfo, + .nway_reset = emac_nway_reset, + .get_link = emac_get_link +}; + +static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct emac_ethtool_regs_subhdr *hdr = buf; + struct ocp_enet_private *fep = dev->priv; + uint16_t *data = (uint16_t *) & rq->ifr_ifru; - hdr->version = EMAC_ETHTOOL_REGS_VER; - hdr->index = dev->def->index; - memcpy_fromio(hdr + 1, dev->emacp, EMAC_ETHTOOL_REGS_SIZE); - return ((void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE); -} + switch (cmd) { + case SIOCGMIIPHY: + data[0] = fep->mii_phy_addr; + /* Fall through */ + case SIOCGMIIREG: + data[3] = emac_phy_read(dev, fep->mii_phy_addr, data[1]); + return 0; + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; -static void emac_ethtool_get_regs(struct net_device *ndev, - struct ethtool_regs *regs, void *buf) -{ - struct ocp_enet_private *dev = ndev->priv; - struct emac_ethtool_regs_hdr *hdr = buf; - - hdr->components = 0; - buf = hdr + 1; - - local_irq_disable(); - buf = mal_dump_regs(dev->mal, buf); - buf = emac_dump_regs(dev, buf); - if (dev->zmii_dev) { - hdr->components |= EMAC_ETHTOOL_REGS_ZMII; - buf = zmii_dump_regs(dev->zmii_dev, buf); - } - if (dev->rgmii_dev) { - hdr->components |= EMAC_ETHTOOL_REGS_RGMII; - buf = rgmii_dump_regs(dev->rgmii_dev, buf); - } - if (dev->tah_dev) { - hdr->components |= EMAC_ETHTOOL_REGS_TAH; - buf = tah_dump_regs(dev->tah_dev, buf); + emac_phy_write(dev, fep->mii_phy_addr, data[1], data[2]); + return 0; + default: + return -EOPNOTSUPP; } - local_irq_enable(); } -static int emac_ethtool_nway_reset(struct net_device *ndev) +static int emac_open(struct net_device *dev) { - struct ocp_enet_private *dev = ndev->priv; - int res = 0; - - DBG("%d: nway_reset" NL, dev->def->index); + struct ocp_enet_private *fep = dev->priv; + int rc; - if (dev->phy.address < 0) - return -EOPNOTSUPP; - - local_bh_disable(); - if (!dev->phy.autoneg) { - res = -EINVAL; - goto out; - } + spin_lock_irq(&fep->lock); - dev->phy.def->ops->setup_aneg(&dev->phy, dev->phy.advertising); - emac_force_link_update(dev); + fep->opened = 1; + netif_carrier_off(dev); - out: - local_bh_enable(); - return res; -} + /* Reset & configure the chip */ + emac_reset_configure(fep); -static int emac_ethtool_get_stats_count(struct net_device *ndev) -{ - return EMAC_ETHTOOL_STATS_COUNT; -} + spin_unlock_irq(&fep->lock); -static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset, - u8 * buf) -{ - if (stringset == ETH_SS_STATS) - memcpy(buf, &emac_stats_keys, sizeof(emac_stats_keys)); -} + /* Request our interrupt lines */ + rc = request_irq(dev->irq, emac_mac_irq, 0, "IBM EMAC MAC", dev); + if (rc != 0) { + printk("dev->irq %d failed\n", dev->irq); + goto bail; + } + /* Kick the chip rx & tx channels into life */ + spin_lock_irq(&fep->lock); + emac_kick(fep); + spin_unlock_irq(&fep->lock); -static void emac_ethtool_get_ethtool_stats(struct net_device *ndev, - struct ethtool_stats *estats, - u64 * tmp_stats) -{ - struct ocp_enet_private *dev = ndev->priv; - local_irq_disable(); - memcpy(tmp_stats, &dev->stats, sizeof(dev->stats)); - tmp_stats += sizeof(dev->stats) / sizeof(u64); - memcpy(tmp_stats, &dev->estats, sizeof(dev->estats)); - local_irq_enable(); + netif_start_queue(dev); + bail: + return rc; } -static void emac_ethtool_get_drvinfo(struct net_device *ndev, - struct ethtool_drvinfo *info) +static int emac_close(struct net_device *dev) { - struct ocp_enet_private *dev = ndev->priv; + struct ocp_enet_private *fep = dev->priv; + emac_t *emacp = fep->emacp; - strcpy(info->driver, "ibm_emac"); - strcpy(info->version, DRV_VERSION); - info->fw_version[0] = '\0'; - sprintf(info->bus_info, "PPC 4xx EMAC %d", dev->def->index); - info->n_stats = emac_ethtool_get_stats_count(ndev); - info->regdump_len = emac_ethtool_get_regs_len(ndev); -} - -static struct ethtool_ops emac_ethtool_ops = { - .get_settings = emac_ethtool_get_settings, - .set_settings = emac_ethtool_set_settings, - .get_drvinfo = emac_ethtool_get_drvinfo, + /* XXX Stop IRQ emitting here */ + spin_lock_irq(&fep->lock); + fep->opened = 0; + mal_disable_tx_channels(fep->mal, fep->commac.tx_chan_mask); + mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask); + netif_carrier_off(dev); + netif_stop_queue(dev); - .get_regs_len = emac_ethtool_get_regs_len, - .get_regs = emac_ethtool_get_regs, + /* + * Check for a link, some PHYs don't provide a clock if + * no link is present. Some EMACs will not come out of + * soft reset without a PHY clock present. + */ + if (fep->phy_mii.def->ops->poll_link(&fep->phy_mii)) { + out_be32(&emacp->em0mr0, EMAC_M0_SRST); + udelay(10); - .nway_reset = emac_ethtool_nway_reset, + if (emacp->em0mr0 & EMAC_M0_SRST) { + /*not sure what to do here hopefully it clears before another open */ + printk(KERN_ERR + "%s: Phy SoftReset didn't clear, no link?\n", + dev->name); + } + } - .get_ringparam = emac_ethtool_get_ringparam, - .get_pauseparam = emac_ethtool_get_pauseparam, + /* Free the irq's */ + free_irq(dev->irq, dev); - .get_rx_csum = emac_ethtool_get_rx_csum, + spin_unlock_irq(&fep->lock); - .get_strings = emac_ethtool_get_strings, - .get_stats_count = emac_ethtool_get_stats_count, - .get_ethtool_stats = emac_ethtool_get_ethtool_stats, + return 0; +} - .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, +static void emac_remove(struct ocp_device *ocpdev) +{ + struct net_device *dev = ocp_get_drvdata(ocpdev); + struct ocp_enet_private *ep = dev->priv; + + /* FIXME: locking, races, ... */ + ep->going_away = 1; + ocp_set_drvdata(ocpdev, NULL); + if (ep->rgmii_dev) + emac_close_rgmii(ep->rgmii_dev); + if (ep->zmii_dev) + emac_close_zmii(ep->zmii_dev); + + unregister_netdev(dev); + del_timer_sync(&ep->link_timer); + mal_unregister_commac(ep->mal, &ep->commac); + iounmap((void *)ep->emacp); + kfree(dev); +} + +struct mal_commac_ops emac_commac_ops = { + .txeob = &emac_txeob_dev, + .txde = &emac_txde_dev, + .rxeob = &emac_rxeob_dev, + .rxde = &emac_rxde_dev, }; -static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) +#ifdef CONFIG_NET_POLL_CONTROLLER +static void emac_netpoll(struct net_device *ndev) { - struct ocp_enet_private *dev = ndev->priv; - uint16_t *data = (uint16_t *) & rq->ifr_ifru; - - DBG("%d: ioctl %08x" NL, dev->def->index, cmd); - - if (dev->phy.address < 0) - return -EOPNOTSUPP; - - switch (cmd) { - case SIOCGMIIPHY: - case SIOCDEVPRIVATE: - data[0] = dev->phy.address; - /* Fall through */ - case SIOCGMIIREG: - case SIOCDEVPRIVATE + 1: - data[3] = emac_mdio_read(ndev, dev->phy.address, data[1]); - return 0; - - case SIOCSMIIREG: - case SIOCDEVPRIVATE + 2: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - emac_mdio_write(ndev, dev->phy.address, data[1], data[2]); - return 0; - default: - return -EOPNOTSUPP; - } + emac_rxeob_dev((void *)ndev, 0); + emac_txeob_dev((void *)ndev, 0); } +#endif -static int __init emac_probe(struct ocp_device *ocpdev) +static int emac_init_device(struct ocp_device *ocpdev, struct ibm_ocp_mal *mal) { - struct ocp_func_emac_data *emacdata = ocpdev->def->additions; + int deferred_init = 0; + int rc = 0, i; struct net_device *ndev; - struct ocp_device *maldev; - struct ocp_enet_private *dev; - int err, i; - - DBG("%d: probe" NL, ocpdev->def->index); + struct ocp_enet_private *ep; + struct ocp_func_emac_data *emacdata; + int commac_reg = 0; + u32 phy_map; + emacdata = (struct ocp_func_emac_data *)ocpdev->def->additions; if (!emacdata) { printk(KERN_ERR "emac%d: Missing additional data!\n", ocpdev->def->index); @@ -1936,312 +1738,304 @@ static int __init emac_probe(struct ocp_device *ocpdev) /* Allocate our net_device structure */ ndev = alloc_etherdev(sizeof(struct ocp_enet_private)); - if (!ndev) { - printk(KERN_ERR "emac%d: could not allocate ethernet device!\n", + if (ndev == NULL) { + printk(KERN_ERR + "emac%d: Could not allocate ethernet device.\n", ocpdev->def->index); return -ENOMEM; } - dev = ndev->priv; - dev->ndev = ndev; - dev->ldev = &ocpdev->dev; - dev->def = ocpdev->def; - SET_MODULE_OWNER(ndev); - - /* Find MAL device we are connected to */ - maldev = - ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_MAL, emacdata->mal_idx); - if (!maldev) { - printk(KERN_ERR "emac%d: unknown mal%d device!\n", - dev->def->index, emacdata->mal_idx); - err = -ENODEV; - goto out; - } - dev->mal = ocp_get_drvdata(maldev); - if (!dev->mal) { - printk(KERN_ERR "emac%d: mal%d hasn't been initialized yet!\n", - dev->def->index, emacdata->mal_idx); - err = -ENODEV; - goto out; - } - - /* Register with MAL */ - dev->commac.ops = &emac_commac_ops; - dev->commac.dev = dev; - dev->commac.tx_chan_mask = MAL_CHAN_MASK(emacdata->mal_tx_chan); - dev->commac.rx_chan_mask = MAL_CHAN_MASK(emacdata->mal_rx_chan); - err = mal_register_commac(dev->mal, &dev->commac); - if (err) { - printk(KERN_ERR "emac%d: failed to register with mal%d!\n", - dev->def->index, emacdata->mal_idx); - goto out; - } - dev->rx_skb_size = emac_rx_skb_size(ndev->mtu); - dev->rx_sync_size = emac_rx_sync_size(ndev->mtu); - - /* Get pointers to BD rings */ - dev->tx_desc = - dev->mal->bd_virt + mal_tx_bd_offset(dev->mal, - emacdata->mal_tx_chan); - dev->rx_desc = - dev->mal->bd_virt + mal_rx_bd_offset(dev->mal, - emacdata->mal_rx_chan); - - DBG("%d: tx_desc %p" NL, ocpdev->def->index, dev->tx_desc); - DBG("%d: rx_desc %p" NL, ocpdev->def->index, dev->rx_desc); - - /* Clean rings */ - memset(dev->tx_desc, 0, NUM_TX_BUFF * sizeof(struct mal_descriptor)); - memset(dev->rx_desc, 0, NUM_RX_BUFF * sizeof(struct mal_descriptor)); - - /* If we depend on another EMAC for MDIO, check whether it was probed already */ - if (emacdata->mdio_idx >= 0 && emacdata->mdio_idx != ocpdev->def->index) { - struct ocp_device *mdiodev = - ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, - emacdata->mdio_idx); - if (!mdiodev) { - printk(KERN_ERR "emac%d: unknown emac%d device!\n", - dev->def->index, emacdata->mdio_idx); - err = -ENODEV; - goto out2; - } - dev->mdio_dev = ocp_get_drvdata(mdiodev); - if (!dev->mdio_dev) { - printk(KERN_ERR - "emac%d: emac%d hasn't been initialized yet!\n", - dev->def->index, emacdata->mdio_idx); - err = -ENODEV; - goto out2; + ep = ndev->priv; + ep->ndev = ndev; + ep->ocpdev = ocpdev; + ndev->irq = ocpdev->def->irq; + ep->wol_irq = emacdata->wol_irq; + if (emacdata->mdio_idx >= 0) { + if (emacdata->mdio_idx == ocpdev->def->index) { + /* Set the common MDIO net_device */ + mdio_ndev = ndev; + deferred_init = 1; } + ep->mdio_dev = mdio_ndev; + } else { + ep->mdio_dev = ndev; } - /* Attach to ZMII, if needed */ - if ((err = zmii_attach(dev)) != 0) - goto out2; - - /* Attach to RGMII, if needed */ - if ((err = rgmii_attach(dev)) != 0) - goto out3; - - /* Attach to TAH, if needed */ - if ((err = tah_attach(dev)) != 0) - goto out4; - - /* Map EMAC regs */ - dev->emacp = - (struct emac_regs *)ioremap(dev->def->paddr, - sizeof(struct emac_regs)); - if (!dev->emacp) { - printk(KERN_ERR "emac%d: could not ioremap device registers!\n", - dev->def->index); - err = -ENOMEM; - goto out5; + ocp_set_drvdata(ocpdev, ndev); + + spin_lock_init(&ep->lock); + + /* Fill out MAL informations and register commac */ + ep->mal = mal; + ep->mal_tx_chan = emacdata->mal_tx_chan; + ep->mal_rx_chan = emacdata->mal_rx_chan; + ep->commac.ops = &emac_commac_ops; + ep->commac.dev = ndev; + ep->commac.tx_chan_mask = MAL_CHAN_MASK(ep->mal_tx_chan); + ep->commac.rx_chan_mask = MAL_CHAN_MASK(ep->mal_rx_chan); + rc = mal_register_commac(ep->mal, &ep->commac); + if (rc != 0) + goto bail; + commac_reg = 1; + + /* Map our MMIOs */ + ep->emacp = (emac_t *) ioremap(ocpdev->def->paddr, sizeof(emac_t)); + + /* Check if we need to attach to a ZMII */ + if (emacdata->zmii_idx >= 0) { + ep->zmii_input = emacdata->zmii_mux; + ep->zmii_dev = + ocp_find_device(OCP_ANY_ID, OCP_FUNC_ZMII, + emacdata->zmii_idx); + if (ep->zmii_dev == NULL) + printk(KERN_WARNING + "emac%d: ZMII %d requested but not found !\n", + ocpdev->def->index, emacdata->zmii_idx); + else if ((rc = + emac_init_zmii(ep->zmii_dev, ep->zmii_input, + emacdata->phy_mode)) != 0) + goto bail; } - /* Fill in MAC address */ - for (i = 0; i < 6; ++i) - ndev->dev_addr[i] = emacdata->mac_addr[i]; - - /* Set some link defaults before we can find out real parameters */ - dev->phy.speed = SPEED_100; - dev->phy.duplex = DUPLEX_FULL; - dev->phy.autoneg = AUTONEG_DISABLE; - dev->phy.pause = dev->phy.asym_pause = 0; - init_timer(&dev->link_timer); - dev->link_timer.function = emac_link_timer; - dev->link_timer.data = (unsigned long)dev; - - /* Find PHY if any */ - dev->phy.dev = ndev; - dev->phy.mode = emacdata->phy_mode; - if (emacdata->phy_map != 0xffffffff) { - u32 phy_map = emacdata->phy_map | busy_phy_map; - u32 adv; - - DBG("%d: PHY maps %08x %08x" NL, dev->def->index, - emacdata->phy_map, busy_phy_map); + /* Check if we need to attach to a RGMII */ + if (emacdata->rgmii_idx >= 0) { + ep->rgmii_input = emacdata->rgmii_mux; + ep->rgmii_dev = + ocp_find_device(OCP_ANY_ID, OCP_FUNC_RGMII, + emacdata->rgmii_idx); + if (ep->rgmii_dev == NULL) + printk(KERN_WARNING + "emac%d: RGMII %d requested but not found !\n", + ocpdev->def->index, emacdata->rgmii_idx); + else if ((rc = + emac_init_rgmii(ep->rgmii_dev, ep->rgmii_input, + emacdata->phy_mode)) != 0) + goto bail; + } - EMAC_RX_CLK_TX(dev->def->index); + /* Check if we need to attach to a TAH */ + if (emacdata->tah_idx >= 0) { + ep->tah_dev = + ocp_find_device(OCP_ANY_ID, OCP_FUNC_TAH, + emacdata->tah_idx); + if (ep->tah_dev == NULL) + printk(KERN_WARNING + "emac%d: TAH %d requested but not found !\n", + ocpdev->def->index, emacdata->tah_idx); + else if ((rc = emac_init_tah(ep)) != 0) + goto bail; + } - dev->phy.mdio_read = emac_mdio_read; - dev->phy.mdio_write = emac_mdio_write; + if (deferred_init) { + if (!list_empty(&emac_init_list)) { + struct list_head *entry; + struct emac_def_dev *ddev; - /* Configure EMAC with defaults so we can at least use MDIO - * This is needed mostly for 440GX - */ - if (emac_phy_gpcs(dev->phy.mode)) { - /* XXX - * Make GPCS PHY address equal to EMAC index. - * We probably should take into account busy_phy_map - * and/or phy_map here. - */ - dev->phy.address = dev->def->index; + list_for_each(entry, &emac_init_list) { + ddev = + list_entry(entry, struct emac_def_dev, + link); + emac_init_device(ddev->ocpdev, ddev->mal); + } } - - emac_configure(dev); - - for (i = 0; i < 0x20; phy_map >>= 1, ++i) - if (!(phy_map & 1)) { - int r; - busy_phy_map |= 1 << i; + } - /* Quick check if there is a PHY at the address */ - r = emac_mdio_read(dev->ndev, i, MII_BMCR); - if (r == 0xffff || r < 0) - continue; - if (!mii_phy_probe(&dev->phy, i)) - break; - } - if (i == 0x20) { - printk(KERN_WARNING "emac%d: can't find PHY!\n", - dev->def->index); - goto out6; + /* Init link monitoring timer */ + init_timer(&ep->link_timer); + ep->link_timer.function = emac_link_timer; + ep->link_timer.data = (unsigned long)ep; + ep->timer_ticks = 0; + + /* Fill up the mii_phy structure */ + ep->phy_mii.dev = ndev; + ep->phy_mii.mdio_read = emac_phy_read; + ep->phy_mii.mdio_write = emac_phy_write; + ep->phy_mii.mode = emacdata->phy_mode; + + /* Find PHY */ + phy_map = emacdata->phy_map | busy_phy_map; + for (i = 0; i <= 0x1f; i++, phy_map >>= 1) { + if ((phy_map & 0x1) == 0) { + int val = emac_phy_read(ndev, i, MII_BMCR); + if (val != 0xffff && val != -1) + break; } + } + if (i == 0x20) { + printk(KERN_WARNING "emac%d: Can't find PHY.\n", + ocpdev->def->index); + rc = -ENODEV; + goto bail; + } + busy_phy_map |= 1 << i; + ep->mii_phy_addr = i; + rc = mii_phy_probe(&ep->phy_mii, i); + if (rc) { + printk(KERN_WARNING "emac%d: Failed to probe PHY type.\n", + ocpdev->def->index); + rc = -ENODEV; + goto bail; + } + + /* Disable any PHY features not supported by the platform */ + ep->phy_mii.def->features &= ~emacdata->phy_feat_exc; - /* Init PHY */ - if (dev->phy.def->ops->init) - dev->phy.def->ops->init(&dev->phy); + /* Setup initial PHY config & startup aneg */ + if (ep->phy_mii.def->ops->init) + ep->phy_mii.def->ops->init(&ep->phy_mii); + netif_carrier_off(ndev); + if (ep->phy_mii.def->features & SUPPORTED_Autoneg) + ep->want_autoneg = 1; + else { + ep->want_autoneg = 0; - /* Disable any PHY features not supported by the platform */ - dev->phy.def->features &= ~emacdata->phy_feat_exc; - - /* Setup initial link parameters */ - if (dev->phy.features & SUPPORTED_Autoneg) { - adv = dev->phy.features; -#if !defined(CONFIG_40x) - adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; -#endif - /* Restart autonegotiation */ - dev->phy.def->ops->setup_aneg(&dev->phy, adv); + /* Select highest supported speed/duplex */ + if (ep->phy_mii.def->features & SUPPORTED_1000baseT_Full) { + ep->phy_mii.speed = SPEED_1000; + ep->phy_mii.duplex = DUPLEX_FULL; + } else if (ep->phy_mii.def->features & + SUPPORTED_1000baseT_Half) { + ep->phy_mii.speed = SPEED_1000; + ep->phy_mii.duplex = DUPLEX_HALF; + } else if (ep->phy_mii.def->features & + SUPPORTED_100baseT_Full) { + ep->phy_mii.speed = SPEED_100; + ep->phy_mii.duplex = DUPLEX_FULL; + } else if (ep->phy_mii.def->features & + SUPPORTED_100baseT_Half) { + ep->phy_mii.speed = SPEED_100; + ep->phy_mii.duplex = DUPLEX_HALF; + } else if (ep->phy_mii.def->features & + SUPPORTED_10baseT_Full) { + ep->phy_mii.speed = SPEED_10; + ep->phy_mii.duplex = DUPLEX_FULL; } else { - u32 f = dev->phy.def->features; - int speed = SPEED_10, fd = DUPLEX_HALF; - - /* Select highest supported speed/duplex */ - if (f & SUPPORTED_1000baseT_Full) { - speed = SPEED_1000; - fd = DUPLEX_FULL; - } else if (f & SUPPORTED_1000baseT_Half) - speed = SPEED_1000; - else if (f & SUPPORTED_100baseT_Full) { - speed = SPEED_100; - fd = DUPLEX_FULL; - } else if (f & SUPPORTED_100baseT_Half) - speed = SPEED_100; - else if (f & SUPPORTED_10baseT_Full) - fd = DUPLEX_FULL; - - /* Force link parameters */ - dev->phy.def->ops->setup_forced(&dev->phy, speed, fd); + ep->phy_mii.speed = SPEED_10; + ep->phy_mii.duplex = DUPLEX_HALF; } - } else { - emac_reset(dev); - - /* PHY-less configuration. - * XXX I probably should move these settings to emacdata - */ - dev->phy.address = -1; - dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII; - dev->phy.pause = 1; } + emac_start_link(ep, NULL); + + /* read the MAC Address */ + for (i = 0; i < 6; i++) + ndev->dev_addr[i] = emacdata->mac_addr[i]; /* Fill in the driver function table */ ndev->open = &emac_open; - if (dev->tah_dev) { - ndev->hard_start_xmit = &emac_start_xmit_sg; - ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - } else - ndev->hard_start_xmit = &emac_start_xmit; - ndev->tx_timeout = &emac_full_tx_reset; - ndev->watchdog_timeo = 5 * HZ; + ndev->hard_start_xmit = &emac_start_xmit; ndev->stop = &emac_close; ndev->get_stats = &emac_stats; + if (emacdata->jumbo) + ndev->change_mtu = &emac_change_mtu; + ndev->set_mac_address = &emac_set_mac_address; ndev->set_multicast_list = &emac_set_multicast_list; ndev->do_ioctl = &emac_ioctl; - if (emac_phy_supports_gige(emacdata->phy_mode)) { - ndev->change_mtu = &emac_change_mtu; - dev->commac.ops = &emac_commac_sg_ops; - } SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops); + if (emacdata->tah_idx >= 0) + ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG; +#ifdef CONFIG_NET_POLL_CONTROLLER + ndev->poll_controller = emac_netpoll; +#endif - netif_carrier_off(ndev); - netif_stop_queue(ndev); - - err = register_netdev(ndev); - if (err) { - printk(KERN_ERR "emac%d: failed to register net device (%d)!\n", - dev->def->index, err); - goto out6; - } + SET_MODULE_OWNER(ndev); - ocp_set_drvdata(ocpdev, dev); + rc = register_netdev(ndev); + if (rc != 0) + goto bail; - printk("%s: emac%d, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - ndev->name, dev->def->index, + printk("%s: IBM emac, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + ndev->name, ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + printk(KERN_INFO "%s: Found %s PHY (0x%02x)\n", + ndev->name, ep->phy_mii.def->name, ep->mii_phy_addr); + + bail: + if (rc && commac_reg) + mal_unregister_commac(ep->mal, &ep->commac); + if (rc && ndev) + kfree(ndev); + + return rc; +} + +static int emac_probe(struct ocp_device *ocpdev) +{ + struct ocp_device *maldev; + struct ibm_ocp_mal *mal; + struct ocp_func_emac_data *emacdata; + + emacdata = (struct ocp_func_emac_data *)ocpdev->def->additions; + if (emacdata == NULL) { + printk(KERN_ERR "emac%d: Missing additional datas !\n", + ocpdev->def->index); + return -ENODEV; + } - if (dev->phy.address >= 0) - printk("%s: found %s PHY (0x%02x)\n", ndev->name, - dev->phy.def->name, dev->phy.address); + /* Get the MAL device */ + maldev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_MAL, emacdata->mal_idx); + if (maldev == NULL) { + printk("No maldev\n"); + return -ENODEV; + } + /* + * Get MAL driver data, it must be here due to link order. + * When the driver is modularized, symbol dependencies will + * ensure the MAL driver is already present if built as a + * module. + */ + mal = (struct ibm_ocp_mal *)ocp_get_drvdata(maldev); + if (mal == NULL) { + printk("No maldrv\n"); + return -ENODEV; + } - emac_dbg_register(dev->def->index, dev); + /* If we depend on another EMAC for MDIO, wait for it to show up */ + if (emacdata->mdio_idx >= 0 && + (emacdata->mdio_idx != ocpdev->def->index) && !mdio_ndev) { + struct emac_def_dev *ddev; + /* Add this index to the deferred init table */ + ddev = kmalloc(sizeof(struct emac_def_dev), GFP_KERNEL); + ddev->ocpdev = ocpdev; + ddev->mal = mal; + list_add_tail(&ddev->link, &emac_init_list); + } else { + emac_init_device(ocpdev, mal); + } return 0; - out6: - iounmap((void *)dev->emacp); - out5: - tah_fini(dev->tah_dev); - out4: - rgmii_fini(dev->rgmii_dev, dev->rgmii_input); - out3: - zmii_fini(dev->zmii_dev, dev->zmii_input); - out2: - mal_unregister_commac(dev->mal, &dev->commac); - out: - kfree(ndev); - return err; } +/* Structure for a device driver */ static struct ocp_device_id emac_ids[] = { - { .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_EMAC }, - { .vendor = OCP_VENDOR_INVALID} + {.vendor = OCP_ANY_ID,.function = OCP_FUNC_EMAC}, + {.vendor = OCP_VENDOR_INVALID} }; static struct ocp_driver emac_driver = { .name = "emac", .id_table = emac_ids, + .probe = emac_probe, .remove = emac_remove, }; static int __init emac_init(void) { - printk(KERN_INFO DRV_DESC ", version " DRV_VERSION "\n"); - - DBG(": init" NL); + printk(KERN_INFO DRV_NAME ": " DRV_DESC ", version " DRV_VERSION "\n"); + printk(KERN_INFO "Maintained by " DRV_AUTHOR "\n"); - if (mal_init()) - return -ENODEV; - - EMAC_CLK_INTERNAL; - if (ocp_register_driver(&emac_driver)) { - EMAC_CLK_EXTERNAL; - ocp_unregister_driver(&emac_driver); - mal_exit(); - return -ENODEV; + if (skb_res > 2) { + printk(KERN_WARNING "Invalid skb_res: %d, cropping to 2\n", + skb_res); + skb_res = 2; } - EMAC_CLK_EXTERNAL; - emac_init_debug(); - return 0; + return ocp_register_driver(&emac_driver); } static void __exit emac_exit(void) { - DBG(": exit" NL); ocp_unregister_driver(&emac_driver); - mal_exit(); - emac_fini_debug(); } module_init(emac_init); diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_core.h b/trunk/drivers/net/ibm_emac/ibm_emac_core.h index e9b44d030ac3..97e6e1ea8c89 100644 --- a/trunk/drivers/net/ibm_emac/ibm_emac_core.h +++ b/trunk/drivers/net/ibm_emac/ibm_emac_core.h @@ -1,221 +1,146 @@ /* - * drivers/net/ibm_emac/ibm_emac_core.h + * ibm_emac_core.h * - * Driver for PowerPC 4xx on-chip ethernet controller. + * Ethernet driver for the built in ethernet on the IBM 405 PowerPC + * processor. * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin or + * Armin Kuster akuster@mvista.com + * Sept, 2001 * - * Based on original work by - * Armin Kuster - * Johnnie Peters - * Copyright 2000, 2001 MontaVista Softare Inc. + * Orignial driver + * Johnnie Peters + * jpeters@mvista.com + * + * Copyright 2000 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. - * */ -#ifndef __IBM_EMAC_CORE_H_ -#define __IBM_EMAC_CORE_H_ -#include +#ifndef _IBM_EMAC_CORE_H_ +#define _IBM_EMAC_CORE_H_ + #include -#include #include +#include /* For phys_addr_t */ #include "ibm_emac.h" #include "ibm_emac_phy.h" -#include "ibm_emac_zmii.h" #include "ibm_emac_rgmii.h" +#include "ibm_emac_zmii.h" #include "ibm_emac_mal.h" #include "ibm_emac_tah.h" -#define NUM_TX_BUFF CONFIG_IBM_EMAC_TXB -#define NUM_RX_BUFF CONFIG_IBM_EMAC_RXB - -/* Simple sanity check */ -#if NUM_TX_BUFF > 256 || NUM_RX_BUFF > 256 -#error Invalid number of buffer descriptors (greater than 256) +#ifndef CONFIG_IBM_EMAC_TXB +#define NUM_TX_BUFF 64 +#define NUM_RX_BUFF 64 +#else +#define NUM_TX_BUFF CONFIG_IBM_EMAC_TXB +#define NUM_RX_BUFF CONFIG_IBM_EMAC_RXB #endif -// XXX -#define EMAC_MIN_MTU 46 -#define EMAC_MAX_MTU 9000 - -/* Maximum L2 header length (VLAN tagged, no FCS) */ -#define EMAC_MTU_OVERHEAD (6 * 2 + 2 + 4) - -/* RX BD size for the given MTU */ -static inline int emac_rx_size(int mtu) -{ - if (mtu > ETH_DATA_LEN) - return MAL_MAX_RX_SIZE; - else - return mal_rx_size(ETH_DATA_LEN + EMAC_MTU_OVERHEAD); -} - -#define EMAC_DMA_ALIGN(x) ALIGN((x), dma_get_cache_alignment()) - -#define EMAC_RX_SKB_HEADROOM \ - EMAC_DMA_ALIGN(CONFIG_IBM_EMAC_RX_SKB_HEADROOM) - -/* Size of RX skb for the given MTU */ -static inline int emac_rx_skb_size(int mtu) -{ - int size = max(mtu + EMAC_MTU_OVERHEAD, emac_rx_size(mtu)); - return EMAC_DMA_ALIGN(size + 2) + EMAC_RX_SKB_HEADROOM; -} - -/* RX DMA sync size */ -static inline int emac_rx_sync_size(int mtu) -{ - return EMAC_DMA_ALIGN(emac_rx_size(mtu) + 2); -} - -/* Driver statistcs is split into two parts to make it more cache friendly: - * - normal statistics (packet count, etc) - * - error statistics - * - * When statistics is requested by ethtool, these parts are concatenated, - * normal one goes first. - * - * Please, keep these structures in sync with emac_stats_keys. +/* This does 16 byte alignment, exactly what we need. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. */ +#ifndef CONFIG_IBM_EMAC_SKBRES +#define SKB_RES 2 +#else +#define SKB_RES CONFIG_IBM_EMAC_SKBRES +#endif -/* Normal TX/RX Statistics */ -struct ibm_emac_stats { - u64 rx_packets; - u64 rx_bytes; - u64 tx_packets; - u64 tx_bytes; - u64 rx_packets_csum; - u64 tx_packets_csum; -}; - -/* Error statistics */ -struct ibm_emac_error_stats { - u64 tx_undo; - - /* Software RX Errors */ - u64 rx_dropped_stack; - u64 rx_dropped_oom; - u64 rx_dropped_error; - u64 rx_dropped_resize; - u64 rx_dropped_mtu; - u64 rx_stopped; - /* BD reported RX errors */ - u64 rx_bd_errors; - u64 rx_bd_overrun; - u64 rx_bd_bad_packet; - u64 rx_bd_runt_packet; - u64 rx_bd_short_event; - u64 rx_bd_alignment_error; - u64 rx_bd_bad_fcs; - u64 rx_bd_packet_too_long; - u64 rx_bd_out_of_range; - u64 rx_bd_in_range; - /* EMAC IRQ reported RX errors */ - u64 rx_parity; - u64 rx_fifo_overrun; - u64 rx_overrun; - u64 rx_bad_packet; - u64 rx_runt_packet; - u64 rx_short_event; - u64 rx_alignment_error; - u64 rx_bad_fcs; - u64 rx_packet_too_long; - u64 rx_out_of_range; - u64 rx_in_range; - - /* Software TX Errors */ - u64 tx_dropped; - /* BD reported TX errors */ - u64 tx_bd_errors; - u64 tx_bd_bad_fcs; - u64 tx_bd_carrier_loss; - u64 tx_bd_excessive_deferral; - u64 tx_bd_excessive_collisions; - u64 tx_bd_late_collision; - u64 tx_bd_multple_collisions; - u64 tx_bd_single_collision; - u64 tx_bd_underrun; - u64 tx_bd_sqe; - /* EMAC IRQ reported TX errors */ - u64 tx_parity; - u64 tx_underrun; - u64 tx_sqe; - u64 tx_errors; -}; - -#define EMAC_ETHTOOL_STATS_COUNT ((sizeof(struct ibm_emac_stats) + \ - sizeof(struct ibm_emac_error_stats)) \ - / sizeof(u64)) - -struct ocp_enet_private { - struct net_device *ndev; /* 0 */ - struct emac_regs *emacp; - - struct mal_descriptor *tx_desc; - int tx_cnt; - int tx_slot; - int ack_slot; - - struct mal_descriptor *rx_desc; - int rx_slot; - struct sk_buff *rx_sg_skb; /* 1 */ - int rx_skb_size; - int rx_sync_size; - - struct ibm_emac_stats stats; - struct ocp_device *tah_dev; - - struct ibm_ocp_mal *mal; - struct mal_commac commac; - - struct sk_buff *tx_skb[NUM_TX_BUFF]; - struct sk_buff *rx_skb[NUM_RX_BUFF]; - - struct ocp_device *zmii_dev; - int zmii_input; - struct ocp_enet_private *mdio_dev; - struct ocp_device *rgmii_dev; - int rgmii_input; - - struct ocp_def *def; - - struct mii_phy phy; - struct timer_list link_timer; - int reset_failed; - - struct ibm_emac_error_stats estats; - struct net_device_stats nstats; - - struct device* ldev; -}; - -/* Ethtool get_regs complex data. - * We want to get not just EMAC registers, but also MAL, ZMII, RGMII, TAH - * when available. - * - * Returned BLOB consists of the ibm_emac_ethtool_regs_hdr, - * MAL registers, EMAC registers and optional ZMII, RGMII, TAH registers. - * Each register component is preceded with emac_ethtool_regs_subhdr. - * Order of the optional headers follows their relative bit posititions - * in emac_ethtool_regs_hdr.components +/* Note about alignement. alloc_skb() returns a cache line + * aligned buffer. However, dev_alloc_skb() will add 16 more + * bytes and "reserve" them, so our buffer will actually end + * on a half cache line. What we do is to use directly + * alloc_skb, allocate 16 more bytes to match the total amount + * allocated by dev_alloc_skb(), but we don't reserve. */ -#define EMAC_ETHTOOL_REGS_ZMII 0x00000001 -#define EMAC_ETHTOOL_REGS_RGMII 0x00000002 -#define EMAC_ETHTOOL_REGS_TAH 0x00000004 - -struct emac_ethtool_regs_hdr { - u32 components; -}; +#define MAX_NUM_BUF_DESC 255 +#define DESC_BUF_SIZE 4080 /* max 4096-16 */ +#define DESC_BUF_SIZE_REG (DESC_BUF_SIZE / 16) + +/* Transmitter timeout. */ +#define TX_TIMEOUT (2*HZ) + +/* MDIO latency delay */ +#define MDIO_DELAY 250 + +/* Power managment shift registers */ +#define IBM_CPM_EMMII 0 /* Shift value for MII */ +#define IBM_CPM_EMRX 1 /* Shift value for recv */ +#define IBM_CPM_EMTX 2 /* Shift value for MAC */ +#define IBM_CPM_EMAC(x) (((x)>>IBM_CPM_EMMII) | ((x)>>IBM_CPM_EMRX) | ((x)>>IBM_CPM_EMTX)) + +#define ENET_HEADER_SIZE 14 +#define ENET_FCS_SIZE 4 +#define ENET_DEF_MTU_SIZE 1500 +#define ENET_DEF_BUF_SIZE (ENET_DEF_MTU_SIZE + ENET_HEADER_SIZE + ENET_FCS_SIZE) +#define EMAC_MIN_FRAME 64 +#define EMAC_MAX_FRAME 9018 +#define EMAC_MIN_MTU (EMAC_MIN_FRAME - ENET_HEADER_SIZE - ENET_FCS_SIZE) +#define EMAC_MAX_MTU (EMAC_MAX_FRAME - ENET_HEADER_SIZE - ENET_FCS_SIZE) + +#ifdef CONFIG_IBM_EMAC_ERRMSG +void emac_serr_dump_0(struct net_device *dev); +void emac_serr_dump_1(struct net_device *dev); +void emac_err_dump(struct net_device *dev, int em0isr); +void emac_phy_dump(struct net_device *); +void emac_desc_dump(struct net_device *); +void emac_mac_dump(struct net_device *); +void emac_mal_dump(struct net_device *); +#else +#define emac_serr_dump_0(dev) do { } while (0) +#define emac_serr_dump_1(dev) do { } while (0) +#define emac_err_dump(dev,x) do { } while (0) +#define emac_phy_dump(dev) do { } while (0) +#define emac_desc_dump(dev) do { } while (0) +#define emac_mac_dump(dev) do { } while (0) +#define emac_mal_dump(dev) do { } while (0) +#endif -struct emac_ethtool_regs_subhdr { - u32 version; - u32 index; +struct ocp_enet_private { + struct sk_buff *tx_skb[NUM_TX_BUFF]; + struct sk_buff *rx_skb[NUM_RX_BUFF]; + struct mal_descriptor *tx_desc; + struct mal_descriptor *rx_desc; + struct mal_descriptor *rx_dirty; + struct net_device_stats stats; + int tx_cnt; + int rx_slot; + int dirty_rx; + int tx_slot; + int ack_slot; + int rx_buffer_size; + + struct mii_phy phy_mii; + int mii_phy_addr; + int want_autoneg; + int timer_ticks; + struct timer_list link_timer; + struct net_device *mdio_dev; + + struct ocp_device *rgmii_dev; + int rgmii_input; + + struct ocp_device *zmii_dev; + int zmii_input; + + struct ibm_ocp_mal *mal; + int mal_tx_chan, mal_rx_chan; + struct mal_commac commac; + + struct ocp_device *tah_dev; + + int opened; + int going_away; + int wol_irq; + emac_t *emacp; + struct ocp_device *ocpdev; + struct net_device *ndev; + spinlock_t lock; }; - -#endif /* __IBM_EMAC_CORE_H_ */ +#endif /* _IBM_EMAC_CORE_H_ */ diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_debug.c b/trunk/drivers/net/ibm_emac/ibm_emac_debug.c index 75d3b8639041..c8512046cf84 100644 --- a/trunk/drivers/net/ibm_emac/ibm_emac_debug.c +++ b/trunk/drivers/net/ibm_emac/ibm_emac_debug.c @@ -1,213 +1,224 @@ /* - * drivers/net/ibm_emac/ibm_emac_debug.c + * ibm_ocp_debug.c * - * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines. + * This has all the debug routines that where in *_enet.c * - * Copyright (c) 2004, 2005 Zultys Technologies - * Eugene Surovegin or + * Armin Kuster akuster@mvista.com + * April , 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 -#include -#include #include #include -#include #include +#include "ibm_ocp_mal.h" +#include "ibm_ocp_zmii.h" +#include "ibm_ocp_enet.h" -#include "ibm_emac_core.h" - -static void emac_desc_dump(int idx, struct ocp_enet_private *p) -{ - int i; - printk("** EMAC%d TX BDs **\n" - " tx_cnt = %d tx_slot = %d ack_slot = %d\n", - idx, p->tx_cnt, p->tx_slot, p->ack_slot); - for (i = 0; i < NUM_TX_BUFF / 2; ++i) - printk - ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n", - i, p->tx_desc[i].data_ptr, p->tx_skb[i] ? 'V' : ' ', - p->tx_desc[i].ctrl, p->tx_desc[i].data_len, - NUM_TX_BUFF / 2 + i, - p->tx_desc[NUM_TX_BUFF / 2 + i].data_ptr, - p->tx_skb[NUM_TX_BUFF / 2 + i] ? 'V' : ' ', - p->tx_desc[NUM_TX_BUFF / 2 + i].ctrl, - p->tx_desc[NUM_TX_BUFF / 2 + i].data_len); - - printk("** EMAC%d RX BDs **\n" - " rx_slot = %d rx_stopped = %d rx_skb_size = %d rx_sync_size = %d\n" - " rx_sg_skb = 0x%p\n", - idx, p->rx_slot, p->commac.rx_stopped, p->rx_skb_size, - p->rx_sync_size, p->rx_sg_skb); - for (i = 0; i < NUM_RX_BUFF / 2; ++i) - printk - ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n", - i, p->rx_desc[i].data_ptr, p->rx_skb[i] ? 'V' : ' ', - p->rx_desc[i].ctrl, p->rx_desc[i].data_len, - NUM_RX_BUFF / 2 + i, - p->rx_desc[NUM_RX_BUFF / 2 + i].data_ptr, - p->rx_skb[NUM_RX_BUFF / 2 + i] ? 'V' : ' ', - p->rx_desc[NUM_RX_BUFF / 2 + i].ctrl, - p->rx_desc[NUM_RX_BUFF / 2 + i].data_len); -} - -static void emac_mac_dump(int idx, struct ocp_enet_private *dev) -{ - struct emac_regs *p = dev->emacp; - - printk("** EMAC%d registers **\n" - "MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n" - "RMR = 0x%08x ISR = 0x%08x ISER = 0x%08x\n" - "IAR = %04x%08x VTPID = 0x%04x VTCI = 0x%04x\n" - "IAHT: 0x%04x 0x%04x 0x%04x 0x%04x " - "GAHT: 0x%04x 0x%04x 0x%04x 0x%04x\n" - "LSA = %04x%08x IPGVR = 0x%04x\n" - "STACR = 0x%08x TRTR = 0x%08x RWMR = 0x%08x\n" - "OCTX = 0x%08x OCRX = 0x%08x IPCR = 0x%08x\n", - idx, in_be32(&p->mr0), in_be32(&p->mr1), - in_be32(&p->tmr0), in_be32(&p->tmr1), - in_be32(&p->rmr), in_be32(&p->isr), in_be32(&p->iser), - in_be32(&p->iahr), in_be32(&p->ialr), in_be32(&p->vtpid), - in_be32(&p->vtci), - in_be32(&p->iaht1), in_be32(&p->iaht2), in_be32(&p->iaht3), - in_be32(&p->iaht4), - in_be32(&p->gaht1), in_be32(&p->gaht2), in_be32(&p->gaht3), - in_be32(&p->gaht4), - in_be32(&p->lsah), in_be32(&p->lsal), in_be32(&p->ipgvr), - in_be32(&p->stacr), in_be32(&p->trtr), in_be32(&p->rwmr), - in_be32(&p->octx), in_be32(&p->ocrx), in_be32(&p->ipcr) - ); - - emac_desc_dump(idx, dev); -} - -static void emac_mal_dump(struct ibm_ocp_mal *mal) -{ - struct ocp_func_mal_data *maldata = mal->def->additions; - int i; - - printk("** MAL%d Registers **\n" - "CFG = 0x%08x ESR = 0x%08x IER = 0x%08x\n" - "TX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n" - "RX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n", - mal->def->index, - get_mal_dcrn(mal, MAL_CFG), get_mal_dcrn(mal, MAL_ESR), - get_mal_dcrn(mal, MAL_IER), - get_mal_dcrn(mal, MAL_TXCASR), get_mal_dcrn(mal, MAL_TXCARR), - get_mal_dcrn(mal, MAL_TXEOBISR), get_mal_dcrn(mal, MAL_TXDEIR), - get_mal_dcrn(mal, MAL_RXCASR), get_mal_dcrn(mal, MAL_RXCARR), - get_mal_dcrn(mal, MAL_RXEOBISR), get_mal_dcrn(mal, MAL_RXDEIR) - ); - - printk("TX|"); - for (i = 0; i < maldata->num_tx_chans; ++i) { - if (i && !(i % 4)) - printk("\n "); - printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_TXCTPR(i))); - } - printk("\nRX|"); - for (i = 0; i < maldata->num_rx_chans; ++i) { - if (i && !(i % 4)) - printk("\n "); - printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_RXCTPR(i))); - } - printk("\n "); - for (i = 0; i < maldata->num_rx_chans; ++i) { - u32 r = get_mal_dcrn(mal, MAL_RCBS(i)); - if (i && !(i % 3)) - printk("\n "); - printk("RCBS%d = 0x%08x (%d) ", i, r, r * 16); - } - printk("\n"); -} - -static struct ocp_enet_private *__emacs[4]; -static struct ibm_ocp_mal *__mals[1]; +extern int emac_phy_read(struct net_device *dev, int mii_id, int reg); -void emac_dbg_register(int idx, struct ocp_enet_private *dev) +void emac_phy_dump(struct net_device *dev) { - unsigned long flags; - - if (idx >= sizeof(__emacs) / sizeof(__emacs[0])) { - printk(KERN_WARNING - "invalid index %d when registering EMAC for debugging\n", - idx); - return; + struct ocp_enet_private *fep = dev->priv; + unsigned long i; + uint data; + + printk(KERN_DEBUG " Prepare for Phy dump....\n"); + for (i = 0; i < 0x1A; i++) { + data = emac_phy_read(dev, fep->mii_phy_addr, i); + printk(KERN_DEBUG "Phy reg 0x%lx ==> %4x\n", i, data); + if (i == 0x07) + i = 0x0f; } - - local_irq_save(flags); - __emacs[idx] = dev; - local_irq_restore(flags); } -void mal_dbg_register(int idx, struct ibm_ocp_mal *mal) +void emac_desc_dump(struct net_device *dev) { - unsigned long flags; - - if (idx >= sizeof(__mals) / sizeof(__mals[0])) { - printk(KERN_WARNING - "invalid index %d when registering MAL for debugging\n", - idx); - return; + struct ocp_enet_private *fep = dev->priv; + int curr_slot; + + printk(KERN_DEBUG + "dumping the receive descriptors: current slot is %d\n", + fep->rx_slot); + for (curr_slot = 0; curr_slot < NUM_RX_BUFF; curr_slot++) { + printk(KERN_DEBUG + "Desc %02d: status 0x%04x, length %3d, addr 0x%x\n", + curr_slot, fep->rx_desc[curr_slot].ctrl, + fep->rx_desc[curr_slot].data_len, + (unsigned int)fep->rx_desc[curr_slot].data_ptr); } - - local_irq_save(flags); - __mals[idx] = mal; - local_irq_restore(flags); } -void emac_dbg_dump_all(void) +void emac_mac_dump(struct net_device *dev) { - unsigned int i; - unsigned long flags; - - local_irq_save(flags); - - for (i = 0; i < sizeof(__mals) / sizeof(__mals[0]); ++i) - if (__mals[i]) - emac_mal_dump(__mals[i]); - - for (i = 0; i < sizeof(__emacs) / sizeof(__emacs[0]); ++i) - if (__emacs[i]) - emac_mac_dump(i, __emacs[i]); - - local_irq_restore(flags); + struct ocp_enet_private *fep = dev->priv; + volatile emac_t *emacp = fep->emacp; + + printk(KERN_DEBUG "EMAC DEBUG ********** \n"); + printk(KERN_DEBUG "EMAC_M0 ==> 0x%x\n", in_be32(&emacp->em0mr0)); + printk(KERN_DEBUG "EMAC_M1 ==> 0x%x\n", in_be32(&emacp->em0mr1)); + printk(KERN_DEBUG "EMAC_TXM0==> 0x%x\n", in_be32(&emacp->em0tmr0)); + printk(KERN_DEBUG "EMAC_TXM1==> 0x%x\n", in_be32(&emacp->em0tmr1)); + printk(KERN_DEBUG "EMAC_RXM ==> 0x%x\n", in_be32(&emacp->em0rmr)); + printk(KERN_DEBUG "EMAC_ISR ==> 0x%x\n", in_be32(&emacp->em0isr)); + printk(KERN_DEBUG "EMAC_IER ==> 0x%x\n", in_be32(&emacp->em0iser)); + printk(KERN_DEBUG "EMAC_IAH ==> 0x%x\n", in_be32(&emacp->em0iahr)); + printk(KERN_DEBUG "EMAC_IAL ==> 0x%x\n", in_be32(&emacp->em0ialr)); + printk(KERN_DEBUG "EMAC_VLAN_TPID_REG ==> 0x%x\n", + in_be32(&emacp->em0vtpid)); } -#if defined(CONFIG_MAGIC_SYSRQ) -static void emac_sysrq_handler(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +void emac_mal_dump(struct net_device *dev) { - emac_dbg_dump_all(); + struct ibm_ocp_mal *mal = ((struct ocp_enet_private *)dev->priv)->mal; + + printk(KERN_DEBUG " MAL DEBUG ********** \n"); + printk(KERN_DEBUG " MCR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALCR)); + printk(KERN_DEBUG " ESR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALESR)); + printk(KERN_DEBUG " IER ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALIER)); +#ifdef CONFIG_40x + printk(KERN_DEBUG " DBR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALDBR)); +#endif /* CONFIG_40x */ + printk(KERN_DEBUG " TXCASR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCASR)); + printk(KERN_DEBUG " TXCARR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCARR)); + printk(KERN_DEBUG " TXEOBISR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXEOBISR)); + printk(KERN_DEBUG " TXDEIR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXDEIR)); + printk(KERN_DEBUG " RXCASR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCASR)); + printk(KERN_DEBUG " RXCARR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCARR)); + printk(KERN_DEBUG " RXEOBISR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRXEOBISR)); + printk(KERN_DEBUG " RXDEIR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRXDEIR)); + printk(KERN_DEBUG " TXCTP0R ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP0R)); + printk(KERN_DEBUG " TXCTP1R ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP1R)); + printk(KERN_DEBUG " TXCTP2R ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP2R)); + printk(KERN_DEBUG " TXCTP3R ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP3R)); + printk(KERN_DEBUG " RXCTP0R ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCTP0R)); + printk(KERN_DEBUG " RXCTP1R ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCTP1R)); + printk(KERN_DEBUG " RCBS0 ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRCBS0)); + printk(KERN_DEBUG " RCBS1 ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRCBS1)); } -static struct sysrq_key_op emac_sysrq_op = { - .handler = emac_sysrq_handler, - .help_msg = "emaC", - .action_msg = "Show EMAC(s) status", -}; - -int __init emac_init_debug(void) +void emac_serr_dump_0(struct net_device *dev) { - return register_sysrq_key('c', &emac_sysrq_op); + struct ibm_ocp_mal *mal = ((struct ocp_enet_private *)dev->priv)->mal; + unsigned long int mal_error, plb_error, plb_addr; + + mal_error = get_mal_dcrn(mal, DCRN_MALESR); + printk(KERN_DEBUG "ppc405_eth_serr: %s channel %ld \n", + (mal_error & 0x40000000) ? "Receive" : + "Transmit", (mal_error & 0x3e000000) >> 25); + printk(KERN_DEBUG " ----- latched error -----\n"); + if (mal_error & MALESR_DE) + printk(KERN_DEBUG " DE: descriptor error\n"); + if (mal_error & MALESR_OEN) + printk(KERN_DEBUG " ONE: OPB non-fullword error\n"); + if (mal_error & MALESR_OTE) + printk(KERN_DEBUG " OTE: OPB timeout error\n"); + if (mal_error & MALESR_OSE) + printk(KERN_DEBUG " OSE: OPB slave error\n"); + + if (mal_error & MALESR_PEIN) { + plb_error = mfdcr(DCRN_PLB0_BESR); + printk(KERN_DEBUG + " PEIN: PLB error, PLB0_BESR is 0x%x\n", + (unsigned int)plb_error); + plb_addr = mfdcr(DCRN_PLB0_BEAR); + printk(KERN_DEBUG + " PEIN: PLB error, PLB0_BEAR is 0x%x\n", + (unsigned int)plb_addr); + } } -void __exit emac_fini_debug(void) +void emac_serr_dump_1(struct net_device *dev) { - unregister_sysrq_key('c', &emac_sysrq_op); + struct ibm_ocp_mal *mal = ((struct ocp_enet_private *)dev->priv)->mal; + int mal_error = get_mal_dcrn(mal, DCRN_MALESR); + + printk(KERN_DEBUG " ----- cumulative errors -----\n"); + if (mal_error & MALESR_DEI) + printk(KERN_DEBUG " DEI: descriptor error interrupt\n"); + if (mal_error & MALESR_ONEI) + printk(KERN_DEBUG " OPB non-fullword error interrupt\n"); + if (mal_error & MALESR_OTEI) + printk(KERN_DEBUG " OTEI: timeout error interrupt\n"); + if (mal_error & MALESR_OSEI) + printk(KERN_DEBUG " OSEI: slave error interrupt\n"); + if (mal_error & MALESR_PBEI) + printk(KERN_DEBUG " PBEI: PLB bus error interrupt\n"); } -#else -int __init emac_init_debug(void) -{ - return 0; -} -void __exit emac_fini_debug(void) +void emac_err_dump(struct net_device *dev, int em0isr) { + printk(KERN_DEBUG "%s: on-chip ethernet error:\n", dev->name); + + if (em0isr & EMAC_ISR_OVR) + printk(KERN_DEBUG " OVR: overrun\n"); + if (em0isr & EMAC_ISR_PP) + printk(KERN_DEBUG " PP: control pause packet\n"); + if (em0isr & EMAC_ISR_BP) + printk(KERN_DEBUG " BP: packet error\n"); + if (em0isr & EMAC_ISR_RP) + printk(KERN_DEBUG " RP: runt packet\n"); + if (em0isr & EMAC_ISR_SE) + printk(KERN_DEBUG " SE: short event\n"); + if (em0isr & EMAC_ISR_ALE) + printk(KERN_DEBUG " ALE: odd number of nibbles in packet\n"); + if (em0isr & EMAC_ISR_BFCS) + printk(KERN_DEBUG " BFCS: bad FCS\n"); + if (em0isr & EMAC_ISR_PTLE) + printk(KERN_DEBUG " PTLE: oversized packet\n"); + if (em0isr & EMAC_ISR_ORE) + printk(KERN_DEBUG + " ORE: packet length field > max allowed LLC\n"); + if (em0isr & EMAC_ISR_IRE) + printk(KERN_DEBUG " IRE: In Range error\n"); + if (em0isr & EMAC_ISR_DBDM) + printk(KERN_DEBUG " DBDM: xmit error or SQE\n"); + if (em0isr & EMAC_ISR_DB0) + printk(KERN_DEBUG " DB0: xmit error or SQE on TX channel 0\n"); + if (em0isr & EMAC_ISR_SE0) + printk(KERN_DEBUG + " SE0: Signal Quality Error test failure from TX channel 0\n"); + if (em0isr & EMAC_ISR_TE0) + printk(KERN_DEBUG " TE0: xmit channel 0 aborted\n"); + if (em0isr & EMAC_ISR_DB1) + printk(KERN_DEBUG " DB1: xmit error or SQE on TX channel \n"); + if (em0isr & EMAC_ISR_SE1) + printk(KERN_DEBUG + " SE1: Signal Quality Error test failure from TX channel 1\n"); + if (em0isr & EMAC_ISR_TE1) + printk(KERN_DEBUG " TE1: xmit channel 1 aborted\n"); + if (em0isr & EMAC_ISR_MOS) + printk(KERN_DEBUG " MOS\n"); + if (em0isr & EMAC_ISR_MOF) + printk(KERN_DEBUG " MOF\n"); + + emac_mac_dump(dev); + emac_mal_dump(dev); } -#endif /* CONFIG_MAGIC_SYSRQ */ diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_debug.h b/trunk/drivers/net/ibm_emac/ibm_emac_debug.h deleted file mode 100644 index e85fbe0a8da9..000000000000 --- a/trunk/drivers/net/ibm_emac/ibm_emac_debug.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_ocp_debug.h - * - * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines. - * - * Copyright (c) 2004, 2005 Zultys Technologies - * Eugene Surovegin or - * - * 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. - * - */ -#ifndef __IBM_EMAC_DEBUG_H_ -#define __IBM_EMAC_DEBUG_H_ - -#include -#include -#include "ibm_emac_core.h" -#include "ibm_emac_mal.h" - -#if defined(CONFIG_IBM_EMAC_DEBUG) -void emac_dbg_register(int idx, struct ocp_enet_private *dev); -void mal_dbg_register(int idx, struct ibm_ocp_mal *mal); -int emac_init_debug(void) __init; -void emac_fini_debug(void) __exit; -void emac_dbg_dump_all(void); -# define DBG_LEVEL 1 -#else -# define emac_dbg_register(x,y) ((void)0) -# define mal_dbg_register(x,y) ((void)0) -# define emac_init_debug() ((void)0) -# define emac_fini_debug() ((void)0) -# define emac_dbg_dump_all() ((void)0) -# define DBG_LEVEL 0 -#endif - -#if DBG_LEVEL > 0 -# define DBG(f,x...) printk("emac" f, ##x) -# define MAL_DBG(f,x...) printk("mal" f, ##x) -# define ZMII_DBG(f,x...) printk("zmii" f, ##x) -# define RGMII_DBG(f,x...) printk("rgmii" f, ##x) -# define NL "\n" -#else -# define DBG(f,x...) ((void)0) -# define MAL_DBG(f,x...) ((void)0) -# define ZMII_DBG(f,x...) ((void)0) -# define RGMII_DBG(f,x...) ((void)0) -#endif -#if DBG_LEVEL > 1 -# define DBG2(f,x...) DBG(f, ##x) -# define MAL_DBG2(f,x...) MAL_DBG(f, ##x) -# define ZMII_DBG2(f,x...) ZMII_DBG(f, ##x) -# define RGMII_DBG2(f,x...) RGMII_DBG(f, ##x) -#else -# define DBG2(f,x...) ((void)0) -# define MAL_DBG2(f,x...) ((void)0) -# define ZMII_DBG2(f,x...) ((void)0) -# define RGMII_DBG2(f,x...) ((void)0) -#endif - -#endif /* __IBM_EMAC_DEBUG_H_ */ diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_mal.c b/trunk/drivers/net/ibm_emac/ibm_emac_mal.c index da88d43081cc..e59f57f363ca 100644 --- a/trunk/drivers/net/ibm_emac/ibm_emac_mal.c +++ b/trunk/drivers/net/ibm_emac/ibm_emac_mal.c @@ -1,565 +1,436 @@ /* - * drivers/net/ibm_emac/ibm_emac_mal.c + * ibm_ocp_mal.c * - * Memory Access Layer (MAL) support - * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin or + * Armin Kuster akuster@mvista.com + * Juen, 2002 * - * Based on original work by - * Benjamin Herrenschmidt , - * David Gibson , - * - * Armin Kuster - * Copyright 2002 MontaVista Softare Inc. + * 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 #include #include #include #include #include -#include #include +#include +#include #include -#include "ibm_emac_core.h" #include "ibm_emac_mal.h" -#include "ibm_emac_debug.h" -int __init mal_register_commac(struct ibm_ocp_mal *mal, - struct mal_commac *commac) +// 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; - local_irq_save(flags); - MAL_DBG("%d: reg(%08x, %08x)" NL, mal->def->index, - commac->tx_chan_mask, commac->rx_chan_mask); + write_lock_irqsave(&mal_list_lock, flags); - /* Don't let multiple commacs claim the same channel(s) */ + /* 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)) { - local_irq_restore(flags); - printk(KERN_WARNING "mal%d: COMMAC channels conflict!\n", - mal->def->index); + 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->list); - local_irq_restore(flags); + list_add(&commac->list, &mal->commac); + + write_unlock_irqrestore(&mal_list_lock, flags); + return 0; } -void __exit mal_unregister_commac(struct ibm_ocp_mal *mal, - struct mal_commac *commac) +int mal_unregister_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac) { unsigned long flags; - local_irq_save(flags); - MAL_DBG("%d: unreg(%08x, %08x)" NL, mal->def->index, - commac->tx_chan_mask, commac->rx_chan_mask); + 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); - local_irq_restore(flags); + write_unlock_irqrestore(&mal_list_lock, flags); + + return 0; } int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, unsigned long size) { - struct ocp_func_mal_data *maldata = mal->def->additions; - BUG_ON(channel < 0 || channel >= maldata->num_rx_chans || - size > MAL_MAX_RX_SIZE); - - MAL_DBG("%d: set_rbcs(%d, %lu)" NL, mal->def->index, channel, size); - - if (size & 0xf) { - printk(KERN_WARNING - "mal%d: incorrect RX size %lu for the channel %d\n", - mal->def->index, size, channel); + 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; } - set_mal_dcrn(mal, MAL_RCBS(channel), size >> 4); return 0; } -int mal_tx_bd_offset(struct ibm_ocp_mal *mal, int channel) -{ - struct ocp_func_mal_data *maldata = mal->def->additions; - BUG_ON(channel < 0 || channel >= maldata->num_tx_chans); - return channel * NUM_TX_BUFF; -} - -int mal_rx_bd_offset(struct ibm_ocp_mal *mal, int channel) -{ - struct ocp_func_mal_data *maldata = mal->def->additions; - BUG_ON(channel < 0 || channel >= maldata->num_rx_chans); - return maldata->num_tx_chans * NUM_TX_BUFF + channel * NUM_RX_BUFF; -} - -void mal_enable_tx_channel(struct ibm_ocp_mal *mal, int channel) +static irqreturn_t mal_serr(int irq, void *dev_instance, struct pt_regs *regs) { - local_bh_disable(); - MAL_DBG("%d: enable_tx(%d)" NL, mal->def->index, channel); - set_mal_dcrn(mal, MAL_TXCASR, - get_mal_dcrn(mal, MAL_TXCASR) | MAL_CHAN_MASK(channel)); - local_bh_enable(); -} + struct ibm_ocp_mal *mal = dev_instance; + unsigned long mal_error; -void mal_disable_tx_channel(struct ibm_ocp_mal *mal, int channel) -{ - set_mal_dcrn(mal, MAL_TXCARR, MAL_CHAN_MASK(channel)); - MAL_DBG("%d: disable_tx(%d)" NL, mal->def->index, channel); -} + /* + * This SERR applies to one of the devices on the MAL, here we charge + * it against the first EMAC registered for the MAL. + */ -void mal_enable_rx_channel(struct ibm_ocp_mal *mal, int channel) -{ - local_bh_disable(); - MAL_DBG("%d: enable_rx(%d)" NL, mal->def->index, channel); - set_mal_dcrn(mal, MAL_RXCASR, - get_mal_dcrn(mal, MAL_RXCASR) | MAL_CHAN_MASK(channel)); - local_bh_enable(); -} + mal_error = get_mal_dcrn(mal, DCRN_MALESR); -void mal_disable_rx_channel(struct ibm_ocp_mal *mal, int channel) -{ - set_mal_dcrn(mal, MAL_RXCARR, MAL_CHAN_MASK(channel)); - MAL_DBG("%d: disable_rx(%d)" NL, mal->def->index, channel); -} + printk(KERN_ERR "%s: System Error (MALESR=%lx)\n", + "MAL" /* FIXME: get the name right */ , mal_error); -void mal_poll_add(struct ibm_ocp_mal *mal, struct mal_commac *commac) -{ - local_bh_disable(); - MAL_DBG("%d: poll_add(%p)" NL, mal->def->index, commac); - list_add_tail(&commac->poll_list, &mal->poll_list); - local_bh_enable(); -} + /* FIXME: decipher error */ + /* DIXME: distribute to commacs, if possible */ -void mal_poll_del(struct ibm_ocp_mal *mal, struct mal_commac *commac) -{ - local_bh_disable(); - MAL_DBG("%d: poll_del(%p)" NL, mal->def->index, commac); - list_del(&commac->poll_list); - local_bh_enable(); -} - -/* synchronized by mal_poll() */ -static inline void mal_enable_eob_irq(struct ibm_ocp_mal *mal) -{ - MAL_DBG2("%d: enable_irq" NL, mal->def->index); - set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) | MAL_CFG_EOPIE); -} + /* Clear the error status register */ + set_mal_dcrn(mal, DCRN_MALESR, mal_error); -/* synchronized by __LINK_STATE_RX_SCHED bit in ndev->state */ -static inline void mal_disable_eob_irq(struct ibm_ocp_mal *mal) -{ - set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) & ~MAL_CFG_EOPIE); - MAL_DBG2("%d: disable_irq" NL, mal->def->index); + return IRQ_HANDLED; } -static irqreturn_t mal_serr(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t mal_txeob(int irq, void *dev_instance, struct pt_regs *regs) { struct ibm_ocp_mal *mal = dev_instance; - u32 esr = get_mal_dcrn(mal, MAL_ESR); - - /* Clear the error status register */ - set_mal_dcrn(mal, MAL_ESR, esr); + struct list_head *l; + unsigned long isr; - MAL_DBG("%d: SERR %08x" NL, mal->def->index, esr); + isr = get_mal_dcrn(mal, DCRN_MALTXEOBISR); + set_mal_dcrn(mal, DCRN_MALTXEOBISR, isr); - if (esr & MAL_ESR_EVB) { - if (esr & MAL_ESR_DE) { - /* We ignore Descriptor error, - * TXDE or RXDE interrupt will be generated anyway. - */ - return IRQ_HANDLED; - } + read_lock(&mal_list_lock); + list_for_each(l, &mal->commac) { + struct mal_commac *mc = list_entry(l, struct mal_commac, list); - if (esr & MAL_ESR_PEIN) { - /* PLB error, it's probably buggy hardware or - * incorrect physical address in BD (i.e. bug) - */ - if (net_ratelimit()) - printk(KERN_ERR - "mal%d: system error, PLB (ESR = 0x%08x)\n", - mal->def->index, esr); - return IRQ_HANDLED; + if (isr & mc->tx_chan_mask) { + mc->ops->txeob(mc->dev, isr & mc->tx_chan_mask); } - - /* OPB error, it's probably buggy hardware or incorrect EBC setup */ - if (net_ratelimit()) - printk(KERN_ERR - "mal%d: system error, OPB (ESR = 0x%08x)\n", - mal->def->index, esr); } - return IRQ_HANDLED; -} - -static inline void mal_schedule_poll(struct ibm_ocp_mal *mal) -{ - if (likely(netif_rx_schedule_prep(&mal->poll_dev))) { - MAL_DBG2("%d: schedule_poll" NL, mal->def->index); - mal_disable_eob_irq(mal); - __netif_rx_schedule(&mal->poll_dev); - } else - MAL_DBG2("%d: already in poll" NL, mal->def->index); -} + read_unlock(&mal_list_lock); -static irqreturn_t mal_txeob(int irq, void *dev_instance, struct pt_regs *regs) -{ - struct ibm_ocp_mal *mal = dev_instance; - u32 r = get_mal_dcrn(mal, MAL_TXEOBISR); - MAL_DBG2("%d: txeob %08x" NL, mal->def->index, r); - mal_schedule_poll(mal); - set_mal_dcrn(mal, MAL_TXEOBISR, r); return IRQ_HANDLED; } static irqreturn_t mal_rxeob(int irq, void *dev_instance, struct pt_regs *regs) { struct ibm_ocp_mal *mal = dev_instance; - u32 r = get_mal_dcrn(mal, MAL_RXEOBISR); - MAL_DBG2("%d: rxeob %08x" NL, mal->def->index, r); - mal_schedule_poll(mal); - set_mal_dcrn(mal, MAL_RXEOBISR, r); - return IRQ_HANDLED; -} + struct list_head *l; + unsigned long isr; -static irqreturn_t mal_txde(int irq, void *dev_instance, struct pt_regs *regs) -{ - struct ibm_ocp_mal *mal = dev_instance; - u32 deir = get_mal_dcrn(mal, MAL_TXDEIR); - set_mal_dcrn(mal, MAL_TXDEIR, deir); + isr = get_mal_dcrn(mal, DCRN_MALRXEOBISR); + set_mal_dcrn(mal, DCRN_MALRXEOBISR, isr); - MAL_DBG("%d: txde %08x" NL, mal->def->index, deir); + read_lock(&mal_list_lock); + list_for_each(l, &mal->commac) { + struct mal_commac *mc = list_entry(l, struct mal_commac, list); - if (net_ratelimit()) - printk(KERN_ERR - "mal%d: TX descriptor error (TXDEIR = 0x%08x)\n", - mal->def->index, deir); + 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_rxde(int irq, void *dev_instance, struct pt_regs *regs) +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; - u32 deir = get_mal_dcrn(mal, MAL_RXDEIR); + unsigned long deir; - MAL_DBG("%d: rxde %08x" NL, mal->def->index, deir); + deir = get_mal_dcrn(mal, DCRN_MALTXDEIR); - list_for_each(l, &mal->list) { + /* 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->rx_chan_mask) { - mc->rx_stopped = 1; - mc->ops->rxde(mc->dev); + + if (deir & mc->tx_chan_mask) { + mc->ops->txde(mc->dev, deir & mc->tx_chan_mask); } } - - mal_schedule_poll(mal); - set_mal_dcrn(mal, MAL_RXDEIR, deir); + read_unlock(&mal_list_lock); return IRQ_HANDLED; } -static int mal_poll(struct net_device *ndev, int *budget) +/* + * 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 = ndev->priv; + struct ibm_ocp_mal *mal = dev_instance; struct list_head *l; - int rx_work_limit = min(ndev->quota, *budget), received = 0, done; - - MAL_DBG2("%d: poll(%d) %d ->" NL, mal->def->index, *budget, - rx_work_limit); - again: - /* Process TX skbs */ - list_for_each(l, &mal->poll_list) { - struct mal_commac *mc = - list_entry(l, struct mal_commac, poll_list); - mc->ops->poll_tx(mc->dev); - } - - /* Process RX skbs. - * We _might_ need something more smart here to enforce polling fairness. - */ - list_for_each(l, &mal->poll_list) { - struct mal_commac *mc = - list_entry(l, struct mal_commac, poll_list); - int n = mc->ops->poll_rx(mc->dev, rx_work_limit); - if (n) { - received += n; - rx_work_limit -= n; - if (rx_work_limit <= 0) { - done = 0; - goto more_work; // XXX What if this is the last one ? - } - } - } - - /* We need to disable IRQs to protect from RXDE IRQ here */ - local_irq_disable(); - __netif_rx_complete(ndev); - mal_enable_eob_irq(mal); - local_irq_enable(); - - done = 1; - - /* Check for "rotting" packet(s) */ - list_for_each(l, &mal->poll_list) { - struct mal_commac *mc = - list_entry(l, struct mal_commac, poll_list); - if (unlikely(mc->ops->peek_rx(mc->dev) || mc->rx_stopped)) { - MAL_DBG2("%d: rotting packet" NL, mal->def->index); - if (netif_rx_reschedule(ndev, received)) - mal_disable_eob_irq(mal); - else - MAL_DBG2("%d: already in poll list" NL, - mal->def->index); - - if (rx_work_limit > 0) - goto again; - else - goto more_work; - } - mc->ops->poll_tx(mc->dev); - } - - more_work: - ndev->quota -= received; - *budget -= received; - - MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, *budget, - done ? 0 : 1); - return done ? 0 : 1; -} - -static void mal_reset(struct ibm_ocp_mal *mal) -{ - int n = 10; - MAL_DBG("%d: reset" NL, mal->def->index); + unsigned long deir; - set_mal_dcrn(mal, MAL_CFG, MAL_CFG_SR); + deir = get_mal_dcrn(mal, DCRN_MALRXDEIR); - /* Wait for reset to complete (1 system clock) */ - while ((get_mal_dcrn(mal, MAL_CFG) & MAL_CFG_SR) && n) - --n; + /* + * This really is needed. This case encountered in stress testing. + */ + if (deir == 0) + return IRQ_HANDLED; - if (unlikely(!n)) - printk(KERN_ERR "mal%d: reset timeout\n", mal->def->index); -} + /* FIXME: print which MAL correctly */ + printk(KERN_WARNING "%s: Rx descriptor error (MALRXDEIR=%lx)\n", + "MAL", deir); -int mal_get_regs_len(struct ibm_ocp_mal *mal) -{ - return sizeof(struct emac_ethtool_regs_subhdr) + - sizeof(struct ibm_mal_regs); -} + read_lock(&mal_list_lock); + list_for_each(l, &mal->commac) { + struct mal_commac *mc = list_entry(l, struct mal_commac, list); -void *mal_dump_regs(struct ibm_ocp_mal *mal, void *buf) -{ - struct emac_ethtool_regs_subhdr *hdr = buf; - struct ibm_mal_regs *regs = (struct ibm_mal_regs *)(hdr + 1); - struct ocp_func_mal_data *maldata = mal->def->additions; - int i; - - hdr->version = MAL_VERSION; - hdr->index = mal->def->index; - - regs->tx_count = maldata->num_tx_chans; - regs->rx_count = maldata->num_rx_chans; - - regs->cfg = get_mal_dcrn(mal, MAL_CFG); - regs->esr = get_mal_dcrn(mal, MAL_ESR); - regs->ier = get_mal_dcrn(mal, MAL_IER); - regs->tx_casr = get_mal_dcrn(mal, MAL_TXCASR); - regs->tx_carr = get_mal_dcrn(mal, MAL_TXCARR); - regs->tx_eobisr = get_mal_dcrn(mal, MAL_TXEOBISR); - regs->tx_deir = get_mal_dcrn(mal, MAL_TXDEIR); - regs->rx_casr = get_mal_dcrn(mal, MAL_RXCASR); - regs->rx_carr = get_mal_dcrn(mal, MAL_RXCARR); - regs->rx_eobisr = get_mal_dcrn(mal, MAL_RXEOBISR); - regs->rx_deir = get_mal_dcrn(mal, MAL_RXDEIR); - - for (i = 0; i < regs->tx_count; ++i) - regs->tx_ctpr[i] = get_mal_dcrn(mal, MAL_TXCTPR(i)); - - for (i = 0; i < regs->rx_count; ++i) { - regs->rx_ctpr[i] = get_mal_dcrn(mal, MAL_RXCTPR(i)); - regs->rcbs[i] = get_mal_dcrn(mal, MAL_RCBS(i)); + if (deir & mc->rx_chan_mask) { + mc->ops->rxde(mc->dev, deir & mc->rx_chan_mask); + } } - return regs + 1; + read_unlock(&mal_list_lock); + + return IRQ_HANDLED; } static int __init mal_probe(struct ocp_device *ocpdev) { - struct ibm_ocp_mal *mal; + struct ibm_ocp_mal *mal = NULL; struct ocp_func_mal_data *maldata; - int err = 0, i, bd_size; - - MAL_DBG("%d: probe" NL, ocpdev->def->index); + int err = 0; - maldata = ocpdev->def->additions; + maldata = (struct ocp_func_mal_data *)ocpdev->def->additions; if (maldata == NULL) { - printk(KERN_ERR "mal%d: missing additional data!\n", + printk(KERN_ERR "mal%d: Missing additional datas !\n", ocpdev->def->index); return -ENODEV; } - mal = kzalloc(sizeof(struct ibm_ocp_mal), GFP_KERNEL); - if (!mal) { + mal = kmalloc(sizeof(struct ibm_ocp_mal), GFP_KERNEL); + if (mal == NULL) { printk(KERN_ERR - "mal%d: out of memory allocating MAL structure!\n", + "mal%d: Out of memory allocating MAL structure !\n", ocpdev->def->index); return -ENOMEM; } - mal->dcrbase = maldata->dcr_base; - mal->def = ocpdev->def; - - INIT_LIST_HEAD(&mal->poll_list); - set_bit(__LINK_STATE_START, &mal->poll_dev.state); - mal->poll_dev.weight = CONFIG_IBM_EMAC_POLL_WEIGHT; - mal->poll_dev.poll = mal_poll; - mal->poll_dev.priv = mal; - atomic_set(&mal->poll_dev.refcnt, 1); - - INIT_LIST_HEAD(&mal->list); + 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(); + } - /* Load power-on reset defaults */ - mal_reset(mal); + /**************************/ - /* Set the MAL configuration register */ - set_mal_dcrn(mal, MAL_CFG, MAL_CFG_DEFAULT | MAL_CFG_PLBB | - MAL_CFG_OPBBL | MAL_CFG_LEA); + INIT_LIST_HEAD(&mal->commac); - mal_enable_eob_irq(mal); + set_mal_dcrn(mal, DCRN_MALRXCARR, 0xFFFFFFFF); + set_mal_dcrn(mal, DCRN_MALTXCARR, 0xFFFFFFFF); - /* Allocate space for BD rings */ - BUG_ON(maldata->num_tx_chans <= 0 || maldata->num_tx_chans > 32); - BUG_ON(maldata->num_rx_chans <= 0 || maldata->num_rx_chans > 32); - bd_size = sizeof(struct mal_descriptor) * - (NUM_TX_BUFF * maldata->num_tx_chans + - NUM_RX_BUFF * maldata->num_rx_chans); - mal->bd_virt = - dma_alloc_coherent(&ocpdev->dev, bd_size, &mal->bd_dma, GFP_KERNEL); + set_mal_dcrn(mal, DCRN_MALCR, MALCR_MMSR); /* 384 */ + /* FIXME: Add delay */ - if (!mal->bd_virt) { + /* 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 RX/TX descriptors!\n", - mal->def->index); + "mal%d: Out of memory allocating MAL descriptors !\n", + ocpdev->def->index); err = -ENOMEM; goto fail; } - memset(mal->bd_virt, 0, bd_size); - for (i = 0; i < maldata->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 < maldata->num_rx_chans; ++i) - set_mal_dcrn(mal, MAL_RXCTPR(i), mal->bd_dma + - sizeof(struct mal_descriptor) * - mal_rx_bd_offset(mal, i)); + /* 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 fail2; - err = request_irq(maldata->txde_irq, mal_txde, 0, "MAL TX DE", mal); + goto fail; + err = request_irq(maldata->txde_irq, mal_txde, 0, "MAL TX DE ", mal); if (err) - goto fail3; + goto fail; err = request_irq(maldata->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); if (err) - goto fail4; + goto fail; err = request_irq(maldata->rxde_irq, mal_rxde, 0, "MAL RX DE", mal); if (err) - goto fail5; + goto fail; err = request_irq(maldata->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); if (err) - goto fail6; + goto fail; - /* Enable all MAL SERR interrupt sources */ - set_mal_dcrn(mal, MAL_IER, MAL_IER_EVENTS); + set_mal_dcrn(mal, DCRN_MALIER, + MALIER_DE | MALIER_NE | MALIER_TE | + MALIER_OPBE | MALIER_PLBE); - /* Advertise this instance to the rest of the world */ + /* Advertise me to the rest of the world */ ocp_set_drvdata(ocpdev, mal); - mal_dbg_register(mal->def->index, 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); - printk(KERN_INFO "mal%d: initialized, %d TX channels, %d RX channels\n", - mal->def->index, maldata->num_tx_chans, maldata->num_rx_chans); return 0; - fail6: - free_irq(maldata->rxde_irq, mal); - fail5: - free_irq(maldata->txeob_irq, mal); - fail4: - free_irq(maldata->txde_irq, mal); - fail3: - free_irq(maldata->serr_irq, mal); - fail2: - dma_free_coherent(&ocpdev->dev, bd_size, mal->bd_virt, mal->bd_dma); fail: - kfree(mal); + /* 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 = mal->def->additions; - - MAL_DBG("%d: remove" NL, mal->def->index); + struct ocp_func_mal_data *maldata = ocpdev->def->additions; - /* Syncronize with scheduled polling, - stolen from net/core/dev.c:dev_close() - */ - clear_bit(__LINK_STATE_START, &mal->poll_dev.state); - netif_poll_disable(&mal->poll_dev); - - if (!list_empty(&mal->list)) { - /* This is *very* bad */ - printk(KERN_EMERG - "mal%d: commac list is not empty on remove!\n", - mal->def->index); - } + 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); - mal_reset(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); - mal_dbg_register(mal->def->index, NULL); - - dma_free_coherent(&ocpdev->dev, - sizeof(struct mal_descriptor) * - (NUM_TX_BUFF * maldata->num_tx_chans + - NUM_RX_BUFF * maldata->num_rx_chans), mal->bd_virt, - mal->bd_dma); + 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_VENDOR_IBM, .function = OCP_FUNC_MAL }, - { .vendor = OCP_VENDOR_INVALID} + {.vendor = OCP_ANY_ID,.function = OCP_FUNC_MAL}, + {.vendor = OCP_VENDOR_INVALID} }; static struct ocp_driver mal_driver = { @@ -570,14 +441,23 @@ static struct ocp_driver mal_driver = { .remove = mal_remove, }; -int __init mal_init(void) +static int __init init_mals(void) { - MAL_DBG(": init" NL); - return ocp_register_driver(&mal_driver); + int rc; + + rc = ocp_register_driver(&mal_driver); + if (rc < 0) { + ocp_unregister_driver(&mal_driver); + return -ENODEV; + } + + return 0; } -void __exit mal_exit(void) +static void __exit exit_mals(void) { - MAL_DBG(": exit" NL); ocp_unregister_driver(&mal_driver); } + +module_init(init_mals); +module_exit(exit_mals); diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_mal.h b/trunk/drivers/net/ibm_emac/ibm_emac_mal.h index 15b0bdae26ac..dd9f0dabc6e0 100644 --- a/trunk/drivers/net/ibm_emac/ibm_emac_mal.h +++ b/trunk/drivers/net/ibm_emac/ibm_emac_mal.h @@ -1,267 +1,131 @@ -/* - * drivers/net/ibm_emac/ibm_emac_mal.h - * - * Memory Access Layer (MAL) support - * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin or - * - * Based on original work by - * Armin Kuster - * 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. - * - */ -#ifndef __IBM_EMAC_MAL_H_ -#define __IBM_EMAC_MAL_H_ +#ifndef _IBM_EMAC_MAL_H +#define _IBM_EMAC_MAL_H -#include -#include #include -#include -#include +#define MAL_DT_ALIGN (4096) /* Alignment for each channel's descriptor table */ -/* - * These MAL "versions" probably aren't the real versions IBM uses for these - * MAL cores, I assigned them just to make #ifdefs in this file nicer and - * reflect the fact that 40x and 44x have slightly different MALs. --ebs - */ -#if defined(CONFIG_405GP) || defined(CONFIG_405GPR) || defined(CONFIG_405EP) || \ - defined(CONFIG_440EP) || defined(CONFIG_NP405H) -#define MAL_VERSION 1 -#elif defined(CONFIG_440GP) || defined(CONFIG_440GX) || defined(CONFIG_440SP) -#define MAL_VERSION 2 -#else -#error "Unknown SoC, please check chip manual and choose MAL 'version'" -#endif - -/* MALx DCR registers */ -#define MAL_CFG 0x00 -#define MAL_CFG_SR 0x80000000 -#define MAL_CFG_PLBB 0x00004000 -#define MAL_CFG_OPBBL 0x00000080 -#define MAL_CFG_EOPIE 0x00000004 -#define MAL_CFG_LEA 0x00000002 -#define MAL_CFG_SD 0x00000001 -#if MAL_VERSION == 1 -#define MAL_CFG_PLBP_MASK 0x00c00000 -#define MAL_CFG_PLBP_10 0x00800000 -#define MAL_CFG_GA 0x00200000 -#define MAL_CFG_OA 0x00100000 -#define MAL_CFG_PLBLE 0x00080000 -#define MAL_CFG_PLBT_MASK 0x00078000 -#define MAL_CFG_DEFAULT (MAL_CFG_PLBP_10 | MAL_CFG_PLBT_MASK) -#elif MAL_VERSION == 2 -#define MAL_CFG_RPP_MASK 0x00c00000 -#define MAL_CFG_RPP_10 0x00800000 -#define MAL_CFG_RMBS_MASK 0x00300000 -#define MAL_CFG_WPP_MASK 0x000c0000 -#define MAL_CFG_WPP_10 0x00080000 -#define MAL_CFG_WMBS_MASK 0x00030000 -#define MAL_CFG_PLBLE 0x00008000 -#define MAL_CFG_DEFAULT (MAL_CFG_RMBS_MASK | MAL_CFG_WMBS_MASK | \ - MAL_CFG_RPP_10 | MAL_CFG_WPP_10) -#else -#error "Unknown MAL version" -#endif - -#define MAL_ESR 0x01 -#define MAL_ESR_EVB 0x80000000 -#define MAL_ESR_CIDT 0x40000000 -#define MAL_ESR_CID_MASK 0x3e000000 -#define MAL_ESR_CID_SHIFT 25 -#define MAL_ESR_DE 0x00100000 -#define MAL_ESR_OTE 0x00040000 -#define MAL_ESR_OSE 0x00020000 -#define MAL_ESR_PEIN 0x00010000 -#define MAL_ESR_DEI 0x00000010 -#define MAL_ESR_OTEI 0x00000004 -#define MAL_ESR_OSEI 0x00000002 -#define MAL_ESR_PBEI 0x00000001 -#if MAL_VERSION == 1 -#define MAL_ESR_ONE 0x00080000 -#define MAL_ESR_ONEI 0x00000008 -#elif MAL_VERSION == 2 -#define MAL_ESR_PTE 0x00800000 -#define MAL_ESR_PRE 0x00400000 -#define MAL_ESR_PWE 0x00200000 -#define MAL_ESR_PTEI 0x00000080 -#define MAL_ESR_PREI 0x00000040 -#define MAL_ESR_PWEI 0x00000020 -#else -#error "Unknown MAL version" -#endif - -#define MAL_IER 0x02 -#define MAL_IER_DE 0x00000010 -#define MAL_IER_OTE 0x00000004 -#define MAL_IER_OE 0x00000002 -#define MAL_IER_PE 0x00000001 -#if MAL_VERSION == 1 -#define MAL_IER_NWE 0x00000008 -#define MAL_IER_SOC_EVENTS MAL_IER_NWE -#elif MAL_VERSION == 2 -#define MAL_IER_PT 0x00000080 -#define MAL_IER_PRE 0x00000040 -#define MAL_IER_PWE 0x00000020 -#define MAL_IER_SOC_EVENTS (MAL_IER_PT | MAL_IER_PRE | MAL_IER_PWE) -#else -#error "Unknown MAL version" -#endif -#define MAL_IER_EVENTS (MAL_IER_SOC_EVENTS | MAL_IER_OTE | \ - MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE) - -#define MAL_TXCASR 0x04 -#define MAL_TXCARR 0x05 -#define MAL_TXEOBISR 0x06 -#define MAL_TXDEIR 0x07 -#define MAL_RXCASR 0x10 -#define MAL_RXCARR 0x11 -#define MAL_RXEOBISR 0x12 -#define MAL_RXDEIR 0x13 -#define MAL_TXCTPR(n) ((n) + 0x20) -#define MAL_RXCTPR(n) ((n) + 0x40) -#define MAL_RCBS(n) ((n) + 0x60) - -/* In reality MAL can handle TX buffers up to 4095 bytes long, - * but this isn't a good round number :) --ebs - */ -#define MAL_MAX_TX_SIZE 4080 -#define MAL_MAX_RX_SIZE 4080 - -static inline int mal_rx_size(int len) -{ - len = (len + 0xf) & ~0xf; - return len > MAL_MAX_RX_SIZE ? MAL_MAX_RX_SIZE : len; -} - -static inline int mal_tx_chunks(int len) -{ - return (len + MAL_MAX_TX_SIZE - 1) / MAL_MAX_TX_SIZE; -} - -#define MAL_CHAN_MASK(n) (0x80000000 >> (n)) +#define MAL_CHAN_MASK(chan) (0x80000000 >> (chan)) /* MAL Buffer Descriptor structure */ struct mal_descriptor { - u16 ctrl; /* MAL / Commac status control bits */ - u16 data_len; /* Max length is 4K-1 (12 bits) */ - u32 data_ptr; /* pointer to actual data buffer */ -}; + unsigned short ctrl; /* MAL / Commac status control bits */ + short data_len; /* Max length is 4K-1 (12 bits) */ + unsigned char *data_ptr; /* pointer to actual data buffer */ +} __attribute__ ((packed)); /* the following defines are for the MadMAL status and control registers. */ /* MADMAL transmit and receive status/control bits */ -#define MAL_RX_CTRL_EMPTY 0x8000 -#define MAL_RX_CTRL_WRAP 0x4000 -#define MAL_RX_CTRL_CM 0x2000 -#define MAL_RX_CTRL_LAST 0x1000 -#define MAL_RX_CTRL_FIRST 0x0800 -#define MAL_RX_CTRL_INTR 0x0400 -#define MAL_RX_CTRL_SINGLE (MAL_RX_CTRL_LAST | MAL_RX_CTRL_FIRST) -#define MAL_IS_SINGLE_RX(ctrl) (((ctrl) & MAL_RX_CTRL_SINGLE) == MAL_RX_CTRL_SINGLE) - -#define MAL_TX_CTRL_READY 0x8000 -#define MAL_TX_CTRL_WRAP 0x4000 -#define MAL_TX_CTRL_CM 0x2000 -#define MAL_TX_CTRL_LAST 0x1000 -#define MAL_TX_CTRL_INTR 0x0400 +#define MAL_RX_CTRL_EMPTY 0x8000 +#define MAL_RX_CTRL_WRAP 0x4000 +#define MAL_RX_CTRL_CM 0x2000 +#define MAL_RX_CTRL_LAST 0x1000 +#define MAL_RX_CTRL_FIRST 0x0800 +#define MAL_RX_CTRL_INTR 0x0400 + +#define MAL_TX_CTRL_READY 0x8000 +#define MAL_TX_CTRL_WRAP 0x4000 +#define MAL_TX_CTRL_CM 0x2000 +#define MAL_TX_CTRL_LAST 0x1000 +#define MAL_TX_CTRL_INTR 0x0400 struct mal_commac_ops { - void (*poll_tx) (void *dev); - int (*poll_rx) (void *dev, int budget); - int (*peek_rx) (void *dev); - void (*rxde) (void *dev); + void (*txeob) (void *dev, u32 chanmask); + void (*txde) (void *dev, u32 chanmask); + void (*rxeob) (void *dev, u32 chanmask); + void (*rxde) (void *dev, u32 chanmask); }; struct mal_commac { - struct mal_commac_ops *ops; - void *dev; - struct list_head poll_list; - int rx_stopped; - - u32 tx_chan_mask; - u32 rx_chan_mask; - struct list_head list; + struct mal_commac_ops *ops; + void *dev; + u32 tx_chan_mask, rx_chan_mask; + struct list_head list; }; struct ibm_ocp_mal { - int dcrbase; - - struct list_head poll_list; - struct net_device poll_dev; + int dcrbase; - struct list_head list; - u32 tx_chan_mask; - u32 rx_chan_mask; + struct list_head commac; + u32 tx_chan_mask, rx_chan_mask; - dma_addr_t bd_dma; - struct mal_descriptor *bd_virt; + dma_addr_t tx_phys_addr; + struct mal_descriptor *tx_virt_addr; - struct ocp_def *def; + dma_addr_t rx_phys_addr; + struct mal_descriptor *rx_virt_addr; }; -static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg) +#define GET_MAL_STANZA(base,dcrn) \ + case base: \ + x = mfdcr(dcrn(base)); \ + break; + +#define SET_MAL_STANZA(base,dcrn, val) \ + case base: \ + mtdcr(dcrn(base), (val)); \ + break; + +#define GET_MAL0_STANZA(dcrn) GET_MAL_STANZA(DCRN_MAL_BASE,dcrn) +#define SET_MAL0_STANZA(dcrn,val) SET_MAL_STANZA(DCRN_MAL_BASE,dcrn,val) + +#ifdef DCRN_MAL1_BASE +#define GET_MAL1_STANZA(dcrn) GET_MAL_STANZA(DCRN_MAL1_BASE,dcrn) +#define SET_MAL1_STANZA(dcrn,val) SET_MAL_STANZA(DCRN_MAL1_BASE,dcrn,val) +#else /* ! DCRN_MAL1_BASE */ +#define GET_MAL1_STANZA(dcrn) +#define SET_MAL1_STANZA(dcrn,val) +#endif + +#define get_mal_dcrn(mal, dcrn) ({ \ + u32 x; \ + switch ((mal)->dcrbase) { \ + GET_MAL0_STANZA(dcrn) \ + GET_MAL1_STANZA(dcrn) \ + default: \ + x = 0; \ + BUG(); \ + } \ +x; }) + +#define set_mal_dcrn(mal, dcrn, val) do { \ + switch ((mal)->dcrbase) { \ + SET_MAL0_STANZA(dcrn,val) \ + SET_MAL1_STANZA(dcrn,val) \ + default: \ + BUG(); \ + } } while (0) + +static inline void mal_enable_tx_channels(struct ibm_ocp_mal *mal, u32 chanmask) { - return mfdcr(mal->dcrbase + reg); + set_mal_dcrn(mal, DCRN_MALTXCASR, + get_mal_dcrn(mal, DCRN_MALTXCASR) | chanmask); } -static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val) +static inline void mal_disable_tx_channels(struct ibm_ocp_mal *mal, + u32 chanmask) { - mtdcr(mal->dcrbase + reg, val); + set_mal_dcrn(mal, DCRN_MALTXCARR, chanmask); } -/* Register MAL devices */ -int mal_init(void) __init; -void mal_exit(void) __exit; - -int mal_register_commac(struct ibm_ocp_mal *mal, - struct mal_commac *commac) __init; -void mal_unregister_commac(struct ibm_ocp_mal *mal, - struct mal_commac *commac) __exit; -int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, unsigned long size); - -/* Returns BD ring offset for a particular channel - (in 'struct mal_descriptor' elements) -*/ -int mal_tx_bd_offset(struct ibm_ocp_mal *mal, int channel); -int mal_rx_bd_offset(struct ibm_ocp_mal *mal, int channel); - -void mal_enable_tx_channel(struct ibm_ocp_mal *mal, int channel); -void mal_disable_tx_channel(struct ibm_ocp_mal *mal, int channel); -void mal_enable_rx_channel(struct ibm_ocp_mal *mal, int channel); -void mal_disable_rx_channel(struct ibm_ocp_mal *mal, int channel); - -/* Add/remove EMAC to/from MAL polling list */ -void mal_poll_add(struct ibm_ocp_mal *mal, struct mal_commac *commac); -void mal_poll_del(struct ibm_ocp_mal *mal, struct mal_commac *commac); +static inline void mal_enable_rx_channels(struct ibm_ocp_mal *mal, u32 chanmask) +{ + set_mal_dcrn(mal, DCRN_MALRXCASR, + get_mal_dcrn(mal, DCRN_MALRXCASR) | chanmask); +} -/* Ethtool MAL registers */ -struct ibm_mal_regs { - u32 tx_count; - u32 rx_count; +static inline void mal_disable_rx_channels(struct ibm_ocp_mal *mal, + u32 chanmask) +{ + set_mal_dcrn(mal, DCRN_MALRXCARR, chanmask); +} - u32 cfg; - u32 esr; - u32 ier; - u32 tx_casr; - u32 tx_carr; - u32 tx_eobisr; - u32 tx_deir; - u32 rx_casr; - u32 rx_carr; - u32 rx_eobisr; - u32 rx_deir; - u32 tx_ctpr[32]; - u32 rx_ctpr[32]; - u32 rcbs[32]; -}; +extern int mal_register_commac(struct ibm_ocp_mal *mal, + struct mal_commac *commac); +extern int mal_unregister_commac(struct ibm_ocp_mal *mal, + struct mal_commac *commac); -int mal_get_regs_len(struct ibm_ocp_mal *mal); -void *mal_dump_regs(struct ibm_ocp_mal *mal, void *buf); +extern int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, + unsigned long size); -#endif /* __IBM_EMAC_MAL_H_ */ +#endif /* _IBM_EMAC_MAL_H */ diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_phy.c b/trunk/drivers/net/ibm_emac/ibm_emac_phy.c index a27e49cfe43b..14213f090e91 100644 --- a/trunk/drivers/net/ibm_emac/ibm_emac_phy.c +++ b/trunk/drivers/net/ibm_emac/ibm_emac_phy.c @@ -1,80 +1,96 @@ /* - * drivers/net/ibm_emac/ibm_emac_phy.c + * ibm_ocp_phy.c * - * Driver for PowerPC 4xx on-chip ethernet controller, PHY support. - * Borrowed from sungem_phy.c, though I only kept the generic MII + * PHY drivers for the ibm ocp ethernet driver. Borrowed + * from sungem_phy.c, though I only kept the generic MII * driver for now. * * This file should be shared with other drivers or eventually * merged as the "low level" part of miilib * * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org) - * (c) 2004-2005, Eugene Surovegin * */ + #include + #include + #include +#include #include #include +#include #include #include #include -#include - #include "ibm_emac_phy.h" -static inline int phy_read(struct mii_phy *phy, int reg) -{ - return phy->mdio_read(phy->dev, phy->address, reg); -} - -static inline void phy_write(struct mii_phy *phy, int reg, int val) +static int reset_one_mii_phy(struct mii_phy *phy, int phy_id) { - phy->mdio_write(phy->dev, phy->address, reg, val); -} - -int mii_reset_phy(struct mii_phy *phy) -{ - int val; + u16 val; int limit = 10000; - val = phy_read(phy, MII_BMCR); + val = __phy_read(phy, phy_id, MII_BMCR); val &= ~BMCR_ISOLATE; val |= BMCR_RESET; - phy_write(phy, MII_BMCR, val); + __phy_write(phy, phy_id, MII_BMCR, val); - udelay(300); + udelay(100); while (limit--) { - val = phy_read(phy, MII_BMCR); - if (val >= 0 && (val & BMCR_RESET) == 0) + val = __phy_read(phy, phy_id, MII_BMCR); + if ((val & BMCR_RESET) == 0) break; udelay(10); } if ((val & BMCR_ISOLATE) && limit > 0) - phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE); + __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE); + + return (limit <= 0); +} + +static int cis8201_init(struct mii_phy *phy) +{ + u16 epcr; + + epcr = phy_read(phy, MII_CIS8201_EPCR); + epcr &= ~EPCR_MODE_MASK; + + switch (phy->mode) { + case PHY_MODE_TBI: + epcr |= EPCR_TBI_MODE; + break; + case PHY_MODE_RTBI: + epcr |= EPCR_RTBI_MODE; + break; + case PHY_MODE_GMII: + epcr |= EPCR_GMII_MODE; + break; + case PHY_MODE_RGMII: + default: + epcr |= EPCR_RGMII_MODE; + } - return limit <= 0; + phy_write(phy, MII_CIS8201_EPCR, epcr); + + return 0; } static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) { - int ctl, adv; + u16 ctl, adv; - phy->autoneg = AUTONEG_ENABLE; + phy->autoneg = 1; phy->speed = SPEED_10; phy->duplex = DUPLEX_HALF; - phy->pause = phy->asym_pause = 0; + phy->pause = 0; phy->advertising = advertise; /* Setup standard advertise */ adv = phy_read(phy, MII_ADVERTISE); - if (adv < 0) - return adv; - adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | - ADVERTISE_PAUSE_ASYM); + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); if (advertise & ADVERTISED_10baseT_Half) adv |= ADVERTISE_10HALF; if (advertise & ADVERTISED_10baseT_Full) @@ -83,25 +99,8 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) adv |= ADVERTISE_100HALF; if (advertise & ADVERTISED_100baseT_Full) adv |= ADVERTISE_100FULL; - if (advertise & ADVERTISED_Pause) - adv |= ADVERTISE_PAUSE_CAP; - if (advertise & ADVERTISED_Asym_Pause) - adv |= ADVERTISE_PAUSE_ASYM; phy_write(phy, MII_ADVERTISE, adv); - if (phy->features & - (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) { - adv = phy_read(phy, MII_CTRL1000); - if (adv < 0) - return adv; - adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); - if (advertise & ADVERTISED_1000baseT_Full) - adv |= ADVERTISE_1000FULL; - if (advertise & ADVERTISED_1000baseT_Half) - adv |= ADVERTISE_1000HALF; - phy_write(phy, MII_CTRL1000, adv); - } - /* Start/Restart aneg */ ctl = phy_read(phy, MII_BMCR); ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); @@ -112,16 +111,14 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) { - int ctl; + u16 ctl; - phy->autoneg = AUTONEG_DISABLE; + phy->autoneg = 0; phy->speed = speed; phy->duplex = fd; - phy->pause = phy->asym_pause = 0; + phy->pause = 0; ctl = phy_read(phy, MII_BMCR); - if (ctl < 0) - return ctl; ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE); /* First reset the PHY */ @@ -135,8 +132,6 @@ static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) ctl |= BMCR_SPEED100; break; case SPEED_1000: - ctl |= BMCR_SPEED1000; - break; default: return -EINVAL; } @@ -149,143 +144,112 @@ static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) static int genmii_poll_link(struct mii_phy *phy) { - int status; + u16 status; - /* Clear latched value with dummy read */ - phy_read(phy, MII_BMSR); + (void)phy_read(phy, MII_BMSR); status = phy_read(phy, MII_BMSR); - if (status < 0 || (status & BMSR_LSTATUS) == 0) + if ((status & BMSR_LSTATUS) == 0) return 0; - if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE)) + if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE)) return 0; return 1; } -static int genmii_read_link(struct mii_phy *phy) -{ - if (phy->autoneg == AUTONEG_ENABLE) { - int glpa = 0; - int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE); - if (lpa < 0) - return lpa; - - if (phy->features & - (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) { - int adv = phy_read(phy, MII_CTRL1000); - glpa = phy_read(phy, MII_STAT1000); - - if (glpa < 0 || adv < 0) - return adv; +#define MII_CIS8201_ACSR 0x1c +#define ACSR_DUPLEX_STATUS 0x0020 +#define ACSR_SPEED_1000BASET 0x0010 +#define ACSR_SPEED_100BASET 0x0008 - glpa &= adv << 2; - } - - phy->speed = SPEED_10; - phy->duplex = DUPLEX_HALF; - phy->pause = phy->asym_pause = 0; - - if (glpa & (LPA_1000FULL | LPA_1000HALF)) { - phy->speed = SPEED_1000; - if (glpa & LPA_1000FULL) - phy->duplex = DUPLEX_FULL; - } else if (lpa & (LPA_100FULL | LPA_100HALF)) { - phy->speed = SPEED_100; - if (lpa & LPA_100FULL) - phy->duplex = DUPLEX_FULL; - } else if (lpa & LPA_10FULL) - phy->duplex = DUPLEX_FULL; +static int cis8201_read_link(struct mii_phy *phy) +{ + u16 acsr; - if (phy->duplex == DUPLEX_FULL) { - phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; - phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; - } - } else { - int bmcr = phy_read(phy, MII_BMCR); - if (bmcr < 0) - return bmcr; + if (phy->autoneg) { + acsr = phy_read(phy, MII_CIS8201_ACSR); - if (bmcr & BMCR_FULLDPLX) + if (acsr & ACSR_DUPLEX_STATUS) phy->duplex = DUPLEX_FULL; else phy->duplex = DUPLEX_HALF; - if (bmcr & BMCR_SPEED1000) + if (acsr & ACSR_SPEED_1000BASET) { phy->speed = SPEED_1000; - else if (bmcr & BMCR_SPEED100) + } else if (acsr & ACSR_SPEED_100BASET) phy->speed = SPEED_100; else phy->speed = SPEED_10; - - phy->pause = phy->asym_pause = 0; + phy->pause = 0; } + /* On non-aneg, we assume what we put in BMCR is the speed, + * though magic-aneg shouldn't prevent this case from occurring + */ + return 0; } -/* Generic implementation for most 10/100/1000 PHYs */ -static struct mii_phy_ops generic_phy_ops = { - .setup_aneg = genmii_setup_aneg, - .setup_forced = genmii_setup_forced, - .poll_link = genmii_poll_link, - .read_link = genmii_read_link -}; - -static struct mii_phy_def genmii_phy_def = { - .phy_id = 0x00000000, - .phy_id_mask = 0x00000000, - .name = "Generic MII", - .ops = &generic_phy_ops -}; - -/* CIS8201 */ -#define MII_CIS8201_EPCR 0x17 -#define EPCR_MODE_MASK 0x3000 -#define EPCR_GMII_MODE 0x0000 -#define EPCR_RGMII_MODE 0x1000 -#define EPCR_TBI_MODE 0x2000 -#define EPCR_RTBI_MODE 0x3000 - -static int cis8201_init(struct mii_phy *phy) +static int genmii_read_link(struct mii_phy *phy) { - int epcr; + u16 lpa; - epcr = phy_read(phy, MII_CIS8201_EPCR); - if (epcr < 0) - return epcr; + if (phy->autoneg) { + lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE); - epcr &= ~EPCR_MODE_MASK; + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = 0; - switch (phy->mode) { - case PHY_MODE_TBI: - epcr |= EPCR_TBI_MODE; - break; - case PHY_MODE_RTBI: - epcr |= EPCR_RTBI_MODE; - break; - case PHY_MODE_GMII: - epcr |= EPCR_GMII_MODE; - break; - case PHY_MODE_RGMII: - default: - epcr |= EPCR_RGMII_MODE; + if (lpa & (LPA_100FULL | LPA_100HALF)) { + phy->speed = SPEED_100; + if (lpa & LPA_100FULL) + phy->duplex = DUPLEX_FULL; + } else if (lpa & LPA_10FULL) + phy->duplex = DUPLEX_FULL; } - - phy_write(phy, MII_CIS8201_EPCR, epcr); + /* On non-aneg, we assume what we put in BMCR is the speed, + * though magic-aneg shouldn't prevent this case from occurring + */ return 0; } +#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII) +#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ + SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) + +/* CIS8201 phy ops */ static struct mii_phy_ops cis8201_phy_ops = { - .init = cis8201_init, - .setup_aneg = genmii_setup_aneg, - .setup_forced = genmii_setup_forced, - .poll_link = genmii_poll_link, - .read_link = genmii_read_link + init:cis8201_init, + setup_aneg:genmii_setup_aneg, + setup_forced:genmii_setup_forced, + poll_link:genmii_poll_link, + read_link:cis8201_read_link +}; + +/* Generic implementation for most 10/100 PHYs */ +static struct mii_phy_ops generic_phy_ops = { + setup_aneg:genmii_setup_aneg, + setup_forced:genmii_setup_forced, + poll_link:genmii_poll_link, + read_link:genmii_read_link }; static struct mii_phy_def cis8201_phy_def = { - .phy_id = 0x000fc410, - .phy_id_mask = 0x000ffff0, - .name = "CIS8201 Gigabit Ethernet", - .ops = &cis8201_phy_ops + phy_id:0x000fc410, + phy_id_mask:0x000ffff0, + name:"CIS8201 Gigabit Ethernet", + features:MII_GBIT_FEATURES, + magic_aneg:0, + ops:&cis8201_phy_ops +}; + +static struct mii_phy_def genmii_phy_def = { + phy_id:0x00000000, + phy_id_mask:0x00000000, + name:"Generic MII", + features:MII_BASIC_FEATURES, + magic_aneg:0, + ops:&generic_phy_ops }; static struct mii_phy_def *mii_phy_table[] = { @@ -294,60 +258,39 @@ static struct mii_phy_def *mii_phy_table[] = { NULL }; -int mii_phy_probe(struct mii_phy *phy, int address) +int mii_phy_probe(struct mii_phy *phy, int mii_id) { + int rc; + u32 id; struct mii_phy_def *def; int i; - u32 id; - phy->autoneg = AUTONEG_DISABLE; + phy->autoneg = 0; phy->advertising = 0; - phy->address = address; - phy->speed = SPEED_10; - phy->duplex = DUPLEX_HALF; - phy->pause = phy->asym_pause = 0; - - /* Take PHY out of isolate mode and reset it. */ - if (mii_reset_phy(phy)) + phy->mii_id = mii_id; + phy->speed = 0; + phy->duplex = 0; + phy->pause = 0; + + /* Take PHY out of isloate mode and reset it. */ + rc = reset_one_mii_phy(phy, mii_id); + if (rc) return -ENODEV; /* Read ID and find matching entry */ - id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2); + id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2)) + & 0xfffffff0; for (i = 0; (def = mii_phy_table[i]) != NULL; i++) if ((id & def->phy_id_mask) == def->phy_id) break; /* Should never be NULL (we have a generic entry), but... */ - if (!def) + if (def == NULL) return -ENODEV; phy->def = def; - /* Determine PHY features if needed */ - phy->features = def->features; - if (!phy->features) { - u16 bmsr = phy_read(phy, MII_BMSR); - if (bmsr & BMSR_ANEGCAPABLE) - phy->features |= SUPPORTED_Autoneg; - if (bmsr & BMSR_10HALF) - phy->features |= SUPPORTED_10baseT_Half; - if (bmsr & BMSR_10FULL) - phy->features |= SUPPORTED_10baseT_Full; - if (bmsr & BMSR_100HALF) - phy->features |= SUPPORTED_100baseT_Half; - if (bmsr & BMSR_100FULL) - phy->features |= SUPPORTED_100baseT_Full; - if (bmsr & BMSR_ESTATEN) { - u16 esr = phy_read(phy, MII_ESTATUS); - if (esr & ESTATUS_1000_TFULL) - phy->features |= SUPPORTED_1000baseT_Full; - if (esr & ESTATUS_1000_THALF) - phy->features |= SUPPORTED_1000baseT_Half; - } - phy->features |= SUPPORTED_MII; - } - /* Setup default advertising */ - phy->advertising = phy->features; + phy->advertising = def->features; return 0; } diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_phy.h b/trunk/drivers/net/ibm_emac/ibm_emac_phy.h index a70e0fea54c4..61afbea96563 100644 --- a/trunk/drivers/net/ibm_emac/ibm_emac_phy.h +++ b/trunk/drivers/net/ibm_emac/ibm_emac_phy.h @@ -1,25 +1,65 @@ + /* - * drivers/net/ibm_emac/ibm_emac_phy.h - * - * Driver for PowerPC 4xx on-chip ethernet controller, PHY support + * ibm_emac_phy.h * - * Benjamin Herrenschmidt - * February 2003 * - * Minor additions by Eugene Surovegin , 2004 + * Benjamin Herrenschmidt + * February 2003 * * 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. + * 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. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * * * This file basically duplicates sungem_phy.{c,h} with different PHYs * supported. I'm looking into merging that in a single mii layer more * flexible than mii.c */ -#ifndef _IBM_OCP_PHY_H_ -#define _IBM_OCP_PHY_H_ +#ifndef _IBM_EMAC_PHY_H_ +#define _IBM_EMAC_PHY_H_ + +/* + * PHY mode settings + * Used for multi-mode capable PHYs + */ +#define PHY_MODE_NA 0 +#define PHY_MODE_MII 1 +#define PHY_MODE_RMII 2 +#define PHY_MODE_SMII 3 +#define PHY_MODE_RGMII 4 +#define PHY_MODE_TBI 5 +#define PHY_MODE_GMII 6 +#define PHY_MODE_RTBI 7 +#define PHY_MODE_SGMII 8 + +/* + * PHY specific registers/values + */ + +/* CIS8201 */ +#define MII_CIS8201_EPCR 0x17 +#define EPCR_MODE_MASK 0x3000 +#define EPCR_GMII_MODE 0x0000 +#define EPCR_RGMII_MODE 0x1000 +#define EPCR_TBI_MODE 0x2000 +#define EPCR_RTBI_MODE 0x3000 struct mii_phy; @@ -37,8 +77,7 @@ struct mii_phy_ops { struct mii_phy_def { u32 phy_id; /* Concatenated ID1 << 16 | ID2 */ u32 phy_id_mask; /* Significant bits */ - u32 features; /* Ethtool SUPPORTED_* defines or - 0 for autodetect */ + u32 features; /* Ethtool SUPPORTED_* defines */ int magic_aneg; /* Autoneg does all speed test for us */ const char *name; const struct mii_phy_ops *ops; @@ -47,11 +86,8 @@ struct mii_phy_def { /* An instance of a PHY, partially borrowed from mii_if_info */ struct mii_phy { struct mii_phy_def *def; - u32 advertising; /* Ethtool ADVERTISED_* defines */ - u32 features; /* Copied from mii_phy_def.features - or determined automaticaly */ - int address; /* PHY address */ - int mode; /* PHY mode */ + int advertising; + int mii_id; /* 1: autoneg enabled, 0: disabled */ int autoneg; @@ -62,19 +98,40 @@ struct mii_phy { int speed; int duplex; int pause; - int asym_pause; + + /* PHY mode - if needed */ + int mode; /* Provided by host chip */ struct net_device *dev; - int (*mdio_read) (struct net_device * dev, int addr, int reg); - void (*mdio_write) (struct net_device * dev, int addr, int reg, + int (*mdio_read) (struct net_device * dev, int mii_id, int reg); + void (*mdio_write) (struct net_device * dev, int mii_id, int reg, int val); }; /* Pass in a struct mii_phy with dev, mdio_read and mdio_write * filled, the remaining fields will be filled on return */ -int mii_phy_probe(struct mii_phy *phy, int address); -int mii_reset_phy(struct mii_phy *phy); +extern int mii_phy_probe(struct mii_phy *phy, int mii_id); + +static inline int __phy_read(struct mii_phy *phy, int id, int reg) +{ + return phy->mdio_read(phy->dev, id, reg); +} + +static inline void __phy_write(struct mii_phy *phy, int id, int reg, int val) +{ + phy->mdio_write(phy->dev, id, reg, val); +} + +static inline int phy_read(struct mii_phy *phy, int reg) +{ + return phy->mdio_read(phy->dev, phy->mii_id, reg); +} + +static inline void phy_write(struct mii_phy *phy, int reg, int val) +{ + phy->mdio_write(phy->dev, phy->mii_id, reg, val); +} -#endif /* _IBM_OCP_PHY_H_ */ +#endif /* _IBM_EMAC_PHY_H_ */ diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_rgmii.c b/trunk/drivers/net/ibm_emac/ibm_emac_rgmii.c deleted file mode 100644 index f0b1ffb2dbbf..000000000000 --- a/trunk/drivers/net/ibm_emac/ibm_emac_rgmii.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_rgmii.c - * - * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support. - * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin or - * - * Based on original work by - * Matt Porter - * Copyright 2004 MontaVista Software, 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 -#include -#include -#include - -#include "ibm_emac_core.h" -#include "ibm_emac_debug.h" - -/* RGMIIx_FER */ -#define RGMII_FER_MASK(idx) (0x7 << ((idx) * 4)) -#define RGMII_FER_RTBI(idx) (0x4 << ((idx) * 4)) -#define RGMII_FER_RGMII(idx) (0x5 << ((idx) * 4)) -#define RGMII_FER_TBI(idx) (0x6 << ((idx) * 4)) -#define RGMII_FER_GMII(idx) (0x7 << ((idx) * 4)) - -/* RGMIIx_SSR */ -#define RGMII_SSR_MASK(idx) (0x7 << ((idx) * 8)) -#define RGMII_SSR_100(idx) (0x2 << ((idx) * 8)) -#define RGMII_SSR_1000(idx) (0x4 << ((idx) * 8)) - -/* RGMII bridge supports only GMII/TBI and RGMII/RTBI PHYs */ -static inline int rgmii_valid_mode(int phy_mode) -{ - return phy_mode == PHY_MODE_GMII || - phy_mode == PHY_MODE_RGMII || - phy_mode == PHY_MODE_TBI || - phy_mode == PHY_MODE_RTBI; -} - -static inline const char *rgmii_mode_name(int mode) -{ - switch (mode) { - case PHY_MODE_RGMII: - return "RGMII"; - case PHY_MODE_TBI: - return "TBI"; - case PHY_MODE_GMII: - return "GMII"; - case PHY_MODE_RTBI: - return "RTBI"; - default: - BUG(); - } -} - -static inline u32 rgmii_mode_mask(int mode, int input) -{ - switch (mode) { - case PHY_MODE_RGMII: - return RGMII_FER_RGMII(input); - case PHY_MODE_TBI: - return RGMII_FER_TBI(input); - case PHY_MODE_GMII: - return RGMII_FER_GMII(input); - case PHY_MODE_RTBI: - return RGMII_FER_RTBI(input); - default: - BUG(); - } -} - -static int __init rgmii_init(struct ocp_device *ocpdev, int input, int mode) -{ - struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); - struct rgmii_regs *p; - - RGMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, mode); - - if (!dev) { - dev = kzalloc(sizeof(struct ibm_ocp_rgmii), GFP_KERNEL); - if (!dev) { - printk(KERN_ERR - "rgmii%d: couldn't allocate device structure!\n", - ocpdev->def->index); - return -ENOMEM; - } - - p = (struct rgmii_regs *)ioremap(ocpdev->def->paddr, - sizeof(struct rgmii_regs)); - if (!p) { - printk(KERN_ERR - "rgmii%d: could not ioremap device registers!\n", - ocpdev->def->index); - kfree(dev); - return -ENOMEM; - } - - dev->base = p; - ocp_set_drvdata(ocpdev, dev); - - /* Disable all inputs by default */ - out_be32(&p->fer, 0); - } else - p = dev->base; - - /* Enable this input */ - out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input)); - - printk(KERN_NOTICE "rgmii%d: input %d in %s mode\n", - ocpdev->def->index, input, rgmii_mode_name(mode)); - - ++dev->users; - return 0; -} - -int __init rgmii_attach(void *emac) -{ - struct ocp_enet_private *dev = emac; - struct ocp_func_emac_data *emacdata = dev->def->additions; - - /* Check if we need to attach to a RGMII */ - if (emacdata->rgmii_idx >= 0 && rgmii_valid_mode(emacdata->phy_mode)) { - dev->rgmii_input = emacdata->rgmii_mux; - dev->rgmii_dev = - ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_RGMII, - emacdata->rgmii_idx); - if (!dev->rgmii_dev) { - printk(KERN_ERR "emac%d: unknown rgmii%d!\n", - dev->def->index, emacdata->rgmii_idx); - return -ENODEV; - } - if (rgmii_init - (dev->rgmii_dev, dev->rgmii_input, emacdata->phy_mode)) { - printk(KERN_ERR - "emac%d: rgmii%d initialization failed!\n", - dev->def->index, emacdata->rgmii_idx); - return -ENODEV; - } - } - return 0; -} - -void rgmii_set_speed(struct ocp_device *ocpdev, int input, int speed) -{ - struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); - u32 ssr = in_be32(&dev->base->ssr) & ~RGMII_SSR_MASK(input); - - RGMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed); - - if (speed == SPEED_1000) - ssr |= RGMII_SSR_1000(input); - else if (speed == SPEED_100) - ssr |= RGMII_SSR_100(input); - - out_be32(&dev->base->ssr, ssr); -} - -void __exit __rgmii_fini(struct ocp_device *ocpdev, int input) -{ - struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); - BUG_ON(!dev || dev->users == 0); - - RGMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input); - - /* Disable this input */ - out_be32(&dev->base->fer, - in_be32(&dev->base->fer) & ~RGMII_FER_MASK(input)); - - if (!--dev->users) { - /* Free everything if this is the last user */ - ocp_set_drvdata(ocpdev, NULL); - iounmap((void *)dev->base); - kfree(dev); - } -} - -int __rgmii_get_regs_len(struct ocp_device *ocpdev) -{ - return sizeof(struct emac_ethtool_regs_subhdr) + - sizeof(struct rgmii_regs); -} - -void *rgmii_dump_regs(struct ocp_device *ocpdev, void *buf) -{ - struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); - struct emac_ethtool_regs_subhdr *hdr = buf; - struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1); - - hdr->version = 0; - hdr->index = ocpdev->def->index; - memcpy_fromio(regs, dev->base, sizeof(struct rgmii_regs)); - return regs + 1; -} diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_rgmii.h b/trunk/drivers/net/ibm_emac/ibm_emac_rgmii.h index a1ffb8a44fff..49f188f4ea6e 100644 --- a/trunk/drivers/net/ibm_emac/ibm_emac_rgmii.h +++ b/trunk/drivers/net/ibm_emac/ibm_emac_rgmii.h @@ -1,7 +1,5 @@ /* - * drivers/net/ibm_emac/ibm_emac_rgmii.c - * - * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support. + * Defines for the IBM RGMII bridge * * Based on ocp_zmii.h/ibm_emac_zmii.h * Armin Kuster akuster@mvista.com @@ -9,9 +7,6 @@ * Copyright 2004 MontaVista Software, Inc. * Matt Porter * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin or - * * 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 @@ -24,42 +19,47 @@ #include /* RGMII bridge */ -struct rgmii_regs { +typedef struct rgmii_regs { u32 fer; /* Function enable register */ u32 ssr; /* Speed select register */ -}; +} rgmii_t; + +#define RGMII_INPUTS 4 /* RGMII device */ struct ibm_ocp_rgmii { struct rgmii_regs *base; + int mode[RGMII_INPUTS]; int users; /* number of EMACs using this RGMII bridge */ }; -#ifdef CONFIG_IBM_EMAC_RGMII -int rgmii_attach(void *emac) __init; +/* Fuctional Enable Reg */ +#define RGMII_FER_MASK(x) (0x00000007 << (4*x)) +#define RGMII_RTBI 0x00000004 +#define RGMII_RGMII 0x00000005 +#define RGMII_TBI 0x00000006 +#define RGMII_GMII 0x00000007 + +/* Speed Selection reg */ -void __rgmii_fini(struct ocp_device *ocpdev, int input) __exit; -static inline void rgmii_fini(struct ocp_device *ocpdev, int input) -{ - if (ocpdev) - __rgmii_fini(ocpdev, input); -} +#define RGMII_SP2_100 0x00000002 +#define RGMII_SP2_1000 0x00000004 +#define RGMII_SP3_100 0x00000200 +#define RGMII_SP3_1000 0x00000400 -void rgmii_set_speed(struct ocp_device *ocpdev, int input, int speed); +#define RGMII_MII2_SPDMASK 0x00000007 +#define RGMII_MII3_SPDMASK 0x00000700 -int __rgmii_get_regs_len(struct ocp_device *ocpdev); -static inline int rgmii_get_regs_len(struct ocp_device *ocpdev) -{ - return ocpdev ? __rgmii_get_regs_len(ocpdev) : 0; -} +#define RGMII_MII2_100MB RGMII_SP2_100 & ~RGMII_SP2_1000 +#define RGMII_MII2_1000MB RGMII_SP2_1000 & ~RGMII_SP2_100 +#define RGMII_MII2_10MB ~(RGMII_SP2_100 | RGMII_SP2_1000) +#define RGMII_MII3_100MB RGMII_SP3_100 & ~RGMII_SP3_1000 +#define RGMII_MII3_1000MB RGMII_SP3_1000 & ~RGMII_SP3_100 +#define RGMII_MII3_10MB ~(RGMII_SP3_100 | RGMII_SP3_1000) -void *rgmii_dump_regs(struct ocp_device *ocpdev, void *buf); -#else -# define rgmii_attach(x) 0 -# define rgmii_fini(x,y) ((void)0) -# define rgmii_set_speed(x,y,z) ((void)0) -# define rgmii_get_regs_len(x) 0 -# define rgmii_dump_regs(x,buf) (buf) -#endif /* !CONFIG_IBM_EMAC_RGMII */ +#define RTBI 0 +#define RGMII 1 +#define TBI 2 +#define GMII 3 #endif /* _IBM_EMAC_RGMII_H_ */ diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_tah.c b/trunk/drivers/net/ibm_emac/ibm_emac_tah.c deleted file mode 100644 index af08afc22f9f..000000000000 --- a/trunk/drivers/net/ibm_emac/ibm_emac_tah.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_tah.c - * - * Driver for PowerPC 4xx on-chip ethernet controller, TAH support. - * - * Copyright 2004 MontaVista Software, Inc. - * Matt Porter - * - * Copyright (c) 2005 Eugene Surovegin - * - * 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 -#include - -#include "ibm_emac_core.h" - -static int __init tah_init(struct ocp_device *ocpdev) -{ - struct tah_regs *p; - - if (ocp_get_drvdata(ocpdev)) { - printk(KERN_ERR "tah%d: already in use!\n", ocpdev->def->index); - return -EBUSY; - } - - /* Initialize TAH and enable IPv4 checksum verification, no TSO yet */ - p = (struct tah_regs *)ioremap(ocpdev->def->paddr, sizeof(*p)); - if (!p) { - printk(KERN_ERR "tah%d: could not ioremap device registers!\n", - ocpdev->def->index); - return -ENOMEM; - } - ocp_set_drvdata(ocpdev, p); - __tah_reset(ocpdev); - - return 0; -} - -int __init tah_attach(void *emac) -{ - struct ocp_enet_private *dev = emac; - struct ocp_func_emac_data *emacdata = dev->def->additions; - - /* Check if we need to attach to a TAH */ - if (emacdata->tah_idx >= 0) { - dev->tah_dev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_TAH, - emacdata->tah_idx); - if (!dev->tah_dev) { - printk(KERN_ERR "emac%d: unknown tah%d!\n", - dev->def->index, emacdata->tah_idx); - return -ENODEV; - } - if (tah_init(dev->tah_dev)) { - printk(KERN_ERR - "emac%d: tah%d initialization failed!\n", - dev->def->index, emacdata->tah_idx); - return -ENODEV; - } - } - return 0; -} - -void __exit __tah_fini(struct ocp_device *ocpdev) -{ - struct tah_regs *p = ocp_get_drvdata(ocpdev); - BUG_ON(!p); - ocp_set_drvdata(ocpdev, NULL); - iounmap((void *)p); -} - -void __tah_reset(struct ocp_device *ocpdev) -{ - struct tah_regs *p = ocp_get_drvdata(ocpdev); - int n; - - /* Reset TAH */ - out_be32(&p->mr, TAH_MR_SR); - n = 100; - while ((in_be32(&p->mr) & TAH_MR_SR) && n) - --n; - - if (unlikely(!n)) - printk(KERN_ERR "tah%d: reset timeout\n", ocpdev->def->index); - - /* 10KB TAH TX FIFO accomodates the max MTU of 9000 */ - out_be32(&p->mr, - TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP | - TAH_MR_DIG); -} - -int __tah_get_regs_len(struct ocp_device *ocpdev) -{ - return sizeof(struct emac_ethtool_regs_subhdr) + - sizeof(struct tah_regs); -} - -void *tah_dump_regs(struct ocp_device *ocpdev, void *buf) -{ - struct tah_regs *dev = ocp_get_drvdata(ocpdev); - struct emac_ethtool_regs_subhdr *hdr = buf; - struct tah_regs *regs = (struct tah_regs *)(hdr + 1); - - hdr->version = 0; - hdr->index = ocpdev->def->index; - memcpy_fromio(regs, dev, sizeof(struct tah_regs)); - return regs + 1; -} diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_tah.h b/trunk/drivers/net/ibm_emac/ibm_emac_tah.h index 9299b5dd7eb1..ecfc69805521 100644 --- a/trunk/drivers/net/ibm_emac/ibm_emac_tah.h +++ b/trunk/drivers/net/ibm_emac/ibm_emac_tah.h @@ -1,13 +1,9 @@ /* - * drivers/net/ibm_emac/ibm_emac_tah.h - * - * Driver for PowerPC 4xx on-chip ethernet controller, TAH support. + * Defines for the IBM TAH * * Copyright 2004 MontaVista Software, Inc. * Matt Porter * - * Copyright (c) 2005 Eugene Surovegin - * * 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 @@ -17,72 +13,36 @@ #ifndef _IBM_EMAC_TAH_H #define _IBM_EMAC_TAH_H -#include -#include -#include - /* TAH */ -struct tah_regs { - u32 revid; +typedef struct tah_regs { + u32 tah_revid; u32 pad[3]; - u32 mr; - u32 ssr0; - u32 ssr1; - u32 ssr2; - u32 ssr3; - u32 ssr4; - u32 ssr5; - u32 tsr; -}; + u32 tah_mr; + u32 tah_ssr0; + u32 tah_ssr1; + u32 tah_ssr2; + u32 tah_ssr3; + u32 tah_ssr4; + u32 tah_ssr5; + u32 tah_tsr; +} tah_t; /* TAH engine */ -#define TAH_MR_CVR 0x80000000 -#define TAH_MR_SR 0x40000000 -#define TAH_MR_ST_256 0x01000000 -#define TAH_MR_ST_512 0x02000000 -#define TAH_MR_ST_768 0x03000000 -#define TAH_MR_ST_1024 0x04000000 -#define TAH_MR_ST_1280 0x05000000 -#define TAH_MR_ST_1536 0x06000000 -#define TAH_MR_TFS_16KB 0x00000000 -#define TAH_MR_TFS_2KB 0x00200000 -#define TAH_MR_TFS_4KB 0x00400000 -#define TAH_MR_TFS_6KB 0x00600000 -#define TAH_MR_TFS_8KB 0x00800000 -#define TAH_MR_TFS_10KB 0x00a00000 -#define TAH_MR_DTFP 0x00100000 -#define TAH_MR_DIG 0x00080000 - -#ifdef CONFIG_IBM_EMAC_TAH -int tah_attach(void *emac) __init; - -void __tah_fini(struct ocp_device *ocpdev) __exit; -static inline void tah_fini(struct ocp_device *ocpdev) -{ - if (ocpdev) - __tah_fini(ocpdev); -} - -void __tah_reset(struct ocp_device *ocpdev); -static inline void tah_reset(struct ocp_device *ocpdev) -{ - if (ocpdev) - __tah_reset(ocpdev); -} - -int __tah_get_regs_len(struct ocp_device *ocpdev); -static inline int tah_get_regs_len(struct ocp_device *ocpdev) -{ - return ocpdev ? __tah_get_regs_len(ocpdev) : 0; -} - -void *tah_dump_regs(struct ocp_device *ocpdev, void *buf); -#else -# define tah_attach(x) 0 -# define tah_fini(x) ((void)0) -# define tah_reset(x) ((void)0) -# define tah_get_regs_len(x) 0 -# define tah_dump_regs(x,buf) (buf) -#endif /* !CONFIG_IBM_EMAC_TAH */ +#define TAH_MR_CVR 0x80000000 +#define TAH_MR_SR 0x40000000 +#define TAH_MR_ST_256 0x01000000 +#define TAH_MR_ST_512 0x02000000 +#define TAH_MR_ST_768 0x03000000 +#define TAH_MR_ST_1024 0x04000000 +#define TAH_MR_ST_1280 0x05000000 +#define TAH_MR_ST_1536 0x06000000 +#define TAH_MR_TFS_16KB 0x00000000 +#define TAH_MR_TFS_2KB 0x00200000 +#define TAH_MR_TFS_4KB 0x00400000 +#define TAH_MR_TFS_6KB 0x00600000 +#define TAH_MR_TFS_8KB 0x00800000 +#define TAH_MR_TFS_10KB 0x00a00000 +#define TAH_MR_DTFP 0x00100000 +#define TAH_MR_DIG 0x00080000 #endif /* _IBM_EMAC_TAH_H */ diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_zmii.c b/trunk/drivers/net/ibm_emac/ibm_emac_zmii.c deleted file mode 100644 index 35c1185079ed..000000000000 --- a/trunk/drivers/net/ibm_emac/ibm_emac_zmii.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * drivers/net/ibm_emac/ibm_emac_zmii.c - * - * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support. - * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin or - * - * Based on original work by - * Armin Kuster - * Copyright 2001 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 -#include -#include -#include - -#include "ibm_emac_core.h" -#include "ibm_emac_debug.h" - -/* ZMIIx_FER */ -#define ZMII_FER_MDI(idx) (0x80000000 >> ((idx) * 4)) -#define ZMII_FER_MDI_ALL (ZMII_FER_MDI(0) | ZMII_FER_MDI(1) | \ - ZMII_FER_MDI(2) | ZMII_FER_MDI(3)) - -#define ZMII_FER_SMII(idx) (0x40000000 >> ((idx) * 4)) -#define ZMII_FER_RMII(idx) (0x20000000 >> ((idx) * 4)) -#define ZMII_FER_MII(idx) (0x10000000 >> ((idx) * 4)) - -/* ZMIIx_SSR */ -#define ZMII_SSR_SCI(idx) (0x40000000 >> ((idx) * 4)) -#define ZMII_SSR_FSS(idx) (0x20000000 >> ((idx) * 4)) -#define ZMII_SSR_SP(idx) (0x10000000 >> ((idx) * 4)) - -/* ZMII only supports MII, RMII and SMII - * we also support autodetection for backward compatibility - */ -static inline int zmii_valid_mode(int mode) -{ - return mode == PHY_MODE_MII || - mode == PHY_MODE_RMII || - mode == PHY_MODE_SMII || - mode == PHY_MODE_NA; -} - -static inline const char *zmii_mode_name(int mode) -{ - switch (mode) { - case PHY_MODE_MII: - return "MII"; - case PHY_MODE_RMII: - return "RMII"; - case PHY_MODE_SMII: - return "SMII"; - default: - BUG(); - } -} - -static inline u32 zmii_mode_mask(int mode, int input) -{ - switch (mode) { - case PHY_MODE_MII: - return ZMII_FER_MII(input); - case PHY_MODE_RMII: - return ZMII_FER_RMII(input); - case PHY_MODE_SMII: - return ZMII_FER_SMII(input); - default: - return 0; - } -} - -static int __init zmii_init(struct ocp_device *ocpdev, int input, int *mode) -{ - struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); - struct zmii_regs *p; - - ZMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, *mode); - - if (!dev) { - dev = kzalloc(sizeof(struct ibm_ocp_zmii), GFP_KERNEL); - if (!dev) { - printk(KERN_ERR - "zmii%d: couldn't allocate device structure!\n", - ocpdev->def->index); - return -ENOMEM; - } - dev->mode = PHY_MODE_NA; - - p = (struct zmii_regs *)ioremap(ocpdev->def->paddr, - sizeof(struct zmii_regs)); - if (!p) { - printk(KERN_ERR - "zmii%d: could not ioremap device registers!\n", - ocpdev->def->index); - kfree(dev); - return -ENOMEM; - } - dev->base = p; - ocp_set_drvdata(ocpdev, dev); - - /* We may need FER value for autodetection later */ - dev->fer_save = in_be32(&p->fer); - - /* Disable all inputs by default */ - out_be32(&p->fer, 0); - } else - p = dev->base; - - if (!zmii_valid_mode(*mode)) { - /* Probably an EMAC connected to RGMII, - * but it still may need ZMII for MDIO - */ - goto out; - } - - /* Autodetect ZMII mode if not specified. - * This is only for backward compatibility with the old driver. - * Please, always specify PHY mode in your board port to avoid - * any surprises. - */ - if (dev->mode == PHY_MODE_NA) { - if (*mode == PHY_MODE_NA) { - u32 r = dev->fer_save; - - ZMII_DBG("%d: autodetecting mode, FER = 0x%08x" NL, - ocpdev->def->index, r); - - if (r & (ZMII_FER_MII(0) | ZMII_FER_MII(1))) - dev->mode = PHY_MODE_MII; - else if (r & (ZMII_FER_RMII(0) | ZMII_FER_RMII(1))) - dev->mode = PHY_MODE_RMII; - else - dev->mode = PHY_MODE_SMII; - } else - dev->mode = *mode; - - printk(KERN_NOTICE "zmii%d: bridge in %s mode\n", - ocpdev->def->index, zmii_mode_name(dev->mode)); - } else { - /* All inputs must use the same mode */ - if (*mode != PHY_MODE_NA && *mode != dev->mode) { - printk(KERN_ERR - "zmii%d: invalid mode %d specified for input %d\n", - ocpdev->def->index, *mode, input); - return -EINVAL; - } - } - - /* Report back correct PHY mode, - * it may be used during PHY initialization. - */ - *mode = dev->mode; - - /* Enable this input */ - out_be32(&p->fer, in_be32(&p->fer) | zmii_mode_mask(dev->mode, input)); - out: - ++dev->users; - return 0; -} - -int __init zmii_attach(void *emac) -{ - struct ocp_enet_private *dev = emac; - struct ocp_func_emac_data *emacdata = dev->def->additions; - - if (emacdata->zmii_idx >= 0) { - dev->zmii_input = emacdata->zmii_mux; - dev->zmii_dev = - ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_ZMII, - emacdata->zmii_idx); - if (!dev->zmii_dev) { - printk(KERN_ERR "emac%d: unknown zmii%d!\n", - dev->def->index, emacdata->zmii_idx); - return -ENODEV; - } - if (zmii_init - (dev->zmii_dev, dev->zmii_input, &emacdata->phy_mode)) { - printk(KERN_ERR - "emac%d: zmii%d initialization failed!\n", - dev->def->index, emacdata->zmii_idx); - return -ENODEV; - } - } - return 0; -} - -void __zmii_enable_mdio(struct ocp_device *ocpdev, int input) -{ - struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); - u32 fer = in_be32(&dev->base->fer) & ~ZMII_FER_MDI_ALL; - - ZMII_DBG2("%d: mdio(%d)" NL, ocpdev->def->index, input); - - out_be32(&dev->base->fer, fer | ZMII_FER_MDI(input)); -} - -void __zmii_set_speed(struct ocp_device *ocpdev, int input, int speed) -{ - struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); - u32 ssr = in_be32(&dev->base->ssr); - - ZMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed); - - if (speed == SPEED_100) - ssr |= ZMII_SSR_SP(input); - else - ssr &= ~ZMII_SSR_SP(input); - - out_be32(&dev->base->ssr, ssr); -} - -void __exit __zmii_fini(struct ocp_device *ocpdev, int input) -{ - struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); - BUG_ON(!dev || dev->users == 0); - - ZMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input); - - /* Disable this input */ - out_be32(&dev->base->fer, - in_be32(&dev->base->fer) & ~zmii_mode_mask(dev->mode, input)); - - if (!--dev->users) { - /* Free everything if this is the last user */ - ocp_set_drvdata(ocpdev, NULL); - iounmap((void *)dev->base); - kfree(dev); - } -} - -int __zmii_get_regs_len(struct ocp_device *ocpdev) -{ - return sizeof(struct emac_ethtool_regs_subhdr) + - sizeof(struct zmii_regs); -} - -void *zmii_dump_regs(struct ocp_device *ocpdev, void *buf) -{ - struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); - struct emac_ethtool_regs_subhdr *hdr = buf; - struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1); - - hdr->version = 0; - hdr->index = ocpdev->def->index; - memcpy_fromio(regs, dev->base, sizeof(struct zmii_regs)); - return regs + 1; -} diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_zmii.h b/trunk/drivers/net/ibm_emac/ibm_emac_zmii.h index 0bb26062c0ad..6f6cd2a39e38 100644 --- a/trunk/drivers/net/ibm_emac/ibm_emac_zmii.h +++ b/trunk/drivers/net/ibm_emac/ibm_emac_zmii.h @@ -1,27 +1,23 @@ /* - * drivers/net/ibm_emac/ibm_emac_zmii.h + * ocp_zmii.h * - * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support. + * Defines for the IBM ZMII bridge * - * Copyright (c) 2004, 2005 Zultys Technologies. - * Eugene Surovegin or + * Armin Kuster akuster@mvista.com + * Dec, 2001 * - * Based on original work by - * Armin Kuster - * Copyright 2001 MontaVista Softare Inc. + * Copyright 2001 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. - * */ + #ifndef _IBM_EMAC_ZMII_H_ #define _IBM_EMAC_ZMII_H_ #include -#include -#include /* ZMII bridge registers */ struct zmii_regs { @@ -30,54 +26,68 @@ struct zmii_regs { u32 smiirs; /* SMII status reg */ }; +#define ZMII_INPUTS 4 + /* ZMII device */ struct ibm_ocp_zmii { struct zmii_regs *base; - int mode; /* subset of PHY_MODE_XXXX */ + int mode[ZMII_INPUTS]; int users; /* number of EMACs using this ZMII bridge */ - u32 fer_save; /* FER value left by firmware */ }; -#ifdef CONFIG_IBM_EMAC_ZMII -int zmii_attach(void *emac) __init; +/* Fuctional Enable Reg */ + +#define ZMII_FER_MASK(x) (0xf0000000 >> (4*x)) + +#define ZMII_MDI0 0x80000000 +#define ZMII_SMII0 0x40000000 +#define ZMII_RMII0 0x20000000 +#define ZMII_MII0 0x10000000 +#define ZMII_MDI1 0x08000000 +#define ZMII_SMII1 0x04000000 +#define ZMII_RMII1 0x02000000 +#define ZMII_MII1 0x01000000 +#define ZMII_MDI2 0x00800000 +#define ZMII_SMII2 0x00400000 +#define ZMII_RMII2 0x00200000 +#define ZMII_MII2 0x00100000 +#define ZMII_MDI3 0x00080000 +#define ZMII_SMII3 0x00040000 +#define ZMII_RMII3 0x00020000 +#define ZMII_MII3 0x00010000 -void __zmii_fini(struct ocp_device *ocpdev, int input) __exit; -static inline void zmii_fini(struct ocp_device *ocpdev, int input) -{ - if (ocpdev) - __zmii_fini(ocpdev, input); -} +/* Speed Selection reg */ -void __zmii_enable_mdio(struct ocp_device *ocpdev, int input); -static inline void zmii_enable_mdio(struct ocp_device *ocpdev, int input) -{ - if (ocpdev) - __zmii_enable_mdio(ocpdev, input); -} +#define ZMII_SCI0 0x40000000 +#define ZMII_FSS0 0x20000000 +#define ZMII_SP0 0x10000000 +#define ZMII_SCI1 0x04000000 +#define ZMII_FSS1 0x02000000 +#define ZMII_SP1 0x01000000 +#define ZMII_SCI2 0x00400000 +#define ZMII_FSS2 0x00200000 +#define ZMII_SP2 0x00100000 +#define ZMII_SCI3 0x00040000 +#define ZMII_FSS3 0x00020000 +#define ZMII_SP3 0x00010000 -void __zmii_set_speed(struct ocp_device *ocpdev, int input, int speed); -static inline void zmii_set_speed(struct ocp_device *ocpdev, int input, - int speed) -{ - if (ocpdev) - __zmii_set_speed(ocpdev, input, speed); -} +#define ZMII_MII0_100MB ZMII_SP0 +#define ZMII_MII0_10MB ~ZMII_SP0 +#define ZMII_MII1_100MB ZMII_SP1 +#define ZMII_MII1_10MB ~ZMII_SP1 +#define ZMII_MII2_100MB ZMII_SP2 +#define ZMII_MII2_10MB ~ZMII_SP2 +#define ZMII_MII3_100MB ZMII_SP3 +#define ZMII_MII3_10MB ~ZMII_SP3 -int __zmii_get_regs_len(struct ocp_device *ocpdev); -static inline int zmii_get_regs_len(struct ocp_device *ocpdev) -{ - return ocpdev ? __zmii_get_regs_len(ocpdev) : 0; -} +/* SMII Status reg */ -void *zmii_dump_regs(struct ocp_device *ocpdev, void *buf); +#define ZMII_STS0 0xFF000000 /* EMAC0 smii status mask */ +#define ZMII_STS1 0x00FF0000 /* EMAC1 smii status mask */ -#else -# define zmii_attach(x) 0 -# define zmii_fini(x,y) ((void)0) -# define zmii_enable_mdio(x,y) ((void)0) -# define zmii_set_speed(x,y,z) ((void)0) -# define zmii_get_regs_len(x) 0 -# define zmii_dump_regs(x,buf) (buf) -#endif /* !CONFIG_IBM_EMAC_ZMII */ +#define SMII 0 +#define RMII 1 +#define MII 2 +#define MDI 3 #endif /* _IBM_EMAC_ZMII_H_ */ diff --git a/trunk/drivers/net/ibmveth.c b/trunk/drivers/net/ibmveth.c index 36da54ad2b7b..a2c4dd4fb221 100644 --- a/trunk/drivers/net/ibmveth.c +++ b/trunk/drivers/net/ibmveth.c @@ -96,7 +96,7 @@ static void ibmveth_proc_unregister_driver(void); static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter); static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); +static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter*); #ifdef CONFIG_PROC_FS #define IBMVETH_PROC_DIR "net/ibmveth" @@ -181,7 +181,6 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool) atomic_set(&pool->available, 0); pool->producer_index = 0; pool->consumer_index = 0; - pool->active = 0; return 0; } @@ -237,7 +236,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc); if(lpar_rc != H_Success) { - pool->free_map[free_index] = index; + pool->free_map[free_index] = IBM_VETH_INVALID_MAP; pool->skbuff[index] = NULL; pool->consumer_index--; dma_unmap_single(&adapter->vdev->dev, @@ -256,19 +255,37 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc atomic_add(buffers_added, &(pool->available)); } -/* replenish routine */ -static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) +/* check if replenishing is needed. */ +static inline int ibmveth_is_replenishing_needed(struct ibmveth_adapter *adapter) { - int i; + return ((atomic_read(&adapter->rx_buff_pool[0].available) < adapter->rx_buff_pool[0].threshold) || + (atomic_read(&adapter->rx_buff_pool[1].available) < adapter->rx_buff_pool[1].threshold) || + (atomic_read(&adapter->rx_buff_pool[2].available) < adapter->rx_buff_pool[2].threshold)); +} + +/* kick the replenish tasklet if we need replenishing and it isn't already running */ +static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter *adapter) +{ + if(ibmveth_is_replenishing_needed(adapter) && + (atomic_dec_if_positive(&adapter->not_replenishing) == 0)) { + schedule_work(&adapter->replenish_task); + } +} +/* replenish tasklet routine */ +static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) +{ adapter->replenish_task_cycles++; - for(i = 0; i < IbmVethNumBufferPools; i++) - if(adapter->rx_buff_pool[i].active) - ibmveth_replenish_buffer_pool(adapter, - &adapter->rx_buff_pool[i]); + ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[0]); + ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[1]); + ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[2]); adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8); + + atomic_inc(&adapter->not_replenishing); + + ibmveth_schedule_replenishing(adapter); } /* empty and free ana buffer pool - also used to do cleanup in error paths */ @@ -276,8 +293,10 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibm { int i; - kfree(pool->free_map); - pool->free_map = NULL; + if(pool->free_map) { + kfree(pool->free_map); + pool->free_map = NULL; + } if(pool->skbuff && pool->dma_addr) { for(i = 0; i < pool->size; ++i) { @@ -302,7 +321,6 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibm kfree(pool->skbuff); pool->skbuff = NULL; } - pool->active = 0; } /* remove a buffer from a pool */ @@ -361,12 +379,6 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) ibmveth_assert(pool < IbmVethNumBufferPools); ibmveth_assert(index < adapter->rx_buff_pool[pool].size); - if(!adapter->rx_buff_pool[pool].active) { - ibmveth_rxq_harvest_buffer(adapter); - ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[pool]); - return; - } - desc.desc = 0; desc.fields.valid = 1; desc.fields.length = adapter->rx_buff_pool[pool].buff_size; @@ -397,8 +409,6 @@ static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter) static void ibmveth_cleanup(struct ibmveth_adapter *adapter) { - int i; - if(adapter->buffer_list_addr != NULL) { if(!dma_mapping_error(adapter->buffer_list_dma)) { dma_unmap_single(&adapter->vdev->dev, @@ -433,24 +443,26 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) adapter->rx_queue.queue_addr = NULL; } - for(i = 0; irx_buff_pool[i]); + ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[0]); + ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[1]); + ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[2]); } static int ibmveth_open(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev->priv; u64 mac_address = 0; - int rxq_entries = 1; + int rxq_entries; unsigned long lpar_rc; int rc; union ibmveth_buf_desc rxq_desc; - int i; ibmveth_debug_printk("open starting\n"); - for(i = 0; irx_buff_pool[i].size; + rxq_entries = + adapter->rx_buff_pool[0].size + + adapter->rx_buff_pool[1].size + + adapter->rx_buff_pool[2].size + 1; adapter->buffer_list_addr = (void*) get_zeroed_page(GFP_KERNEL); adapter->filter_list_addr = (void*) get_zeroed_page(GFP_KERNEL); @@ -490,8 +502,14 @@ static int ibmveth_open(struct net_device *netdev) adapter->rx_queue.num_slots = rxq_entries; adapter->rx_queue.toggle = 1; - /* call change_mtu to init the buffer pools based in initial mtu */ - ibmveth_change_mtu(netdev, netdev->mtu); + if(ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[0]) || + ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[1]) || + ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[2])) + { + ibmveth_error_printk("unable to allocate buffer pools\n"); + ibmveth_cleanup(adapter); + return -ENOMEM; + } memcpy(&mac_address, netdev->dev_addr, netdev->addr_len); mac_address = mac_address >> 16; @@ -534,11 +552,11 @@ static int ibmveth_open(struct net_device *netdev) return rc; } - ibmveth_debug_printk("initial replenish cycle\n"); - ibmveth_replenish_task(adapter); - netif_start_queue(netdev); + ibmveth_debug_printk("scheduling initial replenish cycle\n"); + ibmveth_schedule_replenishing(adapter); + ibmveth_debug_printk("open complete\n"); return 0; @@ -555,6 +573,9 @@ static int ibmveth_close(struct net_device *netdev) free_irq(netdev->irq, netdev); + cancel_delayed_work(&adapter->replenish_task); + flush_scheduled_work(); + do { lpar_rc = h_free_logical_lan(adapter->vdev->unit_address); } while (H_isLongBusy(lpar_rc) || (lpar_rc == H_Busy)); @@ -619,18 +640,12 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned long lpar_rc; int nfrags = 0, curfrag; unsigned long correlator; - unsigned long flags; unsigned int retry_count; - unsigned int tx_dropped = 0; - unsigned int tx_bytes = 0; - unsigned int tx_packets = 0; - unsigned int tx_send_failed = 0; - unsigned int tx_map_failed = 0; - if ((skb_shinfo(skb)->nr_frags + 1) > IbmVethMaxSendFrags) { - tx_dropped++; - goto out; + adapter->stats.tx_dropped++; + dev_kfree_skb(skb); + return 0; } memset(&desc, 0, sizeof(desc)); @@ -649,9 +664,10 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) if(dma_mapping_error(desc[0].fields.address)) { ibmveth_error_printk("tx: unable to map initial fragment\n"); - tx_map_failed++; - tx_dropped++; - goto out; + adapter->tx_map_failed++; + adapter->stats.tx_dropped++; + dev_kfree_skb(skb); + return 0; } curfrag = nfrags; @@ -668,8 +684,8 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) if(dma_mapping_error(desc[curfrag+1].fields.address)) { ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag); - tx_map_failed++; - tx_dropped++; + adapter->tx_map_failed++; + adapter->stats.tx_dropped++; /* Free all the mappings we just created */ while(curfrag < nfrags) { dma_unmap_single(&adapter->vdev->dev, @@ -678,7 +694,8 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) DMA_TO_DEVICE); curfrag++; } - goto out; + dev_kfree_skb(skb); + return 0; } } @@ -703,12 +720,11 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) ibmveth_error_printk("tx: desc[%i] valid=%d, len=%d, address=0x%d\n", i, desc[i].fields.valid, desc[i].fields.length, desc[i].fields.address); } - tx_send_failed++; - tx_dropped++; + adapter->tx_send_failed++; + adapter->stats.tx_dropped++; } else { - tx_packets++; - tx_bytes += skb->len; - netdev->trans_start = jiffies; + adapter->stats.tx_packets++; + adapter->stats.tx_bytes += skb->len; } do { @@ -717,14 +733,6 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) desc[nfrags].fields.length, DMA_TO_DEVICE); } while(--nfrags >= 0); -out: spin_lock_irqsave(&adapter->stats_lock, flags); - adapter->stats.tx_dropped += tx_dropped; - adapter->stats.tx_bytes += tx_bytes; - adapter->stats.tx_packets += tx_packets; - adapter->tx_send_failed += tx_send_failed; - adapter->tx_map_failed += tx_map_failed; - spin_unlock_irqrestore(&adapter->stats_lock, flags); - dev_kfree_skb(skb); return 0; } @@ -768,14 +776,13 @@ static int ibmveth_poll(struct net_device *netdev, int *budget) adapter->stats.rx_packets++; adapter->stats.rx_bytes += length; frames_processed++; - netdev->last_rx = jiffies; } } else { more_work = 0; } } while(more_work && (frames_processed < max_frames_to_process)); - ibmveth_replenish_task(adapter); + ibmveth_schedule_replenishing(adapter); if(more_work) { /* more work to do - return that we are not done yet */ @@ -876,54 +883,17 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) { - struct ibmveth_adapter *adapter = dev->priv; - int i; - int prev_smaller = 1; - - if ((new_mtu < 68) || - (new_mtu > (pool_size[IbmVethNumBufferPools-1]) - IBMVETH_BUFF_OH)) + if ((new_mtu < 68) || (new_mtu > (1<<20))) return -EINVAL; - - for(i = 0; i (pool_size[i] - IBMVETH_BUFF_OH)) { - activate = 1; - prev_smaller= 1; - } else { - if (prev_smaller) - activate = 1; - prev_smaller= 0; - } - - if (activate && !adapter->rx_buff_pool[i].active) { - struct ibmveth_buff_pool *pool = - &adapter->rx_buff_pool[i]; - if(ibmveth_alloc_buffer_pool(pool)) { - ibmveth_error_printk("unable to alloc pool\n"); - return -ENOMEM; - } - adapter->rx_buff_pool[i].active = 1; - } else if (!activate && adapter->rx_buff_pool[i].active) { - adapter->rx_buff_pool[i].active = 0; - h_free_logical_lan_buffer(adapter->vdev->unit_address, - (u64)pool_size[i]); - } - - } - - /* kick the interrupt handler so that the new buffer pools get - replenished or deallocated */ - ibmveth_interrupt(dev->irq, dev, NULL); - dev->mtu = new_mtu; return 0; } static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) { - int rc, i; + int rc; struct net_device *netdev; - struct ibmveth_adapter *adapter = NULL; + struct ibmveth_adapter *adapter; unsigned char *mac_addr_p; unsigned int *mcastFilterSize_p; @@ -990,21 +960,23 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ netdev->ethtool_ops = &netdev_ethtool_ops; netdev->change_mtu = ibmveth_change_mtu; SET_NETDEV_DEV(netdev, &dev->dev); - netdev->features |= NETIF_F_LLTX; - spin_lock_init(&adapter->stats_lock); memcpy(&netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); - for(i = 0; irx_buff_pool[i], i, - pool_count[i], pool_size[i]); + ibmveth_init_buffer_pool(&adapter->rx_buff_pool[0], 0, IbmVethPool0DftCnt, IbmVethPool0DftSize); + ibmveth_init_buffer_pool(&adapter->rx_buff_pool[1], 1, IbmVethPool1DftCnt, IbmVethPool1DftSize); + ibmveth_init_buffer_pool(&adapter->rx_buff_pool[2], 2, IbmVethPool2DftCnt, IbmVethPool2DftSize); ibmveth_debug_printk("adapter @ 0x%p\n", adapter); + INIT_WORK(&adapter->replenish_task, (void*)ibmveth_replenish_task, (void*)adapter); + adapter->buffer_list_dma = DMA_ERROR_CODE; adapter->filter_list_dma = DMA_ERROR_CODE; adapter->rx_queue.queue_dma = DMA_ERROR_CODE; + atomic_set(&adapter->not_replenishing, 1); + ibmveth_debug_printk("registering netdev...\n"); rc = register_netdev(netdev); diff --git a/trunk/drivers/net/ibmveth.h b/trunk/drivers/net/ibmveth.h index 46919a814fca..51a470da9686 100644 --- a/trunk/drivers/net/ibmveth.h +++ b/trunk/drivers/net/ibmveth.h @@ -49,7 +49,6 @@ #define H_SEND_LOGICAL_LAN 0x120 #define H_MULTICAST_CTRL 0x130 #define H_CHANGE_LOGICAL_LAN_MAC 0x14C -#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4 /* hcall macros */ #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \ @@ -70,15 +69,13 @@ #define h_change_logical_lan_mac(ua, mac) \ plpar_hcall_norets(H_CHANGE_LOGICAL_LAN_MAC, ua, mac) -#define h_free_logical_lan_buffer(ua, bufsize) \ - plpar_hcall_norets(H_FREE_LOGICAL_LAN_BUFFER, ua, bufsize) - -#define IbmVethNumBufferPools 5 -#define IBMVETH_BUFF_OH 22 /* Overhead: 14 ethernet header + 8 opaque handle */ - -/* pool_size should be sorted */ -static int pool_size[] = { 512, 1024 * 2, 1024 * 16, 1024 * 32, 1024 * 64 }; -static int pool_count[] = { 256, 768, 256, 256, 256 }; +#define IbmVethNumBufferPools 3 +#define IbmVethPool0DftSize (1024 * 2) +#define IbmVethPool1DftSize (1024 * 4) +#define IbmVethPool2DftSize (1024 * 10) +#define IbmVethPool0DftCnt 256 +#define IbmVethPool1DftCnt 256 +#define IbmVethPool2DftCnt 256 #define IBM_VETH_INVALID_MAP ((u16)0xffff) @@ -93,7 +90,6 @@ struct ibmveth_buff_pool { u16 *free_map; dma_addr_t *dma_addr; struct sk_buff **skbuff; - int active; }; struct ibmveth_rx_q { @@ -118,6 +114,10 @@ struct ibmveth_adapter { dma_addr_t filter_list_dma; struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools]; struct ibmveth_rx_q rx_queue; + atomic_t not_replenishing; + + /* helper tasks */ + struct work_struct replenish_task; /* adapter specific stats */ u64 replenish_task_cycles; @@ -131,7 +131,6 @@ struct ibmveth_adapter { u64 tx_linearize_failed; u64 tx_map_failed; u64 tx_send_failed; - spinlock_t stats_lock; }; struct ibmveth_buf_desc_fields { diff --git a/trunk/drivers/net/irda/donauboe.c b/trunk/drivers/net/irda/donauboe.c index 0282771b1cbb..0a08c539c051 100644 --- a/trunk/drivers/net/irda/donauboe.c +++ b/trunk/drivers/net/irda/donauboe.c @@ -1695,9 +1695,11 @@ toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid) freebufs: for (i = 0; i < TX_SLOTS; ++i) - kfree (self->tx_bufs[i]); + if (self->tx_bufs[i]) + kfree (self->tx_bufs[i]); for (i = 0; i < RX_SLOTS; ++i) - kfree (self->rx_bufs[i]); + if (self->rx_bufs[i]) + kfree (self->rx_bufs[i]); kfree(self->ringbuf); freeregion: diff --git a/trunk/drivers/net/irda/irda-usb.c b/trunk/drivers/net/irda/irda-usb.c index c22c0517883c..6c766fdc51a6 100644 --- a/trunk/drivers/net/irda/irda-usb.c +++ b/trunk/drivers/net/irda/irda-usb.c @@ -1168,8 +1168,10 @@ static inline void irda_usb_close(struct irda_usb_cb *self) unregister_netdev(self->netdev); /* Remove the speed buffer */ - kfree(self->speed_buff); - self->speed_buff = NULL; + if (self->speed_buff != NULL) { + kfree(self->speed_buff); + self->speed_buff = NULL; + } } /********************** USB CONFIG SUBROUTINES **********************/ diff --git a/trunk/drivers/net/irda/irport.c b/trunk/drivers/net/irda/irport.c index 3d016a498e1d..5971315f3fa0 100644 --- a/trunk/drivers/net/irda/irport.c +++ b/trunk/drivers/net/irda/irport.c @@ -235,7 +235,8 @@ static int irport_close(struct irport_cb *self) __FUNCTION__, self->io.sir_base); release_region(self->io.sir_base, self->io.sir_ext); - kfree(self->tx_buff.head); + if (self->tx_buff.head) + kfree(self->tx_buff.head); if (self->rx_buff.skb) kfree_skb(self->rx_buff.skb); diff --git a/trunk/drivers/net/irda/sir_dev.c b/trunk/drivers/net/irda/sir_dev.c index df22b8b532e7..efc5a8870565 100644 --- a/trunk/drivers/net/irda/sir_dev.c +++ b/trunk/drivers/net/irda/sir_dev.c @@ -490,7 +490,8 @@ static void sirdev_free_buffers(struct sir_dev *dev) { if (dev->rx_buff.skb) kfree_skb(dev->rx_buff.skb); - kfree(dev->tx_buff.head); + if (dev->tx_buff.head) + kfree(dev->tx_buff.head); dev->rx_buff.head = dev->tx_buff.head = NULL; dev->rx_buff.skb = NULL; } diff --git a/trunk/drivers/net/irda/vlsi_ir.c b/trunk/drivers/net/irda/vlsi_ir.c index a9f49f058cfb..651c5a6578fd 100644 --- a/trunk/drivers/net/irda/vlsi_ir.c +++ b/trunk/drivers/net/irda/vlsi_ir.c @@ -473,7 +473,8 @@ static int vlsi_free_ring(struct vlsi_ring *r) rd_set_addr_status(rd, 0, 0); if (busaddr) pci_unmap_single(r->pdev, busaddr, r->len, r->dir); - kfree(rd->buf); + if (rd->buf) + kfree(rd->buf); } kfree(r); return 0; diff --git a/trunk/drivers/net/mace.c b/trunk/drivers/net/mace.c index 09b1e7b364e5..81d0a26e4f41 100644 --- a/trunk/drivers/net/mace.c +++ b/trunk/drivers/net/mace.c @@ -1035,8 +1035,10 @@ static void __exit mace_cleanup(void) { macio_unregister_driver(&mace_driver); - kfree(dummy_buf); - dummy_buf = NULL; + if (dummy_buf) { + kfree(dummy_buf); + dummy_buf = NULL; + } } MODULE_AUTHOR("Paul Mackerras"); diff --git a/trunk/drivers/net/ne2k-pci.c b/trunk/drivers/net/ne2k-pci.c index d11821dd86ed..e531a4eedfee 100644 --- a/trunk/drivers/net/ne2k-pci.c +++ b/trunk/drivers/net/ne2k-pci.c @@ -675,6 +675,7 @@ static int ne2k_pci_resume (struct pci_dev *pdev) pci_set_power_state(pdev, 0); pci_restore_state(pdev); pci_enable_device(pdev); + pci_set_master(pdev); NS8390_init(dev, 1); netif_device_attach(dev); diff --git a/trunk/drivers/net/ni65.c b/trunk/drivers/net/ni65.c index bb42ff218484..925d1dfcc4dc 100644 --- a/trunk/drivers/net/ni65.c +++ b/trunk/drivers/net/ni65.c @@ -696,7 +696,8 @@ static void ni65_free_buffer(struct priv *p) return; for(i=0;itmdbounce[i]); + if(p->tmdbounce[i]) + kfree(p->tmdbounce[i]); #ifdef XMT_VIA_SKB if(p->tmd_skb[i]) dev_kfree_skb(p->tmd_skb[i]); @@ -709,10 +710,12 @@ static void ni65_free_buffer(struct priv *p) if(p->recv_skb[i]) dev_kfree_skb(p->recv_skb[i]); #else - kfree(p->recvbounce[i]); + if(p->recvbounce[i]) + kfree(p->recvbounce[i]); #endif } - kfree(p->self); + if(p->self) + kfree(p->self); } diff --git a/trunk/drivers/net/pcmcia/pcnet_cs.c b/trunk/drivers/net/pcmcia/pcnet_cs.c index 818c185d6438..9f22d138e3ad 100644 --- a/trunk/drivers/net/pcmcia/pcnet_cs.c +++ b/trunk/drivers/net/pcmcia/pcnet_cs.c @@ -1020,12 +1020,6 @@ static void set_misc_reg(struct net_device *dev) } else { outb(full_duplex ? 4 : 0, nic_base + DLINK_DIAG); } - } else if (info->flags & IS_DL10019) { - /* Advertise 100F, 100H, 10F, 10H */ - mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1); - /* Restart MII autonegotiation */ - mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000); - mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200); } } diff --git a/trunk/drivers/net/rrunner.c b/trunk/drivers/net/rrunner.c index 19c2df9c86fe..ec1a18d189a1 100644 --- a/trunk/drivers/net/rrunner.c +++ b/trunk/drivers/net/rrunner.c @@ -1710,8 +1710,10 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) error = -EFAULT; } wf_out: - kfree(oldimage); - kfree(image); + if (oldimage) + kfree(oldimage); + if (image) + kfree(image); return error; case SIOCRRID: diff --git a/trunk/drivers/net/s2io.c b/trunk/drivers/net/s2io.c index 3f5e93aad5c7..62d5041845e3 100644 --- a/trunk/drivers/net/s2io.c +++ b/trunk/drivers/net/s2io.c @@ -705,7 +705,8 @@ static void free_shared_mem(struct s2io_nic *nic) } kfree(mac_control->rings[i].ba[j]); } - kfree(mac_control->rings[i].ba); + if (mac_control->rings[i].ba) + kfree(mac_control->rings[i].ba); } #endif diff --git a/trunk/drivers/net/saa9730.c b/trunk/drivers/net/saa9730.c index 110e777f206e..fd0167077fbe 100644 --- a/trunk/drivers/net/saa9730.c +++ b/trunk/drivers/net/saa9730.c @@ -997,7 +997,10 @@ static void __devexit saa9730_remove_one(struct pci_dev *pdev) if (dev) { unregister_netdev(dev); - kfree(dev->priv); + + if (dev->priv) + kfree(dev->priv); + free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); @@ -1093,7 +1096,8 @@ static int lan_saa9730_init(struct net_device *dev, int ioaddr, int irq) return 0; out: - kfree(dev->priv); + if (dev->priv) + kfree(dev->priv); return ret; } diff --git a/trunk/drivers/net/sis190.c b/trunk/drivers/net/sis190.c index 478791e09bf7..92f75529eff8 100644 --- a/trunk/drivers/net/sis190.c +++ b/trunk/drivers/net/sis190.c @@ -842,7 +842,7 @@ static void sis190_set_rx_mode(struct net_device *dev) for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { int bit_nr = - ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f; + ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); rx_mode |= AcceptMulticast; } diff --git a/trunk/drivers/net/sis900.c b/trunk/drivers/net/sis900.c index 1d4d88680db1..23b713c700b3 100644 --- a/trunk/drivers/net/sis900.c +++ b/trunk/drivers/net/sis900.c @@ -1696,20 +1696,15 @@ static int sis900_rx(struct net_device *net_dev) long ioaddr = net_dev->base_addr; unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC; u32 rx_status = sis_priv->rx_ring[entry].cmdsts; - int rx_work_limit; if (netif_msg_rx_status(sis_priv)) printk(KERN_DEBUG "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d " "status:0x%8.8x\n", sis_priv->cur_rx, sis_priv->dirty_rx, rx_status); - rx_work_limit = sis_priv->dirty_rx + NUM_RX_DESC - sis_priv->cur_rx; while (rx_status & OWN) { unsigned int rx_size; - if (--rx_work_limit < 0) - break; - rx_size = (rx_status & DSIZE) - CRC_SIZE; if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) { @@ -1737,11 +1732,9 @@ static int sis900_rx(struct net_device *net_dev) we are working on NULL sk_buff :-( */ if (sis_priv->rx_skbuff[entry] == NULL) { if (netif_msg_rx_err(sis_priv)) - printk(KERN_WARNING "%s: NULL pointer " - "encountered in Rx ring\n" - "cur_rx:%4.4d, dirty_rx:%4.4d\n", - net_dev->name, sis_priv->cur_rx, - sis_priv->dirty_rx); + printk(KERN_INFO "%s: NULL pointer " + "encountered in Rx ring, skipping\n", + net_dev->name); break; } @@ -1777,7 +1770,6 @@ static int sis900_rx(struct net_device *net_dev) sis_priv->rx_ring[entry].cmdsts = 0; sis_priv->rx_ring[entry].bufptr = 0; sis_priv->stats.rx_dropped++; - sis_priv->cur_rx++; break; } skb->dev = net_dev; @@ -1795,7 +1787,7 @@ static int sis900_rx(struct net_device *net_dev) /* refill the Rx buffer, what if the rate of refilling is slower * than consuming ?? */ - for (; sis_priv->cur_rx != sis_priv->dirty_rx; sis_priv->dirty_rx++) { + for (;sis_priv->cur_rx - sis_priv->dirty_rx > 0; sis_priv->dirty_rx++) { struct sk_buff *skb; entry = sis_priv->dirty_rx % NUM_RX_DESC; diff --git a/trunk/drivers/net/smc91x.c b/trunk/drivers/net/smc91x.c index c573bb351d4c..0ddaa611cc61 100644 --- a/trunk/drivers/net/smc91x.c +++ b/trunk/drivers/net/smc91x.c @@ -1983,10 +1983,6 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) if (lp->version >= (CHIP_91100 << 4)) smc_phy_detect(dev); - /* then shut everything down to save power */ - smc_shutdown(dev); - smc_phy_powerdown(dev); - /* Set default parameters */ lp->msg_enable = NETIF_MSG_LINK; lp->ctl_rfduplx = 0; diff --git a/trunk/drivers/net/starfire.c b/trunk/drivers/net/starfire.c index 38b2b0a3ce96..efdb179ecc8c 100644 --- a/trunk/drivers/net/starfire.c +++ b/trunk/drivers/net/starfire.c @@ -1091,10 +1091,8 @@ static int netdev_open(struct net_device *dev) rx_ring_size = sizeof(struct starfire_rx_desc) * RX_RING_SIZE; np->queue_mem_size = tx_done_q_size + rx_done_q_size + tx_ring_size + rx_ring_size; np->queue_mem = pci_alloc_consistent(np->pci_dev, np->queue_mem_size, &np->queue_mem_dma); - if (np->queue_mem == NULL) { - free_irq(dev->irq, dev); + if (np->queue_mem == 0) return -ENOMEM; - } np->tx_done_q = np->queue_mem; np->tx_done_q_dma = np->queue_mem_dma; diff --git a/trunk/drivers/net/sundance.c b/trunk/drivers/net/sundance.c index 0ab9c38b4a34..5de0554fd7c6 100644 --- a/trunk/drivers/net/sundance.c +++ b/trunk/drivers/net/sundance.c @@ -80,7 +80,7 @@ I/O access could affect performance in ARM-based system - Add Linux software VLAN support - Version LK1.08 (Philippe De Muyter phdm@macqel.be): + Version LK1.08 (D-Link): - Fix bug of custom mac address (StationAddr register only accept word write) @@ -91,14 +91,11 @@ Version LK1.09a (ICPlus): - Add the delay time in reading the contents of EEPROM - Version LK1.10 (Philippe De Muyter phdm@macqel.be): - - Make 'unblock interface after Tx underrun' work - */ #define DRV_NAME "sundance" -#define DRV_VERSION "1.01+LK1.10" -#define DRV_RELDATE "28-Oct-2005" +#define DRV_VERSION "1.01+LK1.09a" +#define DRV_RELDATE "10-Jul-2003" /* The user-configurable values. @@ -266,10 +263,8 @@ IV. Notes IVb. References The Sundance ST201 datasheet, preliminary version. -The Kendin KS8723 datasheet, preliminary version. -The ICplus IP100 datasheet, preliminary version. -http://www.scyld.com/expert/100mbps.html -http://www.scyld.com/expert/NWay.html +http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html IVc. Errata @@ -505,25 +500,6 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_close(struct net_device *dev); static struct ethtool_ops ethtool_ops; -static void sundance_reset(struct net_device *dev, unsigned long reset_cmd) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base + ASICCtrl; - int countdown; - - /* ST201 documentation states ASICCtrl is a 32bit register */ - iowrite32 (reset_cmd | ioread32 (ioaddr), ioaddr); - /* ST201 documentation states reset can take up to 1 ms */ - countdown = 10 + 1; - while (ioread32 (ioaddr) & (ResetBusy << 16)) { - if (--countdown == 0) { - printk(KERN_WARNING "%s : reset not completed !!\n", dev->name); - break; - } - udelay(100); - } -} - static int __devinit sundance_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1214,33 +1190,23 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs ("%s: Transmit status is %2.2x.\n", dev->name, tx_status); if (tx_status & 0x1e) { - if (netif_msg_tx_err(np)) - printk("%s: Transmit error status %4.4x.\n", - dev->name, tx_status); np->stats.tx_errors++; if (tx_status & 0x10) np->stats.tx_fifo_errors++; if (tx_status & 0x08) np->stats.collisions++; - if (tx_status & 0x04) - np->stats.tx_fifo_errors++; if (tx_status & 0x02) np->stats.tx_window_errors++; - /* - ** This reset has been verified on - ** DFE-580TX boards ! phdm@macqel.be. - */ - if (tx_status & 0x10) { /* TxUnderrun */ - unsigned short txthreshold; - - txthreshold = ioread16 (ioaddr + TxStartThresh); - /* Restart Tx FIFO and transmitter */ - sundance_reset(dev, (NetworkReset|FIFOReset|TxReset) << 16); - iowrite16 (txthreshold, ioaddr + TxStartThresh); - /* No need to reset the Tx pointer here */ + /* This reset has not been verified!. */ + if (tx_status & 0x10) { /* Reset the Tx. */ + np->stats.tx_fifo_errors++; + spin_lock(&np->lock); + reset_tx(dev); + spin_unlock(&np->lock); } - /* Restart the Tx. */ - iowrite16 (TxEnable, ioaddr + MACCtrl1); + if (tx_status & 0x1e) /* Restart the Tx. */ + iowrite16 (TxEnable, + ioaddr + MACCtrl1); } /* Yup, this is a documentation bug. It cost me *hours*. */ iowrite16 (0, ioaddr + TxStatus); diff --git a/trunk/drivers/net/tg3.c b/trunk/drivers/net/tg3.c index 1828a6bf8458..1802c3b48799 100644 --- a/trunk/drivers/net/tg3.c +++ b/trunk/drivers/net/tg3.c @@ -37,7 +37,6 @@ #include #include #include -#include #include @@ -68,8 +67,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.43" -#define DRV_MODULE_RELDATE "Oct 24, 2005" +#define DRV_MODULE_VERSION "3.42" +#define DRV_MODULE_RELDATE "Oct 3, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -220,10 +219,6 @@ static struct pci_device_id tg3_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S, @@ -471,15 +466,6 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) spin_unlock_irqrestore(&tp->indirect_lock, flags); } -static void tg3_write_mem_fast(struct tg3 *tp, u32 off, u32 val) -{ - /* If no workaround is needed, write to mem space directly */ - if (tp->write32 != tg3_write_indirect_reg32) - tw32(NIC_SRAM_WIN_BASE + off, val); - else - tg3_write_mem(tp, off, val); -} - static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) { unsigned long flags; @@ -584,7 +570,7 @@ static void tg3_switch_clocks(struct tg3 *tp) u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL); u32 orig_clock_ctrl; - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) return; orig_clock_ctrl = clock_ctrl; @@ -1224,7 +1210,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state) CLOCK_CTRL_ALTCLK | CLOCK_CTRL_PWRDOWN_PLL133); udelay(40); - } else if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { /* do nothing */ } else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && (tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) { @@ -3726,14 +3712,14 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, dev->mtu = new_mtu; if (new_mtu > ETH_DATA_LEN) { - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; ethtool_op_set_tso(dev, 0); } else tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE; } else { - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; tp->tg3_flags &= ~TG3_FLAG_JUMBO_RING_ENABLE; } @@ -3864,7 +3850,7 @@ static void tg3_init_rings(struct tg3 *tp) memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); tp->rx_pkt_buf_sz = RX_PKT_BUF_SZ; - if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) && + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) && (tp->dev->mtu > ETH_DATA_LEN)) tp->rx_pkt_buf_sz = RX_JUMBO_PKT_BUF_SZ; @@ -3919,8 +3905,10 @@ static void tg3_init_rings(struct tg3 *tp) */ static void tg3_free_consistent(struct tg3 *tp) { - kfree(tp->rx_std_buffers); - tp->rx_std_buffers = NULL; + if (tp->rx_std_buffers) { + kfree(tp->rx_std_buffers); + tp->rx_std_buffers = NULL; + } if (tp->rx_std) { pci_free_consistent(tp->pdev, TG3_RX_RING_BYTES, tp->rx_std, tp->rx_std_mapping); @@ -4359,7 +4347,7 @@ static int tg3_chip_reset(struct tg3 *tp) val &= ~PCIX_CAPS_RELAXED_ORDERING; pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val); - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { u32 val; /* Chip reset on 5780 will reset MSI enable bit, @@ -6015,7 +6003,7 @@ static int tg3_reset_hw(struct tg3 *tp) tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK); if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780)) limit = 8; else limit = 16; @@ -6203,16 +6191,14 @@ static void tg3_timer(unsigned long __opaque) tp->timer_counter = tp->timer_multiplier; } - /* Heartbeat is only sent once every 2 seconds. */ + /* Heartbeat is only sent once every 120 seconds. */ if (!--tp->asf_counter) { if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { u32 val; - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_MBOX, - FWCMD_NICDRV_ALIVE2); - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); - /* 5 seconds timeout */ - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_ALIVE); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 3); val = tr32(GRC_RX_CPU_EVENT); val |= (1 << 14); tw32(GRC_RX_CPU_EVENT, val); @@ -6423,7 +6409,7 @@ static int tg3_open(struct net_device *dev) tp->timer_counter = tp->timer_multiplier = (HZ / tp->timer_offset); tp->asf_counter = tp->asf_multiplier = - ((HZ / tp->timer_offset) * 2); + ((HZ / tp->timer_offset) * 120); init_timer(&tp->timer); tp->timer.expires = jiffies + tp->timer_offset; @@ -7251,7 +7237,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported |= (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full); - if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) cmd->supported |= (SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_10baseT_Half | @@ -7278,7 +7264,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct tg3 *tp = netdev_priv(dev); - if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { /* These are the only valid advertisement bits allowed. */ if (cmd->autoneg == AUTONEG_ENABLE && (cmd->advertising & ~(ADVERTISED_1000baseT_Half | @@ -7286,17 +7272,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ADVERTISED_Autoneg | ADVERTISED_FIBRE))) return -EINVAL; - /* Fiber can only do SPEED_1000. */ - else if ((cmd->autoneg != AUTONEG_ENABLE) && - (cmd->speed != SPEED_1000)) - return -EINVAL; - /* Copper cannot force SPEED_1000. */ - } else if ((cmd->autoneg != AUTONEG_ENABLE) && - (cmd->speed == SPEED_1000)) - return -EINVAL; - else if ((cmd->speed == SPEED_1000) && - (tp->tg3_flags2 & TG3_FLAG_10_100_ONLY)) - return -EINVAL; + } tg3_full_lock(tp, 0); @@ -8404,7 +8380,7 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) } if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)) { switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) { case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: tp->nvram_jedecnum = JEDEC_ATMEL; @@ -9004,7 +8980,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->phy_id = eeprom_phy_id; if (eeprom_phy_serdes) { - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) tp->tg3_flags2 |= TG3_FLG2_MII_SERDES; else tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; @@ -9417,11 +9393,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } /* Find msi capability. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { - tp->tg3_flags2 |= TG3_FLG2_5780_CLASS; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI); - } /* Initialize misc host control in PCI block. */ tp->misc_host_ctrl |= (misc_ctrl_reg & @@ -9439,7 +9412,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) || @@ -9634,7 +9607,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) * ether_setup() via the alloc_etherdev() call */ if (tp->dev->mtu > ETH_DATA_LEN && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780) tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE; /* Determine WakeOnLan speed to use. */ @@ -9857,7 +9830,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) mac_offset = 0x7c; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && !(tp->tg3_flags & TG3_FLG2_SUN_570X)) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID) mac_offset = 0xcc; if (tg3_nvram_lock(tp)) @@ -10175,9 +10148,6 @@ static int __devinit tg3_test_dma(struct tg3 *tp) } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { /* 5780 always in PCIX mode */ tp->dma_rwctrl |= 0x00144000; - } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { - /* 5714 always in PCIX mode */ - tp->dma_rwctrl |= 0x00148000; } else { tp->dma_rwctrl |= 0x001b000f; } @@ -10377,7 +10347,6 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5705: return "5705"; case PHY_ID_BCM5750: return "5750"; case PHY_ID_BCM5752: return "5752"; - case PHY_ID_BCM5714: return "5714"; case PHY_ID_BCM5780: return "5780"; case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; @@ -10523,17 +10492,17 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, } /* Configure DMA attributes. */ - err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + err = pci_set_dma_mask(pdev, 0xffffffffffffffffULL); if (!err) { pci_using_dac = 1; - err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + err = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL); if (err < 0) { printk(KERN_ERR PFX "Unable to obtain 64 bit DMA " "for consistent allocations\n"); goto err_out_free_res; } } else { - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + err = pci_set_dma_mask(pdev, 0xffffffffULL); if (err) { printk(KERN_ERR PFX "No usable DMA configuration, " "aborting.\n"); diff --git a/trunk/drivers/net/tg3.h b/trunk/drivers/net/tg3.h index fb7e2a5f4a08..2e733c60bfa4 100644 --- a/trunk/drivers/net/tg3.h +++ b/trunk/drivers/net/tg3.h @@ -137,7 +137,6 @@ #define ASIC_REV_5750 0x04 #define ASIC_REV_5752 0x06 #define ASIC_REV_5780 0x08 -#define ASIC_REV_5714 0x09 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -532,8 +531,6 @@ #define MAC_SERDES_CFG_EDGE_SELECT 0x00001000 #define MAC_SERDES_STAT 0x00000594 /* 0x598 --> 0x5b0 unused */ -#define SERDES_RX_CTRL 0x000005b0 /* 5780/5714 only */ -#define SERDES_RX_SIG_DETECT 0x00000400 #define SG_DIG_CTRL 0x000005b0 #define SG_DIG_USING_HW_AUTONEG 0x80000000 #define SG_DIG_SOFT_RESET 0x40000000 @@ -1332,8 +1329,6 @@ #define GRC_LCLCTRL_CLEARINT 0x00000002 #define GRC_LCLCTRL_SETINT 0x00000004 #define GRC_LCLCTRL_INT_ON_ATTN 0x00000008 -#define GRC_LCLCTRL_USE_SIG_DETECT 0x00000010 /* 5714/5780 only */ -#define GRC_LCLCTRL_USE_EXT_SIG_DETECT 0x00000020 /* 5714/5780 only */ #define GRC_LCLCTRL_GPIO_INPUT3 0x00000020 #define GRC_LCLCTRL_GPIO_OE3 0x00000040 #define GRC_LCLCTRL_GPIO_OUTPUT3 0x00000080 @@ -1512,7 +1507,6 @@ #define FWCMD_NICDRV_IPV6ADDR_CHG 0x00000004 #define FWCMD_NICDRV_FIX_DMAR 0x00000005 #define FWCMD_NICDRV_FIX_DMAW 0x00000006 -#define FWCMD_NICDRV_ALIVE2 0x0000000d #define NIC_SRAM_FW_CMD_LEN_MBOX 0x00000b7c #define NIC_SRAM_FW_CMD_DATA_MBOX 0x00000b80 #define NIC_SRAM_FW_ASF_STATUS_MBOX 0x00000c00 @@ -2181,7 +2175,6 @@ struct tg3 { TG3_FLG2_MII_SERDES) #define TG3_FLG2_PARALLEL_DETECT 0x01000000 #define TG3_FLG2_ICH_WORKAROUND 0x02000000 -#define TG3_FLG2_5780_CLASS 0x04000000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 @@ -2229,7 +2222,6 @@ struct tg3 { #define PHY_ID_BCM5705 0x600081a0 #define PHY_ID_BCM5750 0x60008180 #define PHY_ID_BCM5752 0x60008100 -#define PHY_ID_BCM5714 0x60008340 #define PHY_ID_BCM5780 0x60008350 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff @@ -2254,8 +2246,8 @@ struct tg3 { (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \ (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \ (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \ - (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \ - (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM8002) + (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5780 || \ + (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; diff --git a/trunk/drivers/net/tulip/de2104x.c b/trunk/drivers/net/tulip/de2104x.c index d7fb3ffe06ac..6b8eee8f7bfd 100644 --- a/trunk/drivers/net/tulip/de2104x.c +++ b/trunk/drivers/net/tulip/de2104x.c @@ -2076,7 +2076,8 @@ static int __init de_init_one (struct pci_dev *pdev, return 0; err_out_iomap: - kfree(de->ee_data); + if (de->ee_data) + kfree(de->ee_data); iounmap(regs); err_out_res: pci_release_regions(pdev); @@ -2095,7 +2096,8 @@ static void __exit de_remove_one (struct pci_dev *pdev) if (!dev) BUG(); unregister_netdev(dev); - kfree(de->ee_data); + if (de->ee_data) + kfree(de->ee_data); iounmap(de->regs); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/trunk/drivers/net/tulip/tulip_core.c b/trunk/drivers/net/tulip/tulip_core.c index 125ed00e95a5..6266a9a7e6e3 100644 --- a/trunk/drivers/net/tulip/tulip_core.c +++ b/trunk/drivers/net/tulip/tulip_core.c @@ -1727,7 +1727,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, tp->rx_ring, tp->rx_ring_dma); err_out_mtable: - kfree (tp->mtable); + if (tp->mtable) + kfree (tp->mtable); pci_iounmap(pdev, ioaddr); err_out_free_res: @@ -1805,7 +1806,8 @@ static void __devexit tulip_remove_one (struct pci_dev *pdev) sizeof (struct tulip_rx_desc) * RX_RING_SIZE + sizeof (struct tulip_tx_desc) * TX_RING_SIZE, tp->rx_ring, tp->rx_ring_dma); - kfree (tp->mtable); + if (tp->mtable) + kfree (tp->mtable); pci_iounmap(pdev, tp->base_addr); free_netdev (dev); pci_release_regions (pdev); diff --git a/trunk/drivers/net/via-velocity.c b/trunk/drivers/net/via-velocity.c index a368d08e7d19..abc5cee6eedc 100644 --- a/trunk/drivers/net/via-velocity.c +++ b/trunk/drivers/net/via-velocity.c @@ -1212,8 +1212,10 @@ static void velocity_free_td_ring(struct velocity_info *vptr) velocity_free_td_ring_entry(vptr, j, i); } - kfree(vptr->td_infos[j]); - vptr->td_infos[j] = NULL; + if (vptr->td_infos[j]) { + kfree(vptr->td_infos[j]); + vptr->td_infos[j] = NULL; + } } } diff --git a/trunk/drivers/net/wireless/airo.c b/trunk/drivers/net/wireless/airo.c index 4c11699bad91..cb429e783749 100644 --- a/trunk/drivers/net/wireless/airo.c +++ b/trunk/drivers/net/wireless/airo.c @@ -2381,10 +2381,14 @@ void stop_airo_card( struct net_device *dev, int freeres ) dev_kfree_skb(skb); } - kfree(ai->flash); - kfree(ai->rssi); - kfree(ai->APList); - kfree(ai->SSID); + if (ai->flash) + kfree(ai->flash); + if (ai->rssi) + kfree(ai->rssi); + if (ai->APList) + kfree(ai->APList); + if (ai->SSID) + kfree(ai->SSID); if (freeres) { /* PCMCIA frees this stuff, so only for PCI and ISA */ release_region( dev->base_addr, 64 ); @@ -3622,8 +3626,10 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) int rc; memset( &mySsid, 0, sizeof( mySsid ) ); - kfree (ai->flash); - ai->flash = NULL; + if (ai->flash) { + kfree (ai->flash); + ai->flash = NULL; + } /* The NOP is the first step in getting the card going */ cmd.cmd = NOP; @@ -3660,10 +3666,14 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) tdsRssiRid rssi_rid; CapabilityRid cap_rid; - kfree(ai->APList); - ai->APList = NULL; - kfree(ai->SSID); - ai->SSID = NULL; + if (ai->APList) { + kfree(ai->APList); + ai->APList = NULL; + } + if (ai->SSID) { + kfree(ai->SSID); + ai->SSID = NULL; + } // general configuration (read/modify/write) status = readConfigRid(ai, lock); if ( status != SUCCESS ) return ERROR; @@ -3677,8 +3687,10 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */ } else { - kfree(ai->rssi); - ai->rssi = NULL; + if (ai->rssi) { + kfree(ai->rssi); + ai->rssi = NULL; + } if (cap_rid.softCap & 8) ai->config.rmode |= RXMODE_NORMALIZED_RSSI; else @@ -5357,13 +5369,11 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { static int proc_close( struct inode *inode, struct file *file ) { - struct proc_data *data = file->private_data; - - if (data->on_close != NULL) - data->on_close(inode, file); - kfree(data->rbuffer); - kfree(data->wbuffer); - kfree(data); + struct proc_data *data = (struct proc_data *)file->private_data; + if ( data->on_close != NULL ) data->on_close( inode, file ); + if ( data->rbuffer ) kfree( data->rbuffer ); + if ( data->wbuffer ) kfree( data->wbuffer ); + kfree( data ); return 0; } diff --git a/trunk/drivers/net/wireless/airo_cs.c b/trunk/drivers/net/wireless/airo_cs.c index 784de9109113..bf25584d68d3 100644 --- a/trunk/drivers/net/wireless/airo_cs.c +++ b/trunk/drivers/net/wireless/airo_cs.c @@ -258,7 +258,9 @@ static void airo_detach(dev_link_t *link) /* Unlink device structure, free pieces */ *linkp = link->next; - kfree(link->priv); + if (link->priv) { + kfree(link->priv); + } kfree(link); } /* airo_detach */ diff --git a/trunk/drivers/net/wireless/atmel.c b/trunk/drivers/net/wireless/atmel.c index 1fbe027d26b6..d57011028b72 100644 --- a/trunk/drivers/net/wireless/atmel.c +++ b/trunk/drivers/net/wireless/atmel.c @@ -1653,7 +1653,8 @@ void stop_atmel_card(struct net_device *dev, int freeres) unregister_netdev(dev); remove_proc_entry("driver/atmel", NULL); free_irq(dev->irq, dev); - kfree(priv->firmware); + if (priv->firmware) + kfree(priv->firmware); if (freeres) { /* PCMCIA frees this stuff, so only for PCI */ release_region(dev->base_addr, 64); @@ -2449,7 +2450,8 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) break; } - kfree(priv->firmware); + if (priv->firmware) + kfree(priv->firmware); priv->firmware = new_firmware; priv->firmware_length = com.len; diff --git a/trunk/drivers/net/wireless/atmel_cs.c b/trunk/drivers/net/wireless/atmel_cs.c index 195cb36619e8..ff031a3985b3 100644 --- a/trunk/drivers/net/wireless/atmel_cs.c +++ b/trunk/drivers/net/wireless/atmel_cs.c @@ -259,7 +259,8 @@ static void atmel_detach(dev_link_t *link) /* Unlink device structure, free pieces */ *linkp = link->next; - kfree(link->priv); + if (link->priv) + kfree(link->priv); kfree(link); } diff --git a/trunk/drivers/net/wireless/hermes.c b/trunk/drivers/net/wireless/hermes.c index 579480dad374..eba0d9d2b7c5 100644 --- a/trunk/drivers/net/wireless/hermes.c +++ b/trunk/drivers/net/wireless/hermes.c @@ -444,43 +444,6 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, return err; } -/* Write a block of data to the chip's buffer with padding if - * neccessary, via the BAP. Synchronization/serialization is the - * caller's problem. len must be even. - * - * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware - */ -int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf, unsigned data_len, unsigned len, - u16 id, u16 offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if (len < 0 || len % 2 || data_len > len) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Transfer all the complete words of data */ - hermes_write_words(hw, dreg, buf, data_len/2); - /* If there is an odd byte left over pad and transfer it */ - if (data_len & 1) { - u8 end[2]; - end[1] = 0; - end[0] = ((unsigned char *)buf)[data_len - 1]; - hermes_write_words(hw, dreg, end, 1); - data_len ++; - } - /* Now send zeros for the padding */ - if (data_len < len) - hermes_clear_words(hw, dreg, (len - data_len) / 2); - /* Complete */ - out: - return err; -} - /* Read a Length-Type-Value record from the card. * * If length is NULL, we ignore the length read from the card, and @@ -568,7 +531,6 @@ EXPORT_SYMBOL(hermes_allocate); EXPORT_SYMBOL(hermes_bap_pread); EXPORT_SYMBOL(hermes_bap_pwrite); -EXPORT_SYMBOL(hermes_bap_pwrite_pad); EXPORT_SYMBOL(hermes_read_ltv); EXPORT_SYMBOL(hermes_write_ltv); diff --git a/trunk/drivers/net/wireless/hermes.h b/trunk/drivers/net/wireless/hermes.h index a6bd472d75d4..ad28e3294360 100644 --- a/trunk/drivers/net/wireless/hermes.h +++ b/trunk/drivers/net/wireless/hermes.h @@ -376,8 +376,6 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len, u16 id, u16 offset); int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, u16 id, u16 offset); -int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf, - unsigned data_len, unsigned len, u16 id, u16 offset); int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen, u16 *length, void *buf); int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, diff --git a/trunk/drivers/net/wireless/hostap/hostap_ioctl.c b/trunk/drivers/net/wireless/hostap/hostap_ioctl.c index 2617d70bcda9..53f5246c40aa 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/trunk/drivers/net/wireless/hostap/hostap_ioctl.c @@ -552,6 +552,7 @@ static int prism2_ioctl_giwaplist(struct net_device *dev, kfree(addr); kfree(qual); + return 0; } @@ -3080,7 +3081,9 @@ static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p) ret = local->func->download(local, param); out: - kfree(param); + if (param != NULL) + kfree(param); + return ret; } #endif /* PRISM2_DOWNLOAD_SUPPORT */ @@ -3887,7 +3890,9 @@ static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p) } out: - kfree(param); + if (param != NULL) + kfree(param); + return ret; } diff --git a/trunk/drivers/net/wireless/ipw2200.c b/trunk/drivers/net/wireless/ipw2200.c index 3db0c32afe82..de4e6c23e4b8 100644 --- a/trunk/drivers/net/wireless/ipw2200.c +++ b/trunk/drivers/net/wireless/ipw2200.c @@ -4030,10 +4030,6 @@ static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv) int i; rxq = (struct ipw_rx_queue *)kmalloc(sizeof(*rxq), GFP_KERNEL); - if (unlikely(!rxq)) { - IPW_ERROR("memory allocation failed\n"); - return NULL; - } memset(rxq, 0, sizeof(*rxq)); spin_lock_init(&rxq->lock); INIT_LIST_HEAD(&rxq->rx_free); diff --git a/trunk/drivers/net/wireless/orinoco.c b/trunk/drivers/net/wireless/orinoco.c index 488ab06fb79f..d3d4ec9e242e 100644 --- a/trunk/drivers/net/wireless/orinoco.c +++ b/trunk/drivers/net/wireless/orinoco.c @@ -490,8 +490,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } - /* Length of the packet body */ - /* FIXME: what if the skb is smaller than this? */ + /* Check packet length, pad short packets, round up odd length */ len = max_t(int, ALIGN(skb->len, 2), ETH_ZLEN); skb = skb_padto(skb, len); if (skb == NULL) @@ -542,21 +541,13 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) stats->tx_errors++; goto fail; } - /* Actual xfer length - allow for padding */ - len = ALIGN(data_len, 2); - if (len < ETH_ZLEN - ETH_HLEN) - len = ETH_ZLEN - ETH_HLEN; } else { /* IEEE 802.3 frame */ data_len = len + ETH_HLEN; data_off = HERMES_802_3_OFFSET; p = skb->data; - /* Actual xfer length - round up for odd length packets */ - len = ALIGN(data_len, 2); - if (len < ETH_ZLEN) - len = ETH_ZLEN; } - err = hermes_bap_pwrite_pad(hw, USER_BAP, p, data_len, len, + err = hermes_bap_pwrite(hw, USER_BAP, p, data_len, txfid, data_off); if (err) { printk(KERN_ERR "%s: Error %d writing packet to BAP\n", diff --git a/trunk/drivers/net/wireless/prism54/islpci_dev.c b/trunk/drivers/net/wireless/prism54/islpci_dev.c index 78bdb359835e..6c9584a9f284 100644 --- a/trunk/drivers/net/wireless/prism54/islpci_dev.c +++ b/trunk/drivers/net/wireless/prism54/islpci_dev.c @@ -754,7 +754,8 @@ islpci_free_memory(islpci_private *priv) pci_unmap_single(priv->pdev, buf->pci_addr, buf->size, PCI_DMA_FROMDEVICE); buf->pci_addr = 0; - kfree(buf->mem); + if (buf->mem) + kfree(buf->mem); buf->size = 0; buf->mem = NULL; } diff --git a/trunk/drivers/net/wireless/prism54/islpci_eth.c b/trunk/drivers/net/wireless/prism54/islpci_eth.c index 3b49efa37ee5..5952e9960499 100644 --- a/trunk/drivers/net/wireless/prism54/islpci_eth.c +++ b/trunk/drivers/net/wireless/prism54/islpci_eth.c @@ -97,6 +97,12 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) /* lock the driver code */ spin_lock_irqsave(&priv->slock, flags); + /* determine the amount of fragments needed to store the frame */ + + frame_size = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + if (init_wds) + frame_size += 6; + /* check whether the destination queue has enough fragments for the frame */ curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]); if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) { @@ -207,7 +213,6 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) /* store the skb address for future freeing */ priv->data_low_tx[index] = skb; /* set the proper fragment start address and size information */ - frame_size = skb->len; fragment->size = cpu_to_le16(frame_size); fragment->flags = cpu_to_le16(0); /* set to 1 if more fragments */ fragment->address = cpu_to_le32(pci_map_address); @@ -241,10 +246,12 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) return 0; drop_free: - priv->statistics.tx_dropped++; - spin_unlock_irqrestore(&priv->slock, flags); + /* free the skbuf structure before aborting */ dev_kfree_skb(skb); skb = NULL; + + priv->statistics.tx_dropped++; + spin_unlock_irqrestore(&priv->slock, flags); return err; } diff --git a/trunk/drivers/net/wireless/prism54/oid_mgt.c b/trunk/drivers/net/wireless/prism54/oid_mgt.c index eea2f04c8c6d..12123e24b113 100644 --- a/trunk/drivers/net/wireless/prism54/oid_mgt.c +++ b/trunk/drivers/net/wireless/prism54/oid_mgt.c @@ -268,10 +268,11 @@ mgt_clean(islpci_private *priv) if (!priv->mib) return; - for (i = 0; i < OID_NUM_LAST; i++) { - kfree(priv->mib[i]); - priv->mib[i] = NULL; - } + for (i = 0; i < OID_NUM_LAST; i++) + if (priv->mib[i]) { + kfree(priv->mib[i]); + priv->mib[i] = NULL; + } kfree(priv->mib); priv->mib = NULL; } diff --git a/trunk/drivers/net/wireless/strip.c b/trunk/drivers/net/wireless/strip.c index d25264ba0c0e..7bc7fc823128 100644 --- a/trunk/drivers/net/wireless/strip.c +++ b/trunk/drivers/net/wireless/strip.c @@ -860,9 +860,12 @@ static int allocate_buffers(struct strip *strip_info, int mtu) strip_info->mtu = dev->mtu = mtu; return (1); } - kfree(r); - kfree(s); - kfree(t); + if (r) + kfree(r); + if (s) + kfree(s); + if (t) + kfree(t); return (0); } @@ -919,9 +922,13 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu) printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n", strip_info->dev->name, old_mtu, strip_info->mtu); - kfree(orbuff); - kfree(osbuff); - kfree(otbuff); + if (orbuff) + kfree(orbuff); + if (osbuff) + kfree(osbuff); + if (otbuff) + kfree(otbuff); + return 0; } @@ -2491,13 +2498,18 @@ static int strip_close_low(struct net_device *dev) /* * Free all STRIP frame buffers. */ - kfree(strip_info->rx_buff); - strip_info->rx_buff = NULL; - kfree(strip_info->sx_buff); - strip_info->sx_buff = NULL; - kfree(strip_info->tx_buff); - strip_info->tx_buff = NULL; - + if (strip_info->rx_buff) { + kfree(strip_info->rx_buff); + strip_info->rx_buff = NULL; + } + if (strip_info->sx_buff) { + kfree(strip_info->sx_buff); + strip_info->sx_buff = NULL; + } + if (strip_info->tx_buff) { + kfree(strip_info->tx_buff); + strip_info->tx_buff = NULL; + } del_timer(&strip_info->idle_timer); return 0; } diff --git a/trunk/drivers/scsi/libata-core.c b/trunk/drivers/scsi/libata-core.c index b1b1c6f01419..f53d7b8ac33f 100644 --- a/trunk/drivers/scsi/libata-core.c +++ b/trunk/drivers/scsi/libata-core.c @@ -370,8 +370,6 @@ static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - tf->command = ata_check_status(ap); - tf->feature = ata_chk_err(ap); tf->nsect = inb(ioaddr->nsect_addr); tf->lbal = inb(ioaddr->lbal_addr); tf->lbam = inb(ioaddr->lbam_addr); @@ -404,8 +402,6 @@ static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - tf->command = ata_check_status(ap); - tf->feature = ata_chk_err(ap); tf->nsect = readb((void __iomem *)ioaddr->nsect_addr); tf->lbal = readb((void __iomem *)ioaddr->lbal_addr); tf->lbam = readb((void __iomem *)ioaddr->lbam_addr); @@ -4258,10 +4254,11 @@ int ata_device_add(const struct ata_probe_ent *ent) DPRINTK("ENTER\n"); /* alloc a container for our list of ATA ports (buses) */ - host_set = kzalloc(sizeof(struct ata_host_set) + + host_set = kmalloc(sizeof(struct ata_host_set) + (ent->n_ports * sizeof(void *)), GFP_KERNEL); if (!host_set) return 0; + memset(host_set, 0, sizeof(struct ata_host_set) + (ent->n_ports * sizeof(void *))); spin_lock_init(&host_set->lock); host_set->dev = dev; @@ -4301,8 +4298,10 @@ int ata_device_add(const struct ata_probe_ent *ent) count++; } - if (!count) - goto err_free_ret; + if (!count) { + kfree(host_set); + return 0; + } /* obtain irq, that is shared between channels */ if (request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags, @@ -4360,7 +4359,6 @@ int ata_device_add(const struct ata_probe_ent *ent) ata_host_remove(host_set->ports[i], 1); scsi_host_put(host_set->ports[i]->host); } -err_free_ret: kfree(host_set); VPRINTK("EXIT, returning 0\n"); return 0; @@ -4470,13 +4468,15 @@ ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) { struct ata_probe_ent *probe_ent; - probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL); + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (!probe_ent) { printk(KERN_ERR DRV_NAME "(%s): out of memory\n", kobject_name(&(dev->kobj))); return NULL; } + memset(probe_ent, 0, sizeof(*probe_ent)); + INIT_LIST_HEAD(&probe_ent->node); probe_ent->dev = dev; diff --git a/trunk/drivers/scsi/libata-scsi.c b/trunk/drivers/scsi/libata-scsi.c index 89a04b1a5a0e..58858886d751 100644 --- a/trunk/drivers/scsi/libata-scsi.c +++ b/trunk/drivers/scsi/libata-scsi.c @@ -40,56 +40,14 @@ #include "scsi.h" #include #include -#include #include #include "libata.h" -#define SECTOR_SIZE 512 - typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd); static struct ata_device * ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); -#define RW_RECOVERY_MPAGE 0x1 -#define RW_RECOVERY_MPAGE_LEN 12 -#define CACHE_MPAGE 0x8 -#define CACHE_MPAGE_LEN 20 -#define CONTROL_MPAGE 0xa -#define CONTROL_MPAGE_LEN 12 -#define ALL_MPAGES 0x3f -#define ALL_SUB_MPAGES 0xff - - -static const u8 def_rw_recovery_mpage[] = { - RW_RECOVERY_MPAGE, - RW_RECOVERY_MPAGE_LEN - 2, - (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */ - (1 << 6), /* ARRE (auto read reallocation) */ - 0, /* read retry count */ - 0, 0, 0, 0, - 0, /* write retry count */ - 0, 0, 0 -}; - -static const u8 def_cache_mpage[CACHE_MPAGE_LEN] = { - CACHE_MPAGE, - CACHE_MPAGE_LEN - 2, - 0, /* contains WCE, needs to be 0 for logic */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, /* contains DRA, needs to be 0 for logic */ - 0, 0, 0, 0, 0, 0, 0 -}; - -static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = { - CONTROL_MPAGE, - CONTROL_MPAGE_LEN - 2, - 2, /* DSENSE=0, GLTSD=1 */ - 0, /* [QAM+QERR may be 1, see 05-359r1] */ - 0, 0, 0, 0, 0xff, 0xff, - 0, 30 /* extended self test time, see 05-359r1 */ -}; - static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) @@ -128,150 +86,6 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, return 0; } -/** - * ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl - * @dev: Device to whom we are issuing command - * @arg: User provided data for issuing command - * - * LOCKING: - * Defined by the SCSI layer. We don't really care. - * - * RETURNS: - * Zero on success, negative errno on error. - */ - -int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) -{ - int rc = 0; - u8 scsi_cmd[MAX_COMMAND_SIZE]; - u8 args[4], *argbuf = NULL; - int argsize = 0; - struct scsi_request *sreq; - - if (NULL == (void *)arg) - return -EINVAL; - - if (copy_from_user(args, arg, sizeof(args))) - return -EFAULT; - - sreq = scsi_allocate_request(scsidev, GFP_KERNEL); - if (!sreq) - return -EINTR; - - memset(scsi_cmd, 0, sizeof(scsi_cmd)); - - if (args[3]) { - argsize = SECTOR_SIZE * args[3]; - argbuf = kmalloc(argsize, GFP_KERNEL); - if (argbuf == NULL) { - rc = -ENOMEM; - goto error; - } - - scsi_cmd[1] = (4 << 1); /* PIO Data-in */ - scsi_cmd[2] = 0x0e; /* no off.line or cc, read from dev, - block count in sector count field */ - sreq->sr_data_direction = DMA_FROM_DEVICE; - } else { - scsi_cmd[1] = (3 << 1); /* Non-data */ - /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */ - sreq->sr_data_direction = DMA_NONE; - } - - scsi_cmd[0] = ATA_16; - - scsi_cmd[4] = args[2]; - if (args[0] == WIN_SMART) { /* hack -- ide driver does this too... */ - scsi_cmd[6] = args[3]; - scsi_cmd[8] = args[1]; - scsi_cmd[10] = 0x4f; - scsi_cmd[12] = 0xc2; - } else { - scsi_cmd[6] = args[1]; - } - scsi_cmd[14] = args[0]; - - /* Good values for timeout and retries? Values below - from scsi_ioctl_send_command() for default case... */ - scsi_wait_req(sreq, scsi_cmd, argbuf, argsize, (10*HZ), 5); - - if (sreq->sr_result) { - rc = -EIO; - goto error; - } - - /* Need code to retrieve data from check condition? */ - - if ((argbuf) - && copy_to_user((void *)(arg + sizeof(args)), argbuf, argsize)) - rc = -EFAULT; -error: - scsi_release_request(sreq); - - if (argbuf) - kfree(argbuf); - - return rc; -} - -/** - * ata_task_ioctl - Handler for HDIO_DRIVE_TASK ioctl - * @dev: Device to whom we are issuing command - * @arg: User provided data for issuing command - * - * LOCKING: - * Defined by the SCSI layer. We don't really care. - * - * RETURNS: - * Zero on success, negative errno on error. - */ -int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg) -{ - int rc = 0; - u8 scsi_cmd[MAX_COMMAND_SIZE]; - u8 args[7]; - struct scsi_request *sreq; - - if (NULL == (void *)arg) - return -EINVAL; - - if (copy_from_user(args, arg, sizeof(args))) - return -EFAULT; - - memset(scsi_cmd, 0, sizeof(scsi_cmd)); - scsi_cmd[0] = ATA_16; - scsi_cmd[1] = (3 << 1); /* Non-data */ - /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */ - scsi_cmd[4] = args[1]; - scsi_cmd[6] = args[2]; - scsi_cmd[8] = args[3]; - scsi_cmd[10] = args[4]; - scsi_cmd[12] = args[5]; - scsi_cmd[14] = args[0]; - - sreq = scsi_allocate_request(scsidev, GFP_KERNEL); - if (!sreq) { - rc = -EINTR; - goto error; - } - - sreq->sr_data_direction = DMA_NONE; - /* Good values for timeout and retries? Values below - from scsi_ioctl_send_command() for default case... */ - scsi_wait_req(sreq, scsi_cmd, NULL, 0, (10*HZ), 5); - - if (sreq->sr_result) { - rc = -EIO; - goto error; - } - - /* Need code to retrieve data from check condition? */ - -error: - scsi_release_request(sreq); - return rc; -} - int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) { struct ata_port *ap; @@ -301,16 +115,6 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) return -EINVAL; return 0; - case HDIO_DRIVE_CMD: - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - return ata_cmd_ioctl(scsidev, arg); - - case HDIO_DRIVE_TASK: - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - return ata_task_ioctl(scsidev, arg); - default: rc = -ENOTTY; break; @@ -368,71 +172,24 @@ struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap, return qc; } -/** - * ata_dump_status - user friendly display of error info - * @id: id of the port in question - * @tf: ptr to filled out taskfile - * - * Decode and dump the ATA error/status registers for the user so - * that they have some idea what really happened at the non - * make-believe layer. - * - * LOCKING: - * inherited from caller - */ -void ata_dump_status(unsigned id, struct ata_taskfile *tf) -{ - u8 stat = tf->command, err = tf->feature; - - printk(KERN_WARNING "ata%u: status=0x%02x { ", id, stat); - if (stat & ATA_BUSY) { - printk("Busy }\n"); /* Data is not valid in this case */ - } else { - if (stat & 0x40) printk("DriveReady "); - if (stat & 0x20) printk("DeviceFault "); - if (stat & 0x10) printk("SeekComplete "); - if (stat & 0x08) printk("DataRequest "); - if (stat & 0x04) printk("CorrectedError "); - if (stat & 0x02) printk("Index "); - if (stat & 0x01) printk("Error "); - printk("}\n"); - - if (err) { - printk(KERN_WARNING "ata%u: error=0x%02x { ", id, err); - if (err & 0x04) printk("DriveStatusError "); - if (err & 0x80) { - if (err & 0x04) printk("BadCRC "); - else printk("Sector "); - } - if (err & 0x40) printk("UncorrectableError "); - if (err & 0x10) printk("SectorIdNotFound "); - if (err & 0x02) printk("TrackZeroNotFound "); - if (err & 0x01) printk("AddrMarkNotFound "); - printk("}\n"); - } - } -} - /** * ata_to_sense_error - convert ATA error to SCSI error + * @qc: Command that we are erroring out * @drv_stat: value contained in ATA status register - * @drv_err: value contained in ATA error register - * @sk: the sense key we'll fill out - * @asc: the additional sense code we'll fill out - * @ascq: the additional sense code qualifier we'll fill out * - * Converts an ATA error into a SCSI error. Fill out pointers to - * SK, ASC, and ASCQ bytes for later use in fixed or descriptor - * format sense blocks. + * Converts an ATA error into a SCSI error. While we are at it + * we decode and dump the ATA error for the user so that they + * have some idea what really happened at the non make-believe + * layer. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, - u8 *ascq) -{ - int i; +void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + u8 err = 0; /* Based on the 3ware driver translation table */ static unsigned char sense_table[][4] = { /* BBD|ECC|ID|MAR */ @@ -473,184 +230,96 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered {0xFF, 0xFF, 0xFF, 0xFF}, // END mark }; + int i = 0; /* * Is this an error we can process/parse */ - if (drv_stat & ATA_BUSY) { - drv_err = 0; /* Ignore the err bits, they're invalid */ - } - - if (drv_err) { - /* Look for drv_err */ - for (i = 0; sense_table[i][0] != 0xFF; i++) { - /* Look for best matches first */ - if ((sense_table[i][0] & drv_err) == - sense_table[i][0]) { - *sk = sense_table[i][1]; - *asc = sense_table[i][2]; - *ascq = sense_table[i][3]; - goto translate_done; - } - } - /* No immediate match */ - printk(KERN_WARNING "ata%u: no sense translation for " - "error 0x%02x\n", id, drv_err); - } - - /* Fall back to interpreting status bits */ - for (i = 0; stat_table[i][0] != 0xFF; i++) { - if (stat_table[i][0] & drv_stat) { - *sk = stat_table[i][1]; - *asc = stat_table[i][2]; - *ascq = stat_table[i][3]; - goto translate_done; - } - } - /* No error? Undecoded? */ - printk(KERN_WARNING "ata%u: no sense translation for status: 0x%02x\n", - id, drv_stat); - - /* For our last chance pick, use medium read error because - * it's much more common than an ATA drive telling you a write - * has failed. - */ - *sk = MEDIUM_ERROR; - *asc = 0x11; /* "unrecovered read error" */ - *ascq = 0x04; /* "auto-reallocation failed" */ - - translate_done: - printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x to " - "SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n", id, drv_stat, drv_err, - *sk, *asc, *ascq); - return; -} - -/* - * ata_gen_ata_desc_sense - Generate check condition sense block. - * @qc: Command that completed. - * - * This function is specific to the ATA descriptor format sense - * block specified for the ATA pass through commands. Regardless - * of whether the command errored or not, return a sense - * block. Copy all controller registers into the sense - * block. Clear sense key, ASC & ASCQ if there is no error. - * - * LOCKING: - * spin_lock_irqsave(host_set lock) - */ -void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) -{ - struct scsi_cmnd *cmd = qc->scsicmd; - struct ata_taskfile *tf = &qc->tf; - unsigned char *sb = cmd->sense_buffer; - unsigned char *desc = sb + 8; - - memset(sb, 0, SCSI_SENSE_BUFFERSIZE); - cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + if(drv_stat & ATA_ERR) + /* Read the err bits */ + err = ata_chk_err(qc->ap); - /* - * Read the controller registers. - */ - assert(NULL != qc->ap->ops->tf_read); - qc->ap->ops->tf_read(qc->ap, tf); + /* Display the ATA level error info */ - /* - * Use ata_to_sense_error() to map status register bits - * onto sense key, asc & ascq. - */ - if (unlikely(tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) { - ata_to_sense_error(qc->ap->id, tf->command, tf->feature, - &sb[1], &sb[2], &sb[3]); - sb[1] &= 0x0f; + printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat); + if(drv_stat & 0x80) + { + printk("Busy "); + err = 0; /* Data is not valid in this case */ } - - /* - * Sense data is current and format is descriptor. - */ - sb[0] = 0x72; - - desc[0] = 0x09; - - /* - * Set length of additional sense data. - * Since we only populate descriptor 0, the total - * length is the same (fixed) length as descriptor 0. - */ - desc[1] = sb[7] = 14; - - /* - * Copy registers into sense buffer. - */ - desc[2] = 0x00; - desc[3] = tf->feature; /* == error reg */ - desc[5] = tf->nsect; - desc[7] = tf->lbal; - desc[9] = tf->lbam; - desc[11] = tf->lbah; - desc[12] = tf->device; - desc[13] = tf->command; /* == status reg */ - - /* - * Fill in Extend bit, and the high order bytes - * if applicable. - */ - if (tf->flags & ATA_TFLAG_LBA48) { - desc[2] |= 0x01; - desc[4] = tf->hob_nsect; - desc[6] = tf->hob_lbal; - desc[8] = tf->hob_lbam; - desc[10] = tf->hob_lbah; + else { + if(drv_stat & 0x40) printk("DriveReady "); + if(drv_stat & 0x20) printk("DeviceFault "); + if(drv_stat & 0x10) printk("SeekComplete "); + if(drv_stat & 0x08) printk("DataRequest "); + if(drv_stat & 0x04) printk("CorrectedError "); + if(drv_stat & 0x02) printk("Index "); + if(drv_stat & 0x01) printk("Error "); } -} - -/** - * ata_gen_fixed_sense - generate a SCSI fixed sense block - * @qc: Command that we are erroring out - * - * Leverage ata_to_sense_error() to give us the codes. Fit our - * LBA in here if there's room. - * - * LOCKING: - * inherited from caller - */ -void ata_gen_fixed_sense(struct ata_queued_cmd *qc) -{ - struct scsi_cmnd *cmd = qc->scsicmd; - struct ata_taskfile *tf = &qc->tf; - unsigned char *sb = cmd->sense_buffer; - - memset(sb, 0, SCSI_SENSE_BUFFERSIZE); + printk("}\n"); + + if(err) + { + printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err); + if(err & 0x04) printk("DriveStatusError "); + if(err & 0x80) + { + if(err & 0x04) + printk("BadCRC "); + else + printk("Sector "); + } + if(err & 0x40) printk("UncorrectableError "); + if(err & 0x10) printk("SectorIdNotFound "); + if(err & 0x02) printk("TrackZeroNotFound "); + if(err & 0x01) printk("AddrMarkNotFound "); + printk("}\n"); - cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + /* Should we dump sector info here too ?? */ + } - /* - * Read the controller registers. - */ - assert(NULL != qc->ap->ops->tf_read); - qc->ap->ops->tf_read(qc->ap, tf); - /* - * Use ata_to_sense_error() to map status register bits - * onto sense key, asc & ascq. - */ - if (unlikely(tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) { - ata_to_sense_error(qc->ap->id, tf->command, tf->feature, - &sb[2], &sb[12], &sb[13]); - sb[2] &= 0x0f; + /* Look for err */ + while(sense_table[i][0] != 0xFF) + { + /* Look for best matches first */ + if((sense_table[i][0] & err) == sense_table[i][0]) + { + ata_scsi_set_sense(cmd, sense_table[i][1] /* sk */, + sense_table[i][2] /* asc */, + sense_table[i][3] /* ascq */ ); + return; + } + i++; } + /* No immediate match */ + if(err) + printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err); - sb[0] = 0x70; - sb[7] = 0x0a; + i = 0; + /* Fall back to interpreting status bits */ + while(stat_table[i][0] != 0xFF) + { + if(stat_table[i][0] & drv_stat) + { + ata_scsi_set_sense(cmd, sense_table[i][1] /* sk */, + sense_table[i][2] /* asc */, + sense_table[i][3] /* ascq */ ); + return; + } + i++; + } + /* No error ?? */ + printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat); + /* additional-sense-code[-qualifier] */ - if (tf->flags & ATA_TFLAG_LBA && !(tf->flags & ATA_TFLAG_LBA48)) { - /* A small (28b) LBA will fit in the 32b info field */ - sb[0] |= 0x80; /* set valid bit */ - sb[3] = tf->device & 0x0f; - sb[4] = tf->lbah; - sb[5] = tf->lbam; - sb[6] = tf->lbal; + if (cmd->sc_data_direction == DMA_FROM_DEVICE) { + ata_scsi_set_sense(cmd, MEDIUM_ERROR, 0x11, 0x4); + /* "unrecovered read error" */ + } else { + ata_scsi_set_sense(cmd, MEDIUM_ERROR, 0xc, 0x2); + /* "write error - auto-reallocation failed" */ } } @@ -1202,36 +871,11 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; - int need_sense = drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ); - - /* For ATA pass thru (SAT) commands, generate a sense block if - * user mandated it or if there's an error. Note that if we - * generate because the user forced us to, a check condition - * is generated and the ATA register values are returned - * whether the command completed successfully or not. If there - * was no error, SK, ASC and ASCQ will all be zero. - */ - if (((cmd->cmnd[0] == ATA_16) || (cmd->cmnd[0] == ATA_12)) && - ((cmd->cmnd[2] & 0x20) || need_sense)) { - ata_gen_ata_desc_sense(qc); - } else { - if (!need_sense) { - cmd->result = SAM_STAT_GOOD; - } else { - /* TODO: decide which descriptor format to use - * for 48b LBA devices and call that here - * instead of the fixed desc, which is only - * good for smaller LBA (and maybe CHS?) - * devices. - */ - ata_gen_fixed_sense(qc); - } - } - if (need_sense) { - /* The ata_gen_..._sense routines fill in tf */ - ata_dump_status(qc->ap->id, &qc->tf); - } + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) + ata_to_sense_error(qc, drv_stat); + else + cmd->result = SAM_STAT_GOOD; qc->scsidone(cmd); @@ -1622,9 +1266,13 @@ static void ata_msense_push(u8 **ptr_io, const u8 *last, static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io, const u8 *last) { - u8 page[CACHE_MPAGE_LEN]; + u8 page[] = { + 0x8, /* page code */ + 0x12, /* page length */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 zeroes */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 8 zeroes */ + }; - memcpy(page, def_cache_mpage, sizeof(page)); if (ata_id_wcache_enabled(id)) page[2] |= (1 << 2); /* write cache enable */ if (!ata_id_rahead_enabled(id)) @@ -1648,9 +1296,15 @@ static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io, static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) { - ata_msense_push(ptr_io, last, def_control_mpage, - sizeof(def_control_mpage)); - return sizeof(def_control_mpage); + const u8 page[] = {0xa, 0xa, 6, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 30}; + + /* byte 2: set the descriptor format sense data bit (bit 2) + * since we need to support returning this format for SAT + * commands and any SCSI commands against a 48b LBA device. + */ + + ata_msense_push(ptr_io, last, page, sizeof(page)); + return sizeof(page); } /** @@ -1667,10 +1321,15 @@ static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) { + const u8 page[] = { + 0x1, /* page code */ + 0xa, /* page length */ + (1 << 7) | (1 << 6), /* note auto r/w reallocation */ + 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 9 zeroes */ + }; - ata_msense_push(ptr_io, last, def_rw_recovery_mpage, - sizeof(def_rw_recovery_mpage)); - return sizeof(def_rw_recovery_mpage); + ata_msense_push(ptr_io, last, page, sizeof(page)); + return sizeof(page); } /** @@ -1679,9 +1338,7 @@ static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * @buflen: Response buffer length. * - * Simulate MODE SENSE commands. Assume this is invoked for direct - * access devices (e.g. disks) only. There should be no block - * descriptor for other device types. + * Simulate MODE SENSE commands. * * LOCKING: * spin_lock_irqsave(host_set lock) @@ -1691,22 +1348,15 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen) { u8 *scsicmd = args->cmd->cmnd, *p, *last; - const u8 sat_blk_desc[] = { - 0, 0, 0, 0, /* number of blocks: sat unspecified */ - 0, - 0, 0x2, 0x0 /* block length: 512 bytes */ - }; - u8 pg, spg; - unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen; + unsigned int page_control, six_byte, output_len; VPRINTK("ENTER\n"); six_byte = (scsicmd[0] == MODE_SENSE); - ebd = !(scsicmd[1] & 0x8); /* dbd bit inverted == edb */ - /* - * LLBA bit in msense(10) ignored (compliant) - */ + /* we only support saved and current values (which we treat + * in the same manner) + */ page_control = scsicmd[2] >> 6; switch (page_control) { case 0: /* current */ @@ -1719,42 +1369,29 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, goto invalid_fld; } - if (six_byte) { - output_len = 4 + (ebd ? 8 : 0); - alloc_len = scsicmd[4]; - } else { - output_len = 8 + (ebd ? 8 : 0); - alloc_len = (scsicmd[7] << 8) + scsicmd[8]; - } - minlen = (alloc_len < buflen) ? alloc_len : buflen; + if (six_byte) + output_len = 4; + else + output_len = 8; p = rbuf + output_len; - last = rbuf + minlen - 1; + last = rbuf + buflen - 1; - pg = scsicmd[2] & 0x3f; - spg = scsicmd[3]; - /* - * No mode subpages supported (yet) but asking for _all_ - * subpages may be valid - */ - if (spg && (spg != ALL_SUB_MPAGES)) - goto invalid_fld; - - switch(pg) { - case RW_RECOVERY_MPAGE: + switch(scsicmd[2] & 0x3f) { + case 0x01: /* r/w error recovery */ output_len += ata_msense_rw_recovery(&p, last); break; - case CACHE_MPAGE: + case 0x08: /* caching */ output_len += ata_msense_caching(args->id, &p, last); break; - case CONTROL_MPAGE: { + case 0x0a: { /* control mode */ output_len += ata_msense_ctl_mode(&p, last); break; } - case ALL_MPAGES: + case 0x3f: /* all pages */ output_len += ata_msense_rw_recovery(&p, last); output_len += ata_msense_caching(args->id, &p, last); output_len += ata_msense_ctl_mode(&p, last); @@ -1764,31 +1401,15 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, goto invalid_fld; } - if (minlen < 1) - return 0; if (six_byte) { output_len--; rbuf[0] = output_len; - if (ebd) { - if (minlen > 3) - rbuf[3] = sizeof(sat_blk_desc); - if (minlen > 11) - memcpy(rbuf + 4, sat_blk_desc, - sizeof(sat_blk_desc)); - } } else { output_len -= 2; rbuf[0] = output_len >> 8; - if (minlen > 1) - rbuf[1] = output_len; - if (ebd) { - if (minlen > 7) - rbuf[7] = sizeof(sat_blk_desc); - if (minlen > 15) - memcpy(rbuf + 8, sat_blk_desc, - sizeof(sat_blk_desc)); - } + rbuf[1] = output_len; } + return 0; invalid_fld: @@ -2002,12 +1623,7 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) VPRINTK("ENTER, drv_stat == 0x%x\n", drv_stat); if (unlikely(drv_stat & (ATA_BUSY | ATA_DRQ))) - /* FIXME: not quite right; we don't want the - * translation of taskfile registers into - * a sense descriptors, since that's only - * correct for ATA, not ATAPI - */ - ata_gen_ata_desc_sense(qc); + ata_to_sense_error(qc, drv_stat); else if (unlikely(drv_stat & ATA_ERR)) { DPRINTK("request check condition\n"); @@ -2166,143 +1782,6 @@ ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev) return dev; } -/* - * ata_scsi_map_proto - Map pass-thru protocol value to taskfile value. - * @byte1: Byte 1 from pass-thru CDB. - * - * RETURNS: - * ATA_PROT_UNKNOWN if mapping failed/unimplemented, protocol otherwise. - */ -static u8 -ata_scsi_map_proto(u8 byte1) -{ - switch((byte1 & 0x1e) >> 1) { - case 3: /* Non-data */ - return ATA_PROT_NODATA; - - case 6: /* DMA */ - return ATA_PROT_DMA; - - case 4: /* PIO Data-in */ - case 5: /* PIO Data-out */ - if (byte1 & 0xe0) { - return ATA_PROT_PIO_MULT; - } - return ATA_PROT_PIO; - - case 10: /* Device Reset */ - case 0: /* Hard Reset */ - case 1: /* SRST */ - case 2: /* Bus Idle */ - case 7: /* Packet */ - case 8: /* DMA Queued */ - case 9: /* Device Diagnostic */ - case 11: /* UDMA Data-in */ - case 12: /* UDMA Data-Out */ - case 13: /* FPDMA */ - default: /* Reserved */ - break; - } - - return ATA_PROT_UNKNOWN; -} - -/** - * ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile - * @qc: command structure to be initialized - * @cmd: SCSI command to convert - * - * Handles either 12 or 16-byte versions of the CDB. - * - * RETURNS: - * Zero on success, non-zero on failure. - */ -static unsigned int -ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) -{ - struct ata_taskfile *tf = &(qc->tf); - struct scsi_cmnd *cmd = qc->scsicmd; - - if ((tf->protocol = ata_scsi_map_proto(scsicmd[1])) == ATA_PROT_UNKNOWN) - return 1; - - /* - * 12 and 16 byte CDBs use different offsets to - * provide the various register values. - */ - if (scsicmd[0] == ATA_16) { - /* - * 16-byte CDB - may contain extended commands. - * - * If that is the case, copy the upper byte register values. - */ - if (scsicmd[1] & 0x01) { - tf->hob_feature = scsicmd[3]; - tf->hob_nsect = scsicmd[5]; - tf->hob_lbal = scsicmd[7]; - tf->hob_lbam = scsicmd[9]; - tf->hob_lbah = scsicmd[11]; - tf->flags |= ATA_TFLAG_LBA48; - } else - tf->flags &= ~ATA_TFLAG_LBA48; - - /* - * Always copy low byte, device and command registers. - */ - tf->feature = scsicmd[4]; - tf->nsect = scsicmd[6]; - tf->lbal = scsicmd[8]; - tf->lbam = scsicmd[10]; - tf->lbah = scsicmd[12]; - tf->device = scsicmd[13]; - tf->command = scsicmd[14]; - } else { - /* - * 12-byte CDB - incapable of extended commands. - */ - tf->flags &= ~ATA_TFLAG_LBA48; - - tf->feature = scsicmd[3]; - tf->nsect = scsicmd[4]; - tf->lbal = scsicmd[5]; - tf->lbam = scsicmd[6]; - tf->lbah = scsicmd[7]; - tf->device = scsicmd[8]; - tf->command = scsicmd[9]; - } - - /* - * Filter SET_FEATURES - XFER MODE command -- otherwise, - * SET_FEATURES - XFER MODE must be preceded/succeeded - * by an update to hardware-specific registers for each - * controller (i.e. the reason for ->set_piomode(), - * ->set_dmamode(), and ->post_set_mode() hooks). - */ - if ((tf->command == ATA_CMD_SET_FEATURES) - && (tf->feature == SETFEATURES_XFER)) - return 1; - - /* - * Set flags so that all registers will be written, - * and pass on write indication (used for PIO/DMA - * setup.) - */ - tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE); - - if (cmd->sc_data_direction == DMA_TO_DEVICE) - tf->flags |= ATA_TFLAG_WRITE; - - /* - * Set transfer length. - * - * TODO: find out if we need to do more here to - * cover scatter/gather case. - */ - qc->nsect = cmd->bufflen / ATA_SECT_SIZE; - - return 0; -} - /** * ata_get_xlat_func - check if SCSI to ATA translation is possible * @dev: ATA device @@ -2335,11 +1814,6 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) case VERIFY: case VERIFY_16: return ata_scsi_verify_xlat; - - case ATA_12: - case ATA_16: - return ata_scsi_pass_thru; - case START_STOP: return ata_scsi_start_stop_xlat; } @@ -2498,7 +1972,7 @@ void ata_scsi_simulate(u16 *id, ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns); break; - /* mandatory commands we haven't implemented yet */ + /* mandantory commands we haven't implemented yet */ case REQUEST_SENSE: /* all other commands */ diff --git a/trunk/drivers/scsi/libata.h b/trunk/drivers/scsi/libata.h index 65c264b91136..3d60190584ba 100644 --- a/trunk/drivers/scsi/libata.h +++ b/trunk/drivers/scsi/libata.h @@ -50,14 +50,13 @@ extern void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep); extern void ata_tf_to_host_nolock(struct ata_port *ap, const struct ata_taskfile *tf); extern void swap_buf_le16(u16 *buf, unsigned int buf_words); -extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); -extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); /* libata-scsi.c */ extern void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, struct scsi_cmnd *cmd); extern void ata_scsi_scan_host(struct ata_port *ap); +extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat); extern int ata_scsi_error(struct Scsi_Host *host); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); diff --git a/trunk/drivers/scsi/pdc_adma.c b/trunk/drivers/scsi/pdc_adma.c index af99feb9d237..9820f272f889 100644 --- a/trunk/drivers/scsi/pdc_adma.c +++ b/trunk/drivers/scsi/pdc_adma.c @@ -46,7 +46,7 @@ #include #define DRV_NAME "pdc_adma" -#define DRV_VERSION "0.03" +#define DRV_VERSION "0.01" /* macro to calculate base address for ATA regs */ #define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40)) @@ -79,6 +79,7 @@ enum { aNIEN = (1 << 8), /* irq mask: 1==masked */ aGO = (1 << 7), /* packet trigger ("Go!") */ aRSTADM = (1 << 5), /* ADMA logic reset */ + aRSTA = (1 << 2), /* ATA hard reset */ aPIOMD4 = 0x0003, /* PIO mode 4 */ /* ADMA_STATUS register bits */ @@ -451,25 +452,24 @@ static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set) struct adma_port_priv *pp; struct ata_queued_cmd *qc; void __iomem *chan = ADMA_REGS(mmio_base, port_no); - u8 drv_stat = 0, status = readb(chan + ADMA_STATUS); + u8 drv_stat, status = readb(chan + ADMA_STATUS); if (status == 0) continue; handled = 1; adma_enter_reg_mode(ap); - if (ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR)) + if ((ap->flags & ATA_FLAG_PORT_DISABLED)) continue; pp = ap->private_data; if (!pp || pp->state != adma_state_pkt) continue; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) { - if ((status & (aPERR | aPSD | aUIRQ))) - drv_stat = ATA_ERR; - else if (pp->pkt[0] != cDONE) - drv_stat = ATA_ERR; - ata_qc_complete(qc, drv_stat); - } + drv_stat = 0; + if ((status & (aPERR | aPSD | aUIRQ))) + drv_stat = ATA_ERR; + else if (pp->pkt[0] != cDONE) + drv_stat = ATA_ERR; + ata_qc_complete(qc, drv_stat); } return handled; } @@ -490,7 +490,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set) if (qc && (!(qc->tf.ctl & ATA_NIEN))) { /* check main status, clearing INTRQ */ - u8 status = ata_check_status(ap); + u8 status = ata_chk_status(ap); if ((status & ATA_BUSY)) continue; DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", @@ -561,15 +561,15 @@ static int adma_port_start(struct ata_port *ap) if ((pp->pkt_dma & 7) != 0) { printk("bad alignment for pp->pkt_dma: %08x\n", (u32)pp->pkt_dma); - dma_free_coherent(dev, ADMA_PKT_BYTES, - pp->pkt, pp->pkt_dma); - goto err_out_kfree; + goto err_out_kfree2; } memset(pp->pkt, 0, ADMA_PKT_BYTES); ap->private_data = pp; adma_reinit_engine(ap); return 0; +err_out_kfree2: + kfree(pp); err_out_kfree: kfree(pp); err_out: diff --git a/trunk/drivers/scsi/sata_promise.c b/trunk/drivers/scsi/sata_promise.c index 63911f16b6ec..eee93b0016df 100644 --- a/trunk/drivers/scsi/sata_promise.c +++ b/trunk/drivers/scsi/sata_promise.c @@ -195,8 +195,6 @@ static struct ata_port_info pdc_port_info[] = { static struct pci_device_id pdc_ata_pci_tbl[] = { { PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, - { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3571, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0, @@ -209,8 +207,6 @@ static struct pci_device_id pdc_ata_pci_tbl[] = { board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, - { PCI_VENDOR_ID_PROMISE, 0x3d73, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20319 }, diff --git a/trunk/drivers/scsi/sata_qstor.c b/trunk/drivers/scsi/sata_qstor.c index 1aaf3304d397..250dafa6bc36 100644 --- a/trunk/drivers/scsi/sata_qstor.c +++ b/trunk/drivers/scsi/sata_qstor.c @@ -433,7 +433,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set) if (qc && (!(qc->tf.ctl & ATA_NIEN))) { /* check main status, clearing INTRQ */ - u8 status = ata_check_status(ap); + u8 status = ata_chk_status(ap); if ((status & ATA_BUSY)) continue; DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", diff --git a/trunk/drivers/scsi/sata_svw.c b/trunk/drivers/scsi/sata_svw.c index 46208f52d0e1..e0f9570bc6dd 100644 --- a/trunk/drivers/scsi/sata_svw.c +++ b/trunk/drivers/scsi/sata_svw.c @@ -84,8 +84,6 @@ /* Port stride */ #define K2_SATA_PORT_OFFSET 0x100 -static u8 k2_stat_check_status(struct ata_port *ap); - static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { @@ -138,24 +136,16 @@ static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - u16 nsect, lbal, lbam, lbah, feature; + u16 nsect, lbal, lbam, lbah; - tf->command = k2_stat_check_status(ap); + nsect = tf->nsect = readw(ioaddr->nsect_addr); + lbal = tf->lbal = readw(ioaddr->lbal_addr); + lbam = tf->lbam = readw(ioaddr->lbam_addr); + lbah = tf->lbah = readw(ioaddr->lbah_addr); tf->device = readw(ioaddr->device_addr); - feature = readw(ioaddr->error_addr); - nsect = readw(ioaddr->nsect_addr); - lbal = readw(ioaddr->lbal_addr); - lbam = readw(ioaddr->lbam_addr); - lbah = readw(ioaddr->lbah_addr); - - tf->feature = feature; - tf->nsect = nsect; - tf->lbal = lbal; - tf->lbam = lbam; - tf->lbah = lbah; if (tf->flags & ATA_TFLAG_LBA48) { - tf->hob_feature = feature >> 8; + tf->hob_feature = readw(ioaddr->error_addr) >> 8; tf->hob_nsect = nsect >> 8; tf->hob_lbal = lbal >> 8; tf->hob_lbam = lbam >> 8; diff --git a/trunk/drivers/scsi/sata_vsc.c b/trunk/drivers/scsi/sata_vsc.c index 54273e0063c7..5af05fdf8544 100644 --- a/trunk/drivers/scsi/sata_vsc.c +++ b/trunk/drivers/scsi/sata_vsc.c @@ -153,24 +153,16 @@ static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - u16 nsect, lbal, lbam, lbah, feature; + u16 nsect, lbal, lbam, lbah; - tf->command = ata_check_status(ap); + nsect = tf->nsect = readw(ioaddr->nsect_addr); + lbal = tf->lbal = readw(ioaddr->lbal_addr); + lbam = tf->lbam = readw(ioaddr->lbam_addr); + lbah = tf->lbah = readw(ioaddr->lbah_addr); tf->device = readw(ioaddr->device_addr); - feature = readw(ioaddr->error_addr); - nsect = readw(ioaddr->nsect_addr); - lbal = readw(ioaddr->lbal_addr); - lbam = readw(ioaddr->lbam_addr); - lbah = readw(ioaddr->lbah_addr); - - tf->feature = feature; - tf->nsect = nsect; - tf->lbal = lbal; - tf->lbam = lbam; - tf->lbah = lbah; if (tf->flags & ATA_TFLAG_LBA48) { - tf->hob_feature = feature >> 8; + tf->hob_feature = readb(ioaddr->error_addr); tf->hob_nsect = nsect >> 8; tf->hob_lbal = lbal >> 8; tf->hob_lbam = lbam >> 8; diff --git a/trunk/include/linux/fs_enet_pd.h b/trunk/include/linux/fs_enet_pd.h deleted file mode 100644 index bef23bbf8690..000000000000 --- a/trunk/include/linux/fs_enet_pd.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Platform information definitions for the - * universal Freescale Ethernet driver. - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#ifndef FS_ENET_PD_H -#define FS_ENET_PD_H - -#include -#include - -#define FS_ENET_NAME "fs_enet" - -enum fs_id { - fsid_fec1, - fsid_fec2, - fsid_fcc1, - fsid_fcc2, - fsid_fcc3, - fsid_scc1, - fsid_scc2, - fsid_scc3, - fsid_scc4, -}; - -#define FS_MAX_INDEX 9 - -static inline int fs_get_fec_index(enum fs_id id) -{ - if (id >= fsid_fec1 && id <= fsid_fec2) - return id - fsid_fec1; - return -1; -} - -static inline int fs_get_fcc_index(enum fs_id id) -{ - if (id >= fsid_fcc1 && id <= fsid_fcc3) - return id - fsid_fcc1; - return -1; -} - -static inline int fs_get_scc_index(enum fs_id id) -{ - if (id >= fsid_scc1 && id <= fsid_scc4) - return id - fsid_scc1; - return -1; -} - -enum fs_mii_method { - fsmii_fixed, - fsmii_fec, - fsmii_bitbang, -}; - -enum fs_ioport { - fsiop_porta, - fsiop_portb, - fsiop_portc, - fsiop_portd, - fsiop_porte, -}; - -struct fs_mii_bus_info { - int method; /* mii method */ - int id; /* the id of the mii_bus */ - int disable_aneg; /* if the controller needs to negothiate speed & duplex */ - int lpa; /* the default board-specific vallues will be applied otherwise */ - - union { - struct { - int duplex; - int speed; - } fixed; - - struct { - /* nothing */ - } fec; - - struct { - /* nothing */ - } scc; - - struct { - int mdio_port; /* port & bit for MDIO */ - int mdio_bit; - int mdc_port; /* port & bit for MDC */ - int mdc_bit; - int delay; /* delay in us */ - } bitbang; - } i; -}; - -struct fs_platform_info { - - void(*init_ioports)(void); - /* device specific information */ - int fs_no; /* controller index */ - - u32 cp_page; /* CPM page */ - u32 cp_block; /* CPM sblock */ - - u32 clk_trx; /* some stuff for pins & mux configuration*/ - u32 clk_route; - u32 clk_mask; - - u32 mem_offset; - u32 dpram_offset; - u32 fcc_regs_c; - - u32 device_flags; - - int phy_addr; /* the phy address (-1 no phy) */ - int phy_irq; /* the phy irq (if it exists) */ - - const struct fs_mii_bus_info *bus_info; - - int rx_ring, tx_ring; /* number of buffers on rx */ - __u8 macaddr[6]; /* mac address */ - int rx_copybreak; /* limit we copy small frames */ - int use_napi; /* use NAPI */ - int napi_weight; /* NAPI weight */ - - int use_rmii; /* use RMII mode */ -}; - -#endif diff --git a/trunk/include/linux/pci_ids.h b/trunk/include/linux/pci_ids.h index 56192005fa4d..467a096c3b81 100644 --- a/trunk/include/linux/pci_ids.h +++ b/trunk/include/linux/pci_ids.h @@ -1788,13 +1788,11 @@ #define PCI_DEVICE_ID_TIGON3_5721 0x1659 #define PCI_DEVICE_ID_TIGON3_5705M 0x165d #define PCI_DEVICE_ID_TIGON3_5705M_2 0x165e -#define PCI_DEVICE_ID_TIGON3_5714 0x1668 #define PCI_DEVICE_ID_TIGON3_5780 0x166a #define PCI_DEVICE_ID_TIGON3_5780S 0x166b #define PCI_DEVICE_ID_TIGON3_5705F 0x166e #define PCI_DEVICE_ID_TIGON3_5750 0x1676 #define PCI_DEVICE_ID_TIGON3_5751 0x1677 -#define PCI_DEVICE_ID_TIGON3_5715 0x1678 #define PCI_DEVICE_ID_TIGON3_5750M 0x167c #define PCI_DEVICE_ID_TIGON3_5751M 0x167d #define PCI_DEVICE_ID_TIGON3_5751F 0x167e diff --git a/trunk/include/net/ax25.h b/trunk/include/net/ax25.h index 2250a18b0cbb..30bb4a893237 100644 --- a/trunk/include/net/ax25.h +++ b/trunk/include/net/ax25.h @@ -237,7 +237,8 @@ typedef struct ax25_cb { static __inline__ void ax25_cb_put(ax25_cb *ax25) { if (atomic_dec_and_test(&ax25->refcount)) { - kfree(ax25->digipeat); + if (ax25->digipeat) + kfree(ax25->digipeat); kfree(ax25); } } diff --git a/trunk/include/net/netrom.h b/trunk/include/net/netrom.h index a5ee53bce62f..a6bf6e0f606a 100644 --- a/trunk/include/net/netrom.h +++ b/trunk/include/net/netrom.h @@ -136,7 +136,8 @@ static __inline__ void nr_node_put(struct nr_node *nr_node) static __inline__ void nr_neigh_put(struct nr_neigh *nr_neigh) { if (atomic_dec_and_test(&nr_neigh->refcount)) { - kfree(nr_neigh->digipeat); + if (nr_neigh->digipeat != NULL) + kfree(nr_neigh->digipeat); kfree(nr_neigh); } } diff --git a/trunk/include/scsi/scsi.h b/trunk/include/scsi/scsi.h index 6cb1e2788d8b..b361172b576c 100644 --- a/trunk/include/scsi/scsi.h +++ b/trunk/include/scsi/scsi.h @@ -116,9 +116,6 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; /* values for service action in */ #define SAI_READ_CAPACITY_16 0x10 -/* Values for T10/04-262r7 */ -#define ATA_16 0x85 /* 16-byte pass-thru */ -#define ATA_12 0xa1 /* 12-byte pass-thru */ /* * SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft