Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
This commit is contained in:
Коммит
62d3af1b5f
|
@ -1945,6 +1945,14 @@ 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
|
||||
|
|
|
@ -1163,38 +1163,74 @@ config IBMVETH
|
|||
be called ibmveth.
|
||||
|
||||
config IBM_EMAC
|
||||
bool "IBM PPC4xx EMAC driver support"
|
||||
tristate "PowerPC 4xx on-chip Ethernet support"
|
||||
depends on 4xx
|
||||
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
|
||||
help
|
||||
This driver supports the PowerPC 4xx EMAC family of on-chip
|
||||
Ethernet controllers.
|
||||
|
||||
config IBM_EMAC_RXB
|
||||
int "Number of receive buffers"
|
||||
depends on IBM_EMAC
|
||||
default "128" if IBM_EMAC4
|
||||
default "64"
|
||||
default "128"
|
||||
|
||||
config IBM_EMAC_TXB
|
||||
int "Number of transmit buffers"
|
||||
depends on IBM_EMAC
|
||||
default "128" if IBM_EMAC4
|
||||
default "8"
|
||||
default "64"
|
||||
|
||||
config IBM_EMAC_FGAP
|
||||
int "Frame gap"
|
||||
config IBM_EMAC_POLL_WEIGHT
|
||||
int "MAL NAPI polling weight"
|
||||
depends on IBM_EMAC
|
||||
default "8"
|
||||
default "32"
|
||||
|
||||
config IBM_EMAC_SKBRES
|
||||
int "Skb reserve amount"
|
||||
config IBM_EMAC_RX_COPY_THRESHOLD
|
||||
int "RX skb copy threshold (bytes)"
|
||||
depends on IBM_EMAC
|
||||
default "256"
|
||||
|
||||
config IBM_EMAC_RX_SKB_HEADROOM
|
||||
int "Additional RX skb headroom (bytes)"
|
||||
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"
|
||||
|
@ -1775,6 +1811,7 @@ config NE_H8300
|
|||
controller on the Renesas H8/300 processor.
|
||||
|
||||
source "drivers/net/fec_8xx/Kconfig"
|
||||
source "drivers/net/fs_enet/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
|
@ -2201,8 +2238,8 @@ config S2IO
|
|||
depends on PCI
|
||||
---help---
|
||||
This driver supports the 10Gbe XFrame NIC of S2IO.
|
||||
For help regarding driver compilation, installation and
|
||||
tuning please look into ~/drivers/net/s2io/README.txt.
|
||||
More specific information on configuring the driver is in
|
||||
<file:Documentation/networking/s2io.txt>.
|
||||
|
||||
config S2IO_NAPI
|
||||
bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
|
||||
|
|
|
@ -203,3 +203,6 @@ obj-$(CONFIG_IRDA) += irda/
|
|||
obj-$(CONFIG_ETRAX_ETHERNET) += cris/
|
||||
|
||||
obj-$(CONFIG_NETCONSOLE) += netconsole.o
|
||||
|
||||
obj-$(CONFIG_FS_ENET) += fs_enet/
|
||||
|
||||
|
|
|
@ -871,10 +871,8 @@ 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);
|
||||
if (ap->skb)
|
||||
kfree(ap->skb);
|
||||
if (ap->trace_buf)
|
||||
kfree(ap->trace_buf);
|
||||
kfree(ap->skb);
|
||||
kfree(ap->trace_buf);
|
||||
|
||||
if (dev->irq)
|
||||
free_irq(dev->irq, dev);
|
||||
|
|
|
@ -1606,8 +1606,7 @@ err_out:
|
|||
/* here we should have a valid dev plus aup-> register addresses
|
||||
* so we can reset the mac properly.*/
|
||||
reset_mac(dev);
|
||||
if (aup->mii)
|
||||
kfree(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]);
|
||||
|
@ -1806,8 +1805,7 @@ static void __exit au1000_cleanup_module(void)
|
|||
if (dev) {
|
||||
aup = (struct au1000_private *) dev->priv;
|
||||
unregister_netdev(dev);
|
||||
if (aup->mii)
|
||||
kfree(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]);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
|
@ -1130,14 +1131,10 @@ static void b44_init_rings(struct b44 *bp)
|
|||
*/
|
||||
static void b44_free_consistent(struct b44 *bp)
|
||||
{
|
||||
if (bp->rx_buffers) {
|
||||
kfree(bp->rx_buffers);
|
||||
bp->rx_buffers = NULL;
|
||||
}
|
||||
if (bp->tx_buffers) {
|
||||
kfree(bp->tx_buffers);
|
||||
bp->tx_buffers = NULL;
|
||||
}
|
||||
kfree(bp->rx_buffers);
|
||||
bp->rx_buffers = NULL;
|
||||
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,
|
||||
|
@ -1619,14 +1616,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 |= ADVERTISE_10HALF;
|
||||
cmd->advertising |= ADVERTISED_10baseT_Half;
|
||||
if (bp->flags & B44_FLAG_ADV_10FULL)
|
||||
cmd->advertising |= ADVERTISE_10FULL;
|
||||
cmd->advertising |= ADVERTISED_10baseT_Full;
|
||||
if (bp->flags & B44_FLAG_ADV_100HALF)
|
||||
cmd->advertising |= ADVERTISE_100HALF;
|
||||
cmd->advertising |= ADVERTISED_100baseT_Half;
|
||||
if (bp->flags & B44_FLAG_ADV_100FULL)
|
||||
cmd->advertising |= ADVERTISE_100FULL;
|
||||
cmd->advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
|
||||
cmd->advertising |= ADVERTISED_100baseT_Full;
|
||||
cmd->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
|
||||
cmd->speed = (bp->flags & B44_FLAG_100_BASE_T) ?
|
||||
SPEED_100 : SPEED_10;
|
||||
cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ?
|
||||
|
@ -2044,6 +2041,8 @@ 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;
|
||||
}
|
||||
|
@ -2060,6 +2059,9 @@ 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);
|
||||
|
|
|
@ -1689,10 +1689,8 @@ static void __exit bmac_exit(void)
|
|||
{
|
||||
macio_unregister_driver(&bmac_driver);
|
||||
|
||||
if (bmac_emergency_rxbuf != NULL) {
|
||||
kfree(bmac_emergency_rxbuf);
|
||||
bmac_emergency_rxbuf = NULL;
|
||||
}
|
||||
kfree(bmac_emergency_rxbuf);
|
||||
bmac_emergency_rxbuf = NULL;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Randy Gobbel/Paul Mackerras");
|
||||
|
|
|
@ -314,20 +314,16 @@ bnx2_free_mem(struct bnx2 *bp)
|
|||
bp->tx_desc_ring, bp->tx_desc_mapping);
|
||||
bp->tx_desc_ring = NULL;
|
||||
}
|
||||
if (bp->tx_buf_ring) {
|
||||
kfree(bp->tx_buf_ring);
|
||||
bp->tx_buf_ring = NULL;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (bp->rx_buf_ring) {
|
||||
kfree(bp->rx_buf_ring);
|
||||
bp->rx_buf_ring = NULL;
|
||||
}
|
||||
kfree(bp->rx_buf_ring);
|
||||
bp->rx_buf_ring = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -965,11 +965,8 @@ e1000_free_desc_rings(struct e1000_adapter *adapter)
|
|||
if(rxdr->desc)
|
||||
pci_free_consistent(pdev, rxdr->size, rxdr->desc, rxdr->dma);
|
||||
|
||||
if(txdr->buffer_info)
|
||||
kfree(txdr->buffer_info);
|
||||
if(rxdr->buffer_info)
|
||||
kfree(rxdr->buffer_info);
|
||||
|
||||
kfree(txdr->buffer_info);
|
||||
kfree(rxdr->buffer_info);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
static int e1000_suspend(struct pci_dev *pdev, pm_message_t state);
|
||||
#ifdef CONFIG_PM
|
||||
static int e1000_suspend(struct pci_dev *pdev, pm_message_t state);
|
||||
static int e1000_resume(struct pci_dev *pdev);
|
||||
#endif
|
||||
|
||||
|
@ -1149,7 +1149,8 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter,
|
|||
int size;
|
||||
|
||||
size = sizeof(struct e1000_buffer) * txdr->count;
|
||||
txdr->buffer_info = vmalloc(size);
|
||||
|
||||
txdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus));
|
||||
if(!txdr->buffer_info) {
|
||||
DPRINTK(PROBE, ERR,
|
||||
"Unable to allocate memory for the transmit descriptor ring\n");
|
||||
|
@ -1366,7 +1367,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter,
|
|||
int size, desc_len;
|
||||
|
||||
size = sizeof(struct e1000_buffer) * rxdr->count;
|
||||
rxdr->buffer_info = vmalloc(size);
|
||||
rxdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus));
|
||||
if (!rxdr->buffer_info) {
|
||||
DPRINTK(PROBE, ERR,
|
||||
"Unable to allocate memory for the receive descriptor ring\n");
|
||||
|
@ -4193,6 +4194,7 @@ 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)
|
||||
{
|
||||
|
@ -4289,7 +4291,6 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int
|
||||
e1000_resume(struct pci_dev *pdev)
|
||||
{
|
||||
|
|
|
@ -1797,10 +1797,9 @@ MODULE_AUTHOR("Pascal Dupuis and others");
|
|||
MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
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_array(io, int, NULL, 0);
|
||||
module_param_array(irq, int, NULL, 0);
|
||||
module_param_array(mem, int, NULL, 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)");
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
# 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
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,507 @@
|
|||
/*
|
||||
* Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
|
||||
*
|
||||
* Copyright (c) 2003 Intracom S.A.
|
||||
* by Pantelis Antoniou <panto@intracom.gr>
|
||||
*
|
||||
* 2005 (c) MontaVista Software, Inc.
|
||||
* Vitaly Bordug <vbordug@ru.mvista.com>
|
||||
*
|
||||
* Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>
|
||||
* and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
|
||||
*
|
||||
* 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 <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#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);
|
||||
}
|
|
@ -0,0 +1,245 @@
|
|||
#ifndef FS_ENET_H
|
||||
#define FS_ENET_H
|
||||
|
||||
#include <linux/mii.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include <linux/fs_enet_pd.h>
|
||||
|
||||
#include <asm/dma-mapping.h>
|
||||
|
||||
#ifdef CONFIG_CPM1
|
||||
#include <asm/commproc.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPM2
|
||||
#include <asm/cpm2.h>
|
||||
#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
|
|
@ -0,0 +1,578 @@
|
|||
/*
|
||||
* FCC driver for Motorola MPC82xx (PQ2).
|
||||
*
|
||||
* Copyright (c) 2003 Intracom S.A.
|
||||
* by Pantelis Antoniou <panto@intracom.gr>
|
||||
*
|
||||
* 2005 (c) MontaVista Software, Inc.
|
||||
* Vitaly Bordug <vbordug@ru.mvista.com>
|
||||
*
|
||||
* 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 <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include <asm/immap_cpm2.h>
|
||||
#include <asm/mpc8260.h>
|
||||
#include <asm/cpm2.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#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,
|
||||
};
|
|
@ -0,0 +1,653 @@
|
|||
/*
|
||||
* Freescale Ethernet controllers
|
||||
*
|
||||
* Copyright (c) 2005 Intracom S.A.
|
||||
* by Pantelis Antoniou <panto@intracom.gr>
|
||||
*
|
||||
* 2005 (c) MontaVista Software, Inc.
|
||||
* Vitaly Bordug <vbordug@ru.mvista.com>
|
||||
*
|
||||
* 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 <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#ifdef CONFIG_8xx
|
||||
#include <asm/8xx_immap.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/mpc8xx.h>
|
||||
#include <asm/commproc.h>
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,524 @@
|
|||
/*
|
||||
* Ethernet on Serial Communications Controller (SCC) driver for Motorola MPC8xx and MPC82xx.
|
||||
*
|
||||
* Copyright (c) 2003 Intracom S.A.
|
||||
* by Pantelis Antoniou <panto@intracom.gr>
|
||||
*
|
||||
* 2005 (c) MontaVista Software, Inc.
|
||||
* Vitaly Bordug <vbordug@ru.mvista.com>
|
||||
*
|
||||
* 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 <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#ifdef CONFIG_8xx
|
||||
#include <asm/8xx_immap.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/mpc8xx.h>
|
||||
#include <asm/commproc.h>
|
||||
#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,
|
||||
};
|
|
@ -0,0 +1,405 @@
|
|||
/*
|
||||
* Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
|
||||
*
|
||||
* Copyright (c) 2003 Intracom S.A.
|
||||
* by Pantelis Antoniou <panto@intracom.gr>
|
||||
*
|
||||
* 2005 (c) MontaVista Software, Inc.
|
||||
* Vitaly Bordug <vbordug@ru.mvista.com>
|
||||
*
|
||||
* 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 <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
|
||||
*
|
||||
* Copyright (c) 2003 Intracom S.A.
|
||||
* by Pantelis Antoniou <panto@intracom.gr>
|
||||
*
|
||||
* 2005 (c) MontaVista Software, Inc.
|
||||
* Vitaly Bordug <vbordug@ru.mvista.com>
|
||||
*
|
||||
* 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 <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -390,10 +390,8 @@ static void ax_changedmtu(struct mkiss *ax)
|
|||
"MTU change cancelled.\n",
|
||||
ax->dev->name);
|
||||
dev->mtu = ax->mtu;
|
||||
if (xbuff != NULL)
|
||||
kfree(xbuff);
|
||||
if (rbuff != NULL)
|
||||
kfree(rbuff);
|
||||
kfree(xbuff);
|
||||
kfree(rbuff);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
#
|
||||
# Makefile for the IBM PPC4xx EMAC controllers
|
||||
# Makefile for the PowerPC 4xx on-chip ethernet driver
|
||||
#
|
||||
|
||||
obj-$(CONFIG_IBM_EMAC) += ibm_emac.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
|
||||
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
|
||||
|
|
|
@ -1,110 +1,142 @@
|
|||
/*
|
||||
* ibm_emac.h
|
||||
* drivers/net/ibm_emac/ibm_emac.h
|
||||
*
|
||||
* Register definitions for PowerPC 4xx on-chip ethernet contoller
|
||||
*
|
||||
* Armin Kuster akuster@mvista.com
|
||||
* June, 2002
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Copyright 2002 MontaVista Softare Inc.
|
||||
* Based on original work by
|
||||
* Matt Porter <mporter@kernel.crashing.org>
|
||||
* Armin Kuster <akuster@mvista.com>
|
||||
* Copyright 2002-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.
|
||||
*
|
||||
*/
|
||||
#ifndef __IBM_EMAC_H_
|
||||
#define __IBM_EMAC_H_
|
||||
|
||||
#ifndef _IBM_EMAC_H_
|
||||
#define _IBM_EMAC_H_
|
||||
/* General defines needed for the driver */
|
||||
#include <linux/config.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* 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;
|
||||
/* 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
|
||||
|
||||
/* 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
|
||||
/* 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;
|
||||
};
|
||||
|
||||
/* 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_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
|
||||
|
||||
/* Transmit Mode Register 0 */
|
||||
#define EMAC_TMR0_GNP0 0x80000000
|
||||
#define EMAC_TMR0_GNP1 0x40000000
|
||||
#define EMAC_TMR0_GNPD 0x20000000
|
||||
#define EMAC_TMR0_FC 0x10000000
|
||||
/* 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
|
||||
|
||||
/* 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
|
||||
|
||||
#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
|
||||
|
||||
#define EMAC_TX_FIFO_SIZE 2048
|
||||
|
||||
#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
|
||||
#define EMAC_TMR0_TFAE_2_32 0x00000001
|
||||
#define EMAC_TMR0_TFAE_4_64 0x00000002
|
||||
#define EMAC_TMR0_TFAE_8_128 0x00000003
|
||||
|
@ -112,14 +144,36 @@ typedef 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)
|
||||
|
||||
/* Receive Mode Register */
|
||||
/* 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 */
|
||||
#define EMAC_RMR_SP 0x80000000
|
||||
#define EMAC_RMR_SFCS 0x40000000
|
||||
#define EMAC_RMR_ARRP 0x20000000
|
||||
#define EMAC_RMR_ARP 0x10000000
|
||||
#define EMAC_RMR_AROP 0x08000000
|
||||
#define EMAC_RMR_ARPI 0x04000000
|
||||
#define EMAC_RMR_RRP 0x20000000
|
||||
#define EMAC_RMR_RFP 0x10000000
|
||||
#define EMAC_RMR_ROP 0x08000000
|
||||
#define EMAC_RMR_RPIR 0x04000000
|
||||
#define EMAC_RMR_PPP 0x02000000
|
||||
#define EMAC_RMR_PME 0x01000000
|
||||
#define EMAC_RMR_PMME 0x00800000
|
||||
|
@ -127,6 +181,9 @@ typedef 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
|
||||
|
@ -134,9 +191,21 @@ typedef 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_IAE | EMAC_RMR_BAE)
|
||||
#define EMAC_RMR_BASE EMAC_RMR_RFAF_128_2048
|
||||
#endif
|
||||
|
||||
/* Interrupt Status & enable Regs */
|
||||
/* 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
|
||||
#define EMAC_ISR_OVR 0x02000000
|
||||
#define EMAC_ISR_PP 0x01000000
|
||||
#define EMAC_ISR_BP 0x00800000
|
||||
|
@ -147,53 +216,62 @@ typedef struct emac_regs {
|
|||
#define EMAC_ISR_PTLE 0x00040000
|
||||
#define EMAC_ISR_ORE 0x00020000
|
||||
#define EMAC_ISR_IRE 0x00010000
|
||||
#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_SQE 0x00000080
|
||||
#define EMAC_ISR_TE 0x00000040
|
||||
#define EMAC_ISR_MOS 0x00000002
|
||||
#define EMAC_ISR_MOF 0x00000001
|
||||
|
||||
/* STA CONTROL REG */
|
||||
/* EMACx_STACR */
|
||||
#define EMAC_STACR_PHYD_MASK 0xffff
|
||||
#define EMAC_STACR_PHYD_SHIFT 16
|
||||
#define EMAC_STACR_OC 0x00008000
|
||||
#define EMAC_STACR_PHYE 0x00004000
|
||||
#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
|
||||
#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
|
||||
|
||||
/* 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
|
||||
/* 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)
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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 /* 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 */
|
||||
#define EMAC_TX_CTRL_TAH_CSUM 0x000e
|
||||
|
||||
#define EMAC_TX_CTRL_DFLT ( \
|
||||
MAL_TX_CTRL_INTR | EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP )
|
||||
|
||||
/* madmal transmit status / Control bits */
|
||||
/* EMAC specific TX descriptor status fields (read access) */
|
||||
#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
|
||||
|
@ -202,8 +280,16 @@ typedef 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
|
||||
|
||||
/* madmal receive status / Control bits */
|
||||
/* EMAC specific RX descriptor status fields (read access) */
|
||||
#define EMAC_RX_ST_OE 0x0200
|
||||
#define EMAC_RX_ST_PP 0x0100
|
||||
#define EMAC_RX_ST_BP 0x0080
|
||||
|
@ -214,54 +300,10 @@ typedef struct emac_regs {
|
|||
#define EMAC_RX_ST_PTL 0x0004
|
||||
#define EMAC_RX_ST_ORE 0x0002
|
||||
#define EMAC_RX_ST_IRE 0x0001
|
||||
#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
|
||||
#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_ */
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,146 +1,221 @@
|
|||
/*
|
||||
* ibm_emac_core.h
|
||||
* drivers/net/ibm_emac/ibm_emac_core.h
|
||||
*
|
||||
* Ethernet driver for the built in ethernet on the IBM 405 PowerPC
|
||||
* processor.
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller.
|
||||
*
|
||||
* Armin Kuster akuster@mvista.com
|
||||
* Sept, 2001
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Orignial driver
|
||||
* Johnnie Peters
|
||||
* jpeters@mvista.com
|
||||
*
|
||||
* Copyright 2000 MontaVista Softare Inc.
|
||||
* Based on original work by
|
||||
* Armin Kuster <akuster@mvista.com>
|
||||
* Johnnie Peters <jpeters@mvista.com>
|
||||
* Copyright 2000, 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_CORE_H_
|
||||
#define __IBM_EMAC_CORE_H_
|
||||
|
||||
#ifndef _IBM_EMAC_CORE_H_
|
||||
#define _IBM_EMAC_CORE_H_
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <asm/ocp.h>
|
||||
#include <asm/mmu.h> /* For phys_addr_t */
|
||||
|
||||
#include "ibm_emac.h"
|
||||
#include "ibm_emac_phy.h"
|
||||
#include "ibm_emac_rgmii.h"
|
||||
#include "ibm_emac_zmii.h"
|
||||
#include "ibm_emac_rgmii.h"
|
||||
#include "ibm_emac_mal.h"
|
||||
#include "ibm_emac_tah.h"
|
||||
|
||||
#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
|
||||
#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)
|
||||
#endif
|
||||
|
||||
/* 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.
|
||||
// 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.
|
||||
*/
|
||||
#ifndef CONFIG_IBM_EMAC_SKBRES
|
||||
#define SKB_RES 2
|
||||
#else
|
||||
#define SKB_RES CONFIG_IBM_EMAC_SKBRES
|
||||
#endif
|
||||
|
||||
/* 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 MAX_NUM_BUF_DESC 255
|
||||
#define DESC_BUF_SIZE 4080 /* max 4096-16 */
|
||||
#define DESC_BUF_SIZE_REG (DESC_BUF_SIZE / 16)
|
||||
/* 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;
|
||||
};
|
||||
|
||||
/* Transmitter timeout. */
|
||||
#define TX_TIMEOUT (2*HZ)
|
||||
/* Error statistics */
|
||||
struct ibm_emac_error_stats {
|
||||
u64 tx_undo;
|
||||
|
||||
/* MDIO latency delay */
|
||||
#define MDIO_DELAY 250
|
||||
/* 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;
|
||||
|
||||
/* 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))
|
||||
/* 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 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
|
||||
#define EMAC_ETHTOOL_STATS_COUNT ((sizeof(struct ibm_emac_stats) + \
|
||||
sizeof(struct ibm_emac_error_stats)) \
|
||||
/ sizeof(u64))
|
||||
|
||||
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 net_device *ndev; /* 0 */
|
||||
struct emac_regs *emacp;
|
||||
|
||||
struct mal_descriptor *tx_desc;
|
||||
int tx_cnt;
|
||||
int tx_slot;
|
||||
int ack_slot;
|
||||
|
||||
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 mal_descriptor *rx_desc;
|
||||
int rx_slot;
|
||||
struct sk_buff *rx_sg_skb; /* 1 */
|
||||
int rx_skb_size;
|
||||
int rx_sync_size;
|
||||
|
||||
struct ocp_device *rgmii_dev;
|
||||
int rgmii_input;
|
||||
struct ibm_emac_stats stats;
|
||||
struct ocp_device *tah_dev;
|
||||
|
||||
struct ocp_device *zmii_dev;
|
||||
int zmii_input;
|
||||
struct ibm_ocp_mal *mal;
|
||||
struct mal_commac commac;
|
||||
|
||||
struct ibm_ocp_mal *mal;
|
||||
int mal_tx_chan, mal_rx_chan;
|
||||
struct mal_commac commac;
|
||||
struct sk_buff *tx_skb[NUM_TX_BUFF];
|
||||
struct sk_buff *rx_skb[NUM_RX_BUFF];
|
||||
|
||||
struct ocp_device *tah_dev;
|
||||
struct ocp_device *zmii_dev;
|
||||
int zmii_input;
|
||||
struct ocp_enet_private *mdio_dev;
|
||||
struct ocp_device *rgmii_dev;
|
||||
int rgmii_input;
|
||||
|
||||
int opened;
|
||||
int going_away;
|
||||
int wol_irq;
|
||||
emac_t *emacp;
|
||||
struct ocp_device *ocpdev;
|
||||
struct net_device *ndev;
|
||||
spinlock_t lock;
|
||||
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;
|
||||
};
|
||||
#endif /* _IBM_EMAC_CORE_H_ */
|
||||
|
||||
/* 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
|
||||
*/
|
||||
#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;
|
||||
};
|
||||
|
||||
struct emac_ethtool_regs_subhdr {
|
||||
u32 version;
|
||||
u32 index;
|
||||
};
|
||||
|
||||
#endif /* __IBM_EMAC_CORE_H_ */
|
||||
|
|
|
@ -1,224 +1,213 @@
|
|||
/*
|
||||
* ibm_ocp_debug.c
|
||||
* drivers/net/ibm_emac/ibm_emac_debug.c
|
||||
*
|
||||
* This has all the debug routines that where in *_enet.c
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
|
||||
*
|
||||
* Armin Kuster akuster@mvista.com
|
||||
* April , 2002
|
||||
*
|
||||
* Copyright 2002 MontaVista Softare Inc.
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <asm/io.h>
|
||||
#include "ibm_ocp_mal.h"
|
||||
#include "ibm_ocp_zmii.h"
|
||||
#include "ibm_ocp_enet.h"
|
||||
|
||||
extern int emac_phy_read(struct net_device *dev, int mii_id, int reg);
|
||||
#include "ibm_emac_core.h"
|
||||
|
||||
void emac_phy_dump(struct net_device *dev)
|
||||
static void emac_desc_dump(int idx, struct ocp_enet_private *p)
|
||||
{
|
||||
struct ocp_enet_private *fep = dev->priv;
|
||||
unsigned long i;
|
||||
uint data;
|
||||
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(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;
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
void emac_desc_dump(struct net_device *dev)
|
||||
{
|
||||
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);
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
void emac_mac_dump(struct net_device *dev)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
void emac_mal_dump(struct net_device *dev)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
void emac_serr_dump_0(struct net_device *dev)
|
||||
{
|
||||
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);
|
||||
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");
|
||||
}
|
||||
|
||||
void emac_serr_dump_1(struct net_device *dev)
|
||||
static struct ocp_enet_private *__emacs[4];
|
||||
static struct ibm_ocp_mal *__mals[1];
|
||||
|
||||
void emac_dbg_register(int idx, struct ocp_enet_private *dev)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = ((struct ocp_enet_private *)dev->priv)->mal;
|
||||
int mal_error = get_mal_dcrn(mal, DCRN_MALESR);
|
||||
unsigned long flags;
|
||||
|
||||
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");
|
||||
if (idx >= sizeof(__emacs) / sizeof(__emacs[0])) {
|
||||
printk(KERN_WARNING
|
||||
"invalid index %d when registering EMAC for debugging\n",
|
||||
idx);
|
||||
return;
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
__emacs[idx] = dev;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void emac_err_dump(struct net_device *dev, int em0isr)
|
||||
void mal_dbg_register(int idx, struct ibm_ocp_mal *mal)
|
||||
{
|
||||
printk(KERN_DEBUG "%s: on-chip ethernet error:\n", dev->name);
|
||||
unsigned long flags;
|
||||
|
||||
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");
|
||||
if (idx >= sizeof(__mals) / sizeof(__mals[0])) {
|
||||
printk(KERN_WARNING
|
||||
"invalid index %d when registering MAL for debugging\n",
|
||||
idx);
|
||||
return;
|
||||
}
|
||||
|
||||
emac_mac_dump(dev);
|
||||
emac_mal_dump(dev);
|
||||
local_irq_save(flags);
|
||||
__mals[idx] = mal;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void emac_dbg_dump_all(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MAGIC_SYSRQ)
|
||||
static void emac_sysrq_handler(int key, struct pt_regs *pt_regs,
|
||||
struct tty_struct *tty)
|
||||
{
|
||||
emac_dbg_dump_all();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return register_sysrq_key('c', &emac_sysrq_op);
|
||||
}
|
||||
|
||||
void __exit emac_fini_debug(void)
|
||||
{
|
||||
unregister_sysrq_key('c', &emac_sysrq_op);
|
||||
}
|
||||
|
||||
#else
|
||||
int __init emac_init_debug(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void __exit emac_fini_debug(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_MAGIC_SYSRQ */
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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 <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* 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 <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#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_ */
|
|
@ -1,436 +1,565 @@
|
|||
/*
|
||||
* ibm_ocp_mal.c
|
||||
* drivers/net/ibm_emac/ibm_emac_mal.c
|
||||
*
|
||||
* Armin Kuster akuster@mvista.com
|
||||
* Juen, 2002
|
||||
* Memory Access Layer (MAL) support
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Copyright 2002 MontaVista Softare Inc.
|
||||
* Based on original work by
|
||||
* Benjamin Herrenschmidt <benh@kernel.crashing.org>,
|
||||
* David Gibson <hermes@gibson.dropbear.id.au>,
|
||||
*
|
||||
* Armin Kuster <akuster@mvista.com>
|
||||
* Copyright 2002 MontaVista Softare Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/ocp.h>
|
||||
|
||||
#include "ibm_emac_core.h"
|
||||
#include "ibm_emac_mal.h"
|
||||
#include "ibm_emac_debug.h"
|
||||
|
||||
// Locking: Should we share a lock with the client ? The client could provide
|
||||
// a lock pointer (optionally) in the commac structure... I don't think this is
|
||||
// really necessary though
|
||||
|
||||
/* This lock protects the commac list. On today UP implementations, it's
|
||||
* really only used as IRQ protection in mal_{register,unregister}_commac()
|
||||
*/
|
||||
static DEFINE_RWLOCK(mal_list_lock);
|
||||
|
||||
int mal_register_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac)
|
||||
int __init mal_register_commac(struct ibm_ocp_mal *mal,
|
||||
struct mal_commac *commac)
|
||||
{
|
||||
unsigned long flags;
|
||||
local_irq_save(flags);
|
||||
|
||||
write_lock_irqsave(&mal_list_lock, flags);
|
||||
MAL_DBG("%d: reg(%08x, %08x)" NL, mal->def->index,
|
||||
commac->tx_chan_mask, commac->rx_chan_mask);
|
||||
|
||||
/* Don't let multiple commacs claim the same channel */
|
||||
/* Don't let multiple commacs claim the same channel(s) */
|
||||
if ((mal->tx_chan_mask & commac->tx_chan_mask) ||
|
||||
(mal->rx_chan_mask & commac->rx_chan_mask)) {
|
||||
write_unlock_irqrestore(&mal_list_lock, flags);
|
||||
local_irq_restore(flags);
|
||||
printk(KERN_WARNING "mal%d: COMMAC channels conflict!\n",
|
||||
mal->def->index);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
mal->tx_chan_mask |= commac->tx_chan_mask;
|
||||
mal->rx_chan_mask |= commac->rx_chan_mask;
|
||||
list_add(&commac->list, &mal->list);
|
||||
|
||||
list_add(&commac->list, &mal->commac);
|
||||
|
||||
write_unlock_irqrestore(&mal_list_lock, flags);
|
||||
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mal_unregister_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac)
|
||||
void __exit mal_unregister_commac(struct ibm_ocp_mal *mal,
|
||||
struct mal_commac *commac)
|
||||
{
|
||||
unsigned long flags;
|
||||
local_irq_save(flags);
|
||||
|
||||
write_lock_irqsave(&mal_list_lock, flags);
|
||||
MAL_DBG("%d: unreg(%08x, %08x)" NL, mal->def->index,
|
||||
commac->tx_chan_mask, commac->rx_chan_mask);
|
||||
|
||||
mal->tx_chan_mask &= ~commac->tx_chan_mask;
|
||||
mal->rx_chan_mask &= ~commac->rx_chan_mask;
|
||||
|
||||
list_del_init(&commac->list);
|
||||
|
||||
write_unlock_irqrestore(&mal_list_lock, flags);
|
||||
|
||||
return 0;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, unsigned long size)
|
||||
{
|
||||
switch (channel) {
|
||||
case 0:
|
||||
set_mal_dcrn(mal, DCRN_MALRCBS0, size);
|
||||
break;
|
||||
#ifdef DCRN_MALRCBS1
|
||||
case 1:
|
||||
set_mal_dcrn(mal, DCRN_MALRCBS1, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef DCRN_MALRCBS2
|
||||
case 2:
|
||||
set_mal_dcrn(mal, DCRN_MALRCBS2, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef DCRN_MALRCBS3
|
||||
case 3:
|
||||
set_mal_dcrn(mal, DCRN_MALRCBS3, size);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
static irqreturn_t mal_serr(int irq, void *dev_instance, struct pt_regs *regs)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = dev_instance;
|
||||
unsigned long mal_error;
|
||||
|
||||
/*
|
||||
* This SERR applies to one of the devices on the MAL, here we charge
|
||||
* it against the first EMAC registered for the MAL.
|
||||
*/
|
||||
|
||||
mal_error = get_mal_dcrn(mal, DCRN_MALESR);
|
||||
|
||||
printk(KERN_ERR "%s: System Error (MALESR=%lx)\n",
|
||||
"MAL" /* FIXME: get the name right */ , mal_error);
|
||||
|
||||
/* FIXME: decipher error */
|
||||
/* DIXME: distribute to commacs, if possible */
|
||||
u32 esr = get_mal_dcrn(mal, MAL_ESR);
|
||||
|
||||
/* Clear the error status register */
|
||||
set_mal_dcrn(mal, DCRN_MALESR, mal_error);
|
||||
set_mal_dcrn(mal, MAL_ESR, esr);
|
||||
|
||||
MAL_DBG("%d: SERR %08x" NL, mal->def->index, esr);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
static irqreturn_t mal_txeob(int irq, void *dev_instance, struct pt_regs *regs)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = dev_instance;
|
||||
struct list_head *l;
|
||||
unsigned long isr;
|
||||
|
||||
isr = get_mal_dcrn(mal, DCRN_MALTXEOBISR);
|
||||
set_mal_dcrn(mal, DCRN_MALTXEOBISR, isr);
|
||||
|
||||
read_lock(&mal_list_lock);
|
||||
list_for_each(l, &mal->commac) {
|
||||
struct mal_commac *mc = list_entry(l, struct mal_commac, list);
|
||||
|
||||
if (isr & mc->tx_chan_mask) {
|
||||
mc->ops->txeob(mc->dev, isr & mc->tx_chan_mask);
|
||||
}
|
||||
}
|
||||
read_unlock(&mal_list_lock);
|
||||
|
||||
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;
|
||||
struct list_head *l;
|
||||
unsigned long isr;
|
||||
|
||||
isr = get_mal_dcrn(mal, DCRN_MALRXEOBISR);
|
||||
set_mal_dcrn(mal, DCRN_MALRXEOBISR, isr);
|
||||
|
||||
read_lock(&mal_list_lock);
|
||||
list_for_each(l, &mal->commac) {
|
||||
struct mal_commac *mc = list_entry(l, struct mal_commac, list);
|
||||
|
||||
if (isr & mc->rx_chan_mask) {
|
||||
mc->ops->rxeob(mc->dev, isr & mc->rx_chan_mask);
|
||||
}
|
||||
}
|
||||
read_unlock(&mal_list_lock);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static irqreturn_t mal_txde(int irq, void *dev_instance, struct pt_regs *regs)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = dev_instance;
|
||||
struct list_head *l;
|
||||
unsigned long deir;
|
||||
u32 deir = get_mal_dcrn(mal, MAL_TXDEIR);
|
||||
set_mal_dcrn(mal, MAL_TXDEIR, deir);
|
||||
|
||||
deir = get_mal_dcrn(mal, DCRN_MALTXDEIR);
|
||||
MAL_DBG("%d: txde %08x" NL, mal->def->index, deir);
|
||||
|
||||
/* FIXME: print which MAL correctly */
|
||||
printk(KERN_WARNING "%s: Tx descriptor error (MALTXDEIR=%lx)\n",
|
||||
"MAL", deir);
|
||||
|
||||
read_lock(&mal_list_lock);
|
||||
list_for_each(l, &mal->commac) {
|
||||
struct mal_commac *mc = list_entry(l, struct mal_commac, list);
|
||||
|
||||
if (deir & mc->tx_chan_mask) {
|
||||
mc->ops->txde(mc->dev, deir & mc->tx_chan_mask);
|
||||
}
|
||||
}
|
||||
read_unlock(&mal_list_lock);
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR
|
||||
"mal%d: TX descriptor error (TXDEIR = 0x%08x)\n",
|
||||
mal->def->index, deir);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* This interrupt should be very rare at best. This occurs when
|
||||
* the hardware has a problem with the receive descriptors. The manual
|
||||
* states that it occurs when the hardware cannot the receive descriptor
|
||||
* empty bit is not set. The recovery mechanism will be to
|
||||
* traverse through the descriptors, handle any that are marked to be
|
||||
* handled and reinitialize each along the way. At that point the driver
|
||||
* will be restarted.
|
||||
*/
|
||||
static irqreturn_t mal_rxde(int irq, void *dev_instance, struct pt_regs *regs)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = dev_instance;
|
||||
struct list_head *l;
|
||||
unsigned long deir;
|
||||
u32 deir = get_mal_dcrn(mal, MAL_RXDEIR);
|
||||
|
||||
deir = get_mal_dcrn(mal, DCRN_MALRXDEIR);
|
||||
MAL_DBG("%d: rxde %08x" NL, mal->def->index, deir);
|
||||
|
||||
/*
|
||||
* This really is needed. This case encountered in stress testing.
|
||||
*/
|
||||
if (deir == 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/* FIXME: print which MAL correctly */
|
||||
printk(KERN_WARNING "%s: Rx descriptor error (MALRXDEIR=%lx)\n",
|
||||
"MAL", deir);
|
||||
|
||||
read_lock(&mal_list_lock);
|
||||
list_for_each(l, &mal->commac) {
|
||||
list_for_each(l, &mal->list) {
|
||||
struct mal_commac *mc = list_entry(l, struct mal_commac, list);
|
||||
|
||||
if (deir & mc->rx_chan_mask) {
|
||||
mc->ops->rxde(mc->dev, deir & mc->rx_chan_mask);
|
||||
mc->rx_stopped = 1;
|
||||
mc->ops->rxde(mc->dev);
|
||||
}
|
||||
}
|
||||
read_unlock(&mal_list_lock);
|
||||
|
||||
mal_schedule_poll(mal);
|
||||
set_mal_dcrn(mal, MAL_RXDEIR, deir);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mal_poll(struct net_device *ndev, int *budget)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = ndev->priv;
|
||||
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);
|
||||
|
||||
set_mal_dcrn(mal, MAL_CFG, MAL_CFG_SR);
|
||||
|
||||
/* Wait for reset to complete (1 system clock) */
|
||||
while ((get_mal_dcrn(mal, MAL_CFG) & MAL_CFG_SR) && n)
|
||||
--n;
|
||||
|
||||
if (unlikely(!n))
|
||||
printk(KERN_ERR "mal%d: reset timeout\n", mal->def->index);
|
||||
}
|
||||
|
||||
int mal_get_regs_len(struct ibm_ocp_mal *mal)
|
||||
{
|
||||
return sizeof(struct emac_ethtool_regs_subhdr) +
|
||||
sizeof(struct ibm_mal_regs);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
return regs + 1;
|
||||
}
|
||||
|
||||
static int __init mal_probe(struct ocp_device *ocpdev)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = NULL;
|
||||
struct ibm_ocp_mal *mal;
|
||||
struct ocp_func_mal_data *maldata;
|
||||
int err = 0;
|
||||
int err = 0, i, bd_size;
|
||||
|
||||
maldata = (struct ocp_func_mal_data *)ocpdev->def->additions;
|
||||
MAL_DBG("%d: probe" NL, ocpdev->def->index);
|
||||
|
||||
maldata = ocpdev->def->additions;
|
||||
if (maldata == NULL) {
|
||||
printk(KERN_ERR "mal%d: Missing additional datas !\n",
|
||||
printk(KERN_ERR "mal%d: missing additional data!\n",
|
||||
ocpdev->def->index);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mal = kmalloc(sizeof(struct ibm_ocp_mal), GFP_KERNEL);
|
||||
if (mal == NULL) {
|
||||
mal = kzalloc(sizeof(struct ibm_ocp_mal), GFP_KERNEL);
|
||||
if (!mal) {
|
||||
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;
|
||||
}
|
||||
memset(mal, 0, sizeof(*mal));
|
||||
mal->dcrbase = maldata->dcr_base;
|
||||
mal->def = ocpdev->def;
|
||||
|
||||
switch (ocpdev->def->index) {
|
||||
case 0:
|
||||
mal->dcrbase = DCRN_MAL_BASE;
|
||||
break;
|
||||
#ifdef DCRN_MAL1_BASE
|
||||
case 1:
|
||||
mal->dcrbase = DCRN_MAL1_BASE;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
INIT_LIST_HEAD(&mal->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);
|
||||
|
||||
INIT_LIST_HEAD(&mal->commac);
|
||||
|
||||
set_mal_dcrn(mal, DCRN_MALRXCARR, 0xFFFFFFFF);
|
||||
set_mal_dcrn(mal, DCRN_MALTXCARR, 0xFFFFFFFF);
|
||||
|
||||
set_mal_dcrn(mal, DCRN_MALCR, MALCR_MMSR); /* 384 */
|
||||
/* FIXME: Add delay */
|
||||
/* Load power-on reset defaults */
|
||||
mal_reset(mal);
|
||||
|
||||
/* Set the MAL configuration register */
|
||||
set_mal_dcrn(mal, DCRN_MALCR,
|
||||
MALCR_PLBB | MALCR_OPBBL | MALCR_LEA |
|
||||
MALCR_PLBLT_DEFAULT);
|
||||
set_mal_dcrn(mal, MAL_CFG, MAL_CFG_DEFAULT | MAL_CFG_PLBB |
|
||||
MAL_CFG_OPBBL | MAL_CFG_LEA);
|
||||
|
||||
/* 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) {
|
||||
mal_enable_eob_irq(mal);
|
||||
|
||||
/* 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);
|
||||
|
||||
if (!mal->bd_virt) {
|
||||
printk(KERN_ERR
|
||||
"mal%d: Out of memory allocating MAL descriptors !\n",
|
||||
ocpdev->def->index);
|
||||
"mal%d: out of memory allocating RX/TX descriptors!\n",
|
||||
mal->def->index);
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
memset(mal->bd_virt, 0, bd_size);
|
||||
|
||||
/* 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 */
|
||||
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));
|
||||
|
||||
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 */
|
||||
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));
|
||||
|
||||
err = request_irq(maldata->serr_irq, mal_serr, 0, "MAL SERR", mal);
|
||||
if (err)
|
||||
goto fail;
|
||||
err = request_irq(maldata->txde_irq, mal_txde, 0, "MAL TX DE ", mal);
|
||||
goto fail2;
|
||||
err = request_irq(maldata->txde_irq, mal_txde, 0, "MAL TX DE", mal);
|
||||
if (err)
|
||||
goto fail;
|
||||
goto fail3;
|
||||
err = request_irq(maldata->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal);
|
||||
if (err)
|
||||
goto fail;
|
||||
goto fail4;
|
||||
err = request_irq(maldata->rxde_irq, mal_rxde, 0, "MAL RX DE", mal);
|
||||
if (err)
|
||||
goto fail;
|
||||
goto fail5;
|
||||
err = request_irq(maldata->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal);
|
||||
if (err)
|
||||
goto fail;
|
||||
goto fail6;
|
||||
|
||||
set_mal_dcrn(mal, DCRN_MALIER,
|
||||
MALIER_DE | MALIER_NE | MALIER_TE |
|
||||
MALIER_OPBE | MALIER_PLBE);
|
||||
/* Enable all MAL SERR interrupt sources */
|
||||
set_mal_dcrn(mal, MAL_IER, MAL_IER_EVENTS);
|
||||
|
||||
/* Advertise me to the rest of the world */
|
||||
/* Advertise this instance to the rest of the world */
|
||||
ocp_set_drvdata(ocpdev, mal);
|
||||
|
||||
printk(KERN_INFO "mal%d: Initialized, %d tx channels, %d rx channels\n",
|
||||
ocpdev->def->index, maldata->num_tx_chans,
|
||||
maldata->num_rx_chans);
|
||||
mal_dbg_register(mal->def->index, mal);
|
||||
|
||||
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:
|
||||
/* FIXME: dispose requested IRQs ! */
|
||||
if (err && mal)
|
||||
kfree(mal);
|
||||
kfree(mal);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit mal_remove(struct ocp_device *ocpdev)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = ocp_get_drvdata(ocpdev);
|
||||
struct ocp_func_mal_data *maldata = ocpdev->def->additions;
|
||||
struct ocp_func_mal_data *maldata = mal->def->additions;
|
||||
|
||||
BUG_ON(!maldata);
|
||||
MAL_DBG("%d: remove" NL, mal->def->index);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
ocp_set_drvdata(ocpdev, NULL);
|
||||
|
||||
/* FIXME: shut down the MAL, deal with dependency with emac */
|
||||
free_irq(maldata->serr_irq, mal);
|
||||
free_irq(maldata->txde_irq, mal);
|
||||
free_irq(maldata->txeob_irq, mal);
|
||||
free_irq(maldata->rxde_irq, mal);
|
||||
free_irq(maldata->rxeob_irq, mal);
|
||||
|
||||
if (mal->tx_virt_addr)
|
||||
dma_free_coherent(&ocpdev->dev,
|
||||
MAL_DT_ALIGN * maldata->num_tx_chans,
|
||||
mal->tx_virt_addr, mal->tx_phys_addr);
|
||||
mal_reset(mal);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
kfree(mal);
|
||||
}
|
||||
|
||||
/* Structure for a device driver */
|
||||
static struct ocp_device_id mal_ids[] = {
|
||||
{.vendor = OCP_ANY_ID,.function = OCP_FUNC_MAL},
|
||||
{.vendor = OCP_VENDOR_INVALID}
|
||||
{ .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_MAL },
|
||||
{ .vendor = OCP_VENDOR_INVALID}
|
||||
};
|
||||
|
||||
static struct ocp_driver mal_driver = {
|
||||
|
@ -441,23 +570,14 @@ static struct ocp_driver mal_driver = {
|
|||
.remove = mal_remove,
|
||||
};
|
||||
|
||||
static int __init init_mals(void)
|
||||
int __init mal_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ocp_register_driver(&mal_driver);
|
||||
if (rc < 0) {
|
||||
ocp_unregister_driver(&mal_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
MAL_DBG(": init" NL);
|
||||
return ocp_register_driver(&mal_driver);
|
||||
}
|
||||
|
||||
static void __exit exit_mals(void)
|
||||
void __exit mal_exit(void)
|
||||
{
|
||||
MAL_DBG(": exit" NL);
|
||||
ocp_unregister_driver(&mal_driver);
|
||||
}
|
||||
|
||||
module_init(init_mals);
|
||||
module_exit(exit_mals);
|
||||
|
|
|
@ -1,131 +1,267 @@
|
|||
#ifndef _IBM_EMAC_MAL_H
|
||||
#define _IBM_EMAC_MAL_H
|
||||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac_mal.h
|
||||
*
|
||||
* Memory Access Layer (MAL) support
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Based on original work by
|
||||
* Armin Kuster <akuster@mvista.com>
|
||||
* 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_
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#define MAL_DT_ALIGN (4096) /* Alignment for each channel's descriptor table */
|
||||
#include <asm/io.h>
|
||||
|
||||
#define MAL_CHAN_MASK(chan) (0x80000000 >> (chan))
|
||||
/*
|
||||
* 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))
|
||||
|
||||
/* MAL Buffer Descriptor structure */
|
||||
struct mal_descriptor {
|
||||
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));
|
||||
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 */
|
||||
};
|
||||
|
||||
/* 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_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_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 (*txeob) (void *dev, u32 chanmask);
|
||||
void (*txde) (void *dev, u32 chanmask);
|
||||
void (*rxeob) (void *dev, u32 chanmask);
|
||||
void (*rxde) (void *dev, u32 chanmask);
|
||||
void (*poll_tx) (void *dev);
|
||||
int (*poll_rx) (void *dev, int budget);
|
||||
int (*peek_rx) (void *dev);
|
||||
void (*rxde) (void *dev);
|
||||
};
|
||||
|
||||
struct mal_commac {
|
||||
struct mal_commac_ops *ops;
|
||||
void *dev;
|
||||
u32 tx_chan_mask, rx_chan_mask;
|
||||
struct list_head list;
|
||||
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 ibm_ocp_mal {
|
||||
int dcrbase;
|
||||
int dcrbase;
|
||||
|
||||
struct list_head commac;
|
||||
u32 tx_chan_mask, rx_chan_mask;
|
||||
struct list_head poll_list;
|
||||
struct net_device poll_dev;
|
||||
|
||||
dma_addr_t tx_phys_addr;
|
||||
struct mal_descriptor *tx_virt_addr;
|
||||
struct list_head list;
|
||||
u32 tx_chan_mask;
|
||||
u32 rx_chan_mask;
|
||||
|
||||
dma_addr_t rx_phys_addr;
|
||||
struct mal_descriptor *rx_virt_addr;
|
||||
dma_addr_t bd_dma;
|
||||
struct mal_descriptor *bd_virt;
|
||||
|
||||
struct ocp_def *def;
|
||||
};
|
||||
|
||||
#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)
|
||||
static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg)
|
||||
{
|
||||
set_mal_dcrn(mal, DCRN_MALTXCASR,
|
||||
get_mal_dcrn(mal, DCRN_MALTXCASR) | chanmask);
|
||||
return mfdcr(mal->dcrbase + reg);
|
||||
}
|
||||
|
||||
static inline void mal_disable_tx_channels(struct ibm_ocp_mal *mal,
|
||||
u32 chanmask)
|
||||
static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val)
|
||||
{
|
||||
set_mal_dcrn(mal, DCRN_MALTXCARR, chanmask);
|
||||
mtdcr(mal->dcrbase + reg, val);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
/* Register MAL devices */
|
||||
int mal_init(void) __init;
|
||||
void mal_exit(void) __exit;
|
||||
|
||||
static inline void mal_disable_rx_channels(struct ibm_ocp_mal *mal,
|
||||
u32 chanmask)
|
||||
{
|
||||
set_mal_dcrn(mal, DCRN_MALRXCARR, chanmask);
|
||||
}
|
||||
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);
|
||||
|
||||
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);
|
||||
/* 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);
|
||||
|
||||
extern int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel,
|
||||
unsigned long size);
|
||||
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);
|
||||
|
||||
#endif /* _IBM_EMAC_MAL_H */
|
||||
/* 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);
|
||||
|
||||
/* Ethtool MAL registers */
|
||||
struct ibm_mal_regs {
|
||||
u32 tx_count;
|
||||
u32 rx_count;
|
||||
|
||||
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];
|
||||
};
|
||||
|
||||
int mal_get_regs_len(struct ibm_ocp_mal *mal);
|
||||
void *mal_dump_regs(struct ibm_ocp_mal *mal, void *buf);
|
||||
|
||||
#endif /* __IBM_EMAC_MAL_H_ */
|
||||
|
|
|
@ -1,61 +1,256 @@
|
|||
/*
|
||||
* ibm_ocp_phy.c
|
||||
* drivers/net/ibm_emac/ibm_emac_phy.c
|
||||
*
|
||||
* PHY drivers for the ibm ocp ethernet driver. Borrowed
|
||||
* from sungem_phy.c, though I only kept the generic MII
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, PHY support.
|
||||
* 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 <ebs@ebshome.net>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <asm/ocp.h>
|
||||
|
||||
#include "ibm_emac_phy.h"
|
||||
|
||||
static int reset_one_mii_phy(struct mii_phy *phy, int phy_id)
|
||||
static inline int phy_read(struct mii_phy *phy, int reg)
|
||||
{
|
||||
u16 val;
|
||||
return phy->mdio_read(phy->dev, phy->address, reg);
|
||||
}
|
||||
|
||||
static inline void phy_write(struct mii_phy *phy, int reg, int val)
|
||||
{
|
||||
phy->mdio_write(phy->dev, phy->address, reg, val);
|
||||
}
|
||||
|
||||
int mii_reset_phy(struct mii_phy *phy)
|
||||
{
|
||||
int val;
|
||||
int limit = 10000;
|
||||
|
||||
val = __phy_read(phy, phy_id, MII_BMCR);
|
||||
val = phy_read(phy, MII_BMCR);
|
||||
val &= ~BMCR_ISOLATE;
|
||||
val |= BMCR_RESET;
|
||||
__phy_write(phy, phy_id, MII_BMCR, val);
|
||||
phy_write(phy, MII_BMCR, val);
|
||||
|
||||
udelay(100);
|
||||
udelay(300);
|
||||
|
||||
while (limit--) {
|
||||
val = __phy_read(phy, phy_id, MII_BMCR);
|
||||
if ((val & BMCR_RESET) == 0)
|
||||
val = phy_read(phy, MII_BMCR);
|
||||
if (val >= 0 && (val & BMCR_RESET) == 0)
|
||||
break;
|
||||
udelay(10);
|
||||
}
|
||||
if ((val & BMCR_ISOLATE) && limit > 0)
|
||||
__phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
|
||||
phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
|
||||
|
||||
return (limit <= 0);
|
||||
return limit <= 0;
|
||||
}
|
||||
|
||||
static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
|
||||
{
|
||||
int ctl, adv;
|
||||
|
||||
phy->autoneg = AUTONEG_ENABLE;
|
||||
phy->speed = SPEED_10;
|
||||
phy->duplex = DUPLEX_HALF;
|
||||
phy->pause = phy->asym_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);
|
||||
if (advertise & ADVERTISED_10baseT_Half)
|
||||
adv |= ADVERTISE_10HALF;
|
||||
if (advertise & ADVERTISED_10baseT_Full)
|
||||
adv |= ADVERTISE_10FULL;
|
||||
if (advertise & ADVERTISED_100baseT_Half)
|
||||
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);
|
||||
phy_write(phy, MII_BMCR, ctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
|
||||
{
|
||||
int ctl;
|
||||
|
||||
phy->autoneg = AUTONEG_DISABLE;
|
||||
phy->speed = speed;
|
||||
phy->duplex = fd;
|
||||
phy->pause = phy->asym_pause = 0;
|
||||
|
||||
ctl = phy_read(phy, MII_BMCR);
|
||||
if (ctl < 0)
|
||||
return ctl;
|
||||
ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE);
|
||||
|
||||
/* First reset the PHY */
|
||||
phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
|
||||
|
||||
/* Select speed & duplex */
|
||||
switch (speed) {
|
||||
case SPEED_10:
|
||||
break;
|
||||
case SPEED_100:
|
||||
ctl |= BMCR_SPEED100;
|
||||
break;
|
||||
case SPEED_1000:
|
||||
ctl |= BMCR_SPEED1000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (fd == DUPLEX_FULL)
|
||||
ctl |= BMCR_FULLDPLX;
|
||||
phy_write(phy, MII_BMCR, ctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int genmii_poll_link(struct mii_phy *phy)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* Clear latched value with dummy read */
|
||||
phy_read(phy, MII_BMSR);
|
||||
status = phy_read(phy, MII_BMSR);
|
||||
if (status < 0 || (status & BMSR_LSTATUS) == 0)
|
||||
return 0;
|
||||
if (phy->autoneg == AUTONEG_ENABLE && !(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;
|
||||
|
||||
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;
|
||||
|
||||
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 (bmcr & BMCR_FULLDPLX)
|
||||
phy->duplex = DUPLEX_FULL;
|
||||
else
|
||||
phy->duplex = DUPLEX_HALF;
|
||||
if (bmcr & BMCR_SPEED1000)
|
||||
phy->speed = SPEED_1000;
|
||||
else if (bmcr & BMCR_SPEED100)
|
||||
phy->speed = SPEED_100;
|
||||
else
|
||||
phy->speed = SPEED_10;
|
||||
|
||||
phy->pause = phy->asym_pause = 0;
|
||||
}
|
||||
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)
|
||||
{
|
||||
u16 epcr;
|
||||
int epcr;
|
||||
|
||||
epcr = phy_read(phy, MII_CIS8201_EPCR);
|
||||
if (epcr < 0)
|
||||
return epcr;
|
||||
|
||||
epcr &= ~EPCR_MODE_MASK;
|
||||
|
||||
switch (phy->mode) {
|
||||
|
@ -78,178 +273,19 @@ static int cis8201_init(struct mii_phy *phy)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
|
||||
{
|
||||
u16 ctl, adv;
|
||||
|
||||
phy->autoneg = 1;
|
||||
phy->speed = SPEED_10;
|
||||
phy->duplex = DUPLEX_HALF;
|
||||
phy->pause = 0;
|
||||
phy->advertising = advertise;
|
||||
|
||||
/* Setup standard advertise */
|
||||
adv = phy_read(phy, MII_ADVERTISE);
|
||||
adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
|
||||
if (advertise & ADVERTISED_10baseT_Half)
|
||||
adv |= ADVERTISE_10HALF;
|
||||
if (advertise & ADVERTISED_10baseT_Full)
|
||||
adv |= ADVERTISE_10FULL;
|
||||
if (advertise & ADVERTISED_100baseT_Half)
|
||||
adv |= ADVERTISE_100HALF;
|
||||
if (advertise & ADVERTISED_100baseT_Full)
|
||||
adv |= ADVERTISE_100FULL;
|
||||
phy_write(phy, MII_ADVERTISE, adv);
|
||||
|
||||
/* Start/Restart aneg */
|
||||
ctl = phy_read(phy, MII_BMCR);
|
||||
ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
|
||||
phy_write(phy, MII_BMCR, ctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
|
||||
{
|
||||
u16 ctl;
|
||||
|
||||
phy->autoneg = 0;
|
||||
phy->speed = speed;
|
||||
phy->duplex = fd;
|
||||
phy->pause = 0;
|
||||
|
||||
ctl = phy_read(phy, MII_BMCR);
|
||||
ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE);
|
||||
|
||||
/* First reset the PHY */
|
||||
phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
|
||||
|
||||
/* Select speed & duplex */
|
||||
switch (speed) {
|
||||
case SPEED_10:
|
||||
break;
|
||||
case SPEED_100:
|
||||
ctl |= BMCR_SPEED100;
|
||||
break;
|
||||
case SPEED_1000:
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (fd == DUPLEX_FULL)
|
||||
ctl |= BMCR_FULLDPLX;
|
||||
phy_write(phy, MII_BMCR, ctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int genmii_poll_link(struct mii_phy *phy)
|
||||
{
|
||||
u16 status;
|
||||
|
||||
(void)phy_read(phy, MII_BMSR);
|
||||
status = phy_read(phy, MII_BMSR);
|
||||
if ((status & BMSR_LSTATUS) == 0)
|
||||
return 0;
|
||||
if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define MII_CIS8201_ACSR 0x1c
|
||||
#define ACSR_DUPLEX_STATUS 0x0020
|
||||
#define ACSR_SPEED_1000BASET 0x0010
|
||||
#define ACSR_SPEED_100BASET 0x0008
|
||||
|
||||
static int cis8201_read_link(struct mii_phy *phy)
|
||||
{
|
||||
u16 acsr;
|
||||
|
||||
if (phy->autoneg) {
|
||||
acsr = phy_read(phy, MII_CIS8201_ACSR);
|
||||
|
||||
if (acsr & ACSR_DUPLEX_STATUS)
|
||||
phy->duplex = DUPLEX_FULL;
|
||||
else
|
||||
phy->duplex = DUPLEX_HALF;
|
||||
if (acsr & ACSR_SPEED_1000BASET) {
|
||||
phy->speed = SPEED_1000;
|
||||
} else if (acsr & ACSR_SPEED_100BASET)
|
||||
phy->speed = SPEED_100;
|
||||
else
|
||||
phy->speed = SPEED_10;
|
||||
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;
|
||||
}
|
||||
|
||||
static int genmii_read_link(struct mii_phy *phy)
|
||||
{
|
||||
u16 lpa;
|
||||
|
||||
if (phy->autoneg) {
|
||||
lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE);
|
||||
|
||||
phy->speed = SPEED_10;
|
||||
phy->duplex = DUPLEX_HALF;
|
||||
phy->pause = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
/* 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: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
|
||||
.init = cis8201_init,
|
||||
.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",
|
||||
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
|
||||
.phy_id = 0x000fc410,
|
||||
.phy_id_mask = 0x000ffff0,
|
||||
.name = "CIS8201 Gigabit Ethernet",
|
||||
.ops = &cis8201_phy_ops
|
||||
};
|
||||
|
||||
static struct mii_phy_def *mii_phy_table[] = {
|
||||
|
@ -258,39 +294,60 @@ static struct mii_phy_def *mii_phy_table[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
int mii_phy_probe(struct mii_phy *phy, int mii_id)
|
||||
int mii_phy_probe(struct mii_phy *phy, int address)
|
||||
{
|
||||
int rc;
|
||||
u32 id;
|
||||
struct mii_phy_def *def;
|
||||
int i;
|
||||
u32 id;
|
||||
|
||||
phy->autoneg = 0;
|
||||
phy->autoneg = AUTONEG_DISABLE;
|
||||
phy->advertising = 0;
|
||||
phy->mii_id = mii_id;
|
||||
phy->speed = 0;
|
||||
phy->duplex = 0;
|
||||
phy->pause = 0;
|
||||
phy->address = address;
|
||||
phy->speed = SPEED_10;
|
||||
phy->duplex = DUPLEX_HALF;
|
||||
phy->pause = phy->asym_pause = 0;
|
||||
|
||||
/* Take PHY out of isloate mode and reset it. */
|
||||
rc = reset_one_mii_phy(phy, mii_id);
|
||||
if (rc)
|
||||
/* Take PHY out of isolate mode and reset it. */
|
||||
if (mii_reset_phy(phy))
|
||||
return -ENODEV;
|
||||
|
||||
/* Read ID and find matching entry */
|
||||
id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2))
|
||||
& 0xfffffff0;
|
||||
id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2);
|
||||
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 == NULL)
|
||||
if (!def)
|
||||
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 = def->features;
|
||||
phy->advertising = phy->features;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,65 +1,25 @@
|
|||
|
||||
/*
|
||||
* ibm_emac_phy.h
|
||||
* drivers/net/ibm_emac/ibm_emac_phy.h
|
||||
*
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, PHY support
|
||||
*
|
||||
* Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
* February 2003
|
||||
* Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
* February 2003
|
||||
*
|
||||
* Minor additions by Eugene Surovegin <ebs@ebshome.net>, 2004
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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 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_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
|
||||
#ifndef _IBM_OCP_PHY_H_
|
||||
#define _IBM_OCP_PHY_H_
|
||||
|
||||
struct mii_phy;
|
||||
|
||||
|
@ -77,7 +37,8 @@ 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 */
|
||||
u32 features; /* Ethtool SUPPORTED_* defines or
|
||||
0 for autodetect */
|
||||
int magic_aneg; /* Autoneg does all speed test for us */
|
||||
const char *name;
|
||||
const struct mii_phy_ops *ops;
|
||||
|
@ -86,8 +47,11 @@ struct mii_phy_def {
|
|||
/* An instance of a PHY, partially borrowed from mii_if_info */
|
||||
struct mii_phy {
|
||||
struct mii_phy_def *def;
|
||||
int advertising;
|
||||
int mii_id;
|
||||
u32 advertising; /* Ethtool ADVERTISED_* defines */
|
||||
u32 features; /* Copied from mii_phy_def.features
|
||||
or determined automaticaly */
|
||||
int address; /* PHY address */
|
||||
int mode; /* PHY mode */
|
||||
|
||||
/* 1: autoneg enabled, 0: disabled */
|
||||
int autoneg;
|
||||
|
@ -98,40 +62,19 @@ struct mii_phy {
|
|||
int speed;
|
||||
int duplex;
|
||||
int pause;
|
||||
|
||||
/* PHY mode - if needed */
|
||||
int mode;
|
||||
int asym_pause;
|
||||
|
||||
/* Provided by host chip */
|
||||
struct net_device *dev;
|
||||
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 (*mdio_read) (struct net_device * dev, int addr, int reg);
|
||||
void (*mdio_write) (struct net_device * dev, int addr, 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
|
||||
*/
|
||||
extern int mii_phy_probe(struct mii_phy *phy, int mii_id);
|
||||
int mii_phy_probe(struct mii_phy *phy, int address);
|
||||
int mii_reset_phy(struct mii_phy *phy);
|
||||
|
||||
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_EMAC_PHY_H_ */
|
||||
#endif /* _IBM_OCP_PHY_H_ */
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* 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 <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Based on original work by
|
||||
* Matt Porter <mporter@kernel.crashing.org>
|
||||
* 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 <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
/*
|
||||
* Defines for the IBM RGMII bridge
|
||||
* drivers/net/ibm_emac/ibm_emac_rgmii.c
|
||||
*
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
|
||||
*
|
||||
* Based on ocp_zmii.h/ibm_emac_zmii.h
|
||||
* Armin Kuster akuster@mvista.com
|
||||
|
@ -7,6 +9,9 @@
|
|||
* Copyright 2004 MontaVista Software, Inc.
|
||||
* Matt Porter <mporter@kernel.crashing.org>
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* 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
|
||||
|
@ -19,47 +24,42 @@
|
|||
#include <linux/config.h>
|
||||
|
||||
/* RGMII bridge */
|
||||
typedef struct rgmii_regs {
|
||||
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 */
|
||||
};
|
||||
|
||||
/* 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
|
||||
#ifdef CONFIG_IBM_EMAC_RGMII
|
||||
int rgmii_attach(void *emac) __init;
|
||||
|
||||
/* 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)
|
||||
|
||||
#define RTBI 0
|
||||
#define RGMII 1
|
||||
#define TBI 2
|
||||
#define GMII 3
|
||||
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 */
|
||||
|
||||
#endif /* _IBM_EMAC_RGMII_H_ */
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* 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 <mporter@kernel.crashing.org>
|
||||
*
|
||||
* Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
#include <linux/config.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -1,9 +1,13 @@
|
|||
/*
|
||||
* Defines for the IBM TAH
|
||||
* drivers/net/ibm_emac/ibm_emac_tah.h
|
||||
*
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, TAH support.
|
||||
*
|
||||
* Copyright 2004 MontaVista Software, Inc.
|
||||
* Matt Porter <mporter@kernel.crashing.org>
|
||||
*
|
||||
* Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net>
|
||||
*
|
||||
* 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
|
||||
|
@ -13,36 +17,72 @@
|
|||
#ifndef _IBM_EMAC_TAH_H
|
||||
#define _IBM_EMAC_TAH_H
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/ocp.h>
|
||||
|
||||
/* TAH */
|
||||
typedef struct tah_regs {
|
||||
u32 tah_revid;
|
||||
struct tah_regs {
|
||||
u32 revid;
|
||||
u32 pad[3];
|
||||
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;
|
||||
u32 mr;
|
||||
u32 ssr0;
|
||||
u32 ssr1;
|
||||
u32 ssr2;
|
||||
u32 ssr3;
|
||||
u32 ssr4;
|
||||
u32 ssr5;
|
||||
u32 tsr;
|
||||
};
|
||||
|
||||
/* 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
|
||||
#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 */
|
||||
|
||||
#endif /* _IBM_EMAC_TAH_H */
|
||||
|
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* 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 <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Based on original work by
|
||||
* Armin Kuster <akuster@mvista.com>
|
||||
* 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 <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -1,23 +1,27 @@
|
|||
/*
|
||||
* ocp_zmii.h
|
||||
* drivers/net/ibm_emac/ibm_emac_zmii.h
|
||||
*
|
||||
* Defines for the IBM ZMII bridge
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support.
|
||||
*
|
||||
* Armin Kuster akuster@mvista.com
|
||||
* Dec, 2001
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Copyright 2001 MontaVista Softare Inc.
|
||||
* Based on original work by
|
||||
* Armin Kuster <akuster@mvista.com>
|
||||
* 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 <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/ocp.h>
|
||||
|
||||
/* ZMII bridge registers */
|
||||
struct zmii_regs {
|
||||
|
@ -26,68 +30,54 @@ struct zmii_regs {
|
|||
u32 smiirs; /* SMII status reg */
|
||||
};
|
||||
|
||||
#define ZMII_INPUTS 4
|
||||
|
||||
/* ZMII device */
|
||||
struct ibm_ocp_zmii {
|
||||
struct zmii_regs *base;
|
||||
int mode[ZMII_INPUTS];
|
||||
int mode; /* subset of PHY_MODE_XXXX */
|
||||
int users; /* number of EMACs using this ZMII bridge */
|
||||
u32 fer_save; /* FER value left by firmware */
|
||||
};
|
||||
|
||||
/* Fuctional Enable Reg */
|
||||
#ifdef CONFIG_IBM_EMAC_ZMII
|
||||
int zmii_attach(void *emac) __init;
|
||||
|
||||
#define ZMII_FER_MASK(x) (0xf0000000 >> (4*x))
|
||||
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);
|
||||
}
|
||||
|
||||
#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_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);
|
||||
}
|
||||
|
||||
/* Speed Selection reg */
|
||||
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_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
|
||||
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;
|
||||
}
|
||||
|
||||
#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
|
||||
void *zmii_dump_regs(struct ocp_device *ocpdev, void *buf);
|
||||
|
||||
/* SMII Status reg */
|
||||
|
||||
#define ZMII_STS0 0xFF000000 /* EMAC0 smii status mask */
|
||||
#define ZMII_STS1 0x00FF0000 /* EMAC1 smii status mask */
|
||||
|
||||
#define SMII 0
|
||||
#define RMII 1
|
||||
#define MII 2
|
||||
#define MDI 3
|
||||
#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 */
|
||||
|
||||
#endif /* _IBM_EMAC_ZMII_H_ */
|
||||
|
|
|
@ -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_schedule_replenishing(struct ibmveth_adapter*);
|
||||
static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#define IBMVETH_PROC_DIR "net/ibmveth"
|
||||
|
@ -181,6 +181,7 @@ 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;
|
||||
}
|
||||
|
@ -236,7 +237,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] = IBM_VETH_INVALID_MAP;
|
||||
pool->free_map[free_index] = index;
|
||||
pool->skbuff[index] = NULL;
|
||||
pool->consumer_index--;
|
||||
dma_unmap_single(&adapter->vdev->dev,
|
||||
|
@ -255,37 +256,19 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc
|
|||
atomic_add(buffers_added, &(pool->available));
|
||||
}
|
||||
|
||||
/* check if replenishing is needed. */
|
||||
static inline int ibmveth_is_replenishing_needed(struct ibmveth_adapter *adapter)
|
||||
{
|
||||
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 */
|
||||
/* replenish routine */
|
||||
static void ibmveth_replenish_task(struct ibmveth_adapter *adapter)
|
||||
{
|
||||
int i;
|
||||
|
||||
adapter->replenish_task_cycles++;
|
||||
|
||||
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]);
|
||||
for(i = 0; i < IbmVethNumBufferPools; i++)
|
||||
if(adapter->rx_buff_pool[i].active)
|
||||
ibmveth_replenish_buffer_pool(adapter,
|
||||
&adapter->rx_buff_pool[i]);
|
||||
|
||||
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 */
|
||||
|
@ -293,10 +276,8 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibm
|
|||
{
|
||||
int i;
|
||||
|
||||
if(pool->free_map) {
|
||||
kfree(pool->free_map);
|
||||
pool->free_map = NULL;
|
||||
}
|
||||
kfree(pool->free_map);
|
||||
pool->free_map = NULL;
|
||||
|
||||
if(pool->skbuff && pool->dma_addr) {
|
||||
for(i = 0; i < pool->size; ++i) {
|
||||
|
@ -321,6 +302,7 @@ 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 */
|
||||
|
@ -379,6 +361,12 @@ 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;
|
||||
|
@ -409,6 +397,8 @@ 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,
|
||||
|
@ -443,26 +433,24 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
|
|||
adapter->rx_queue.queue_addr = NULL;
|
||||
}
|
||||
|
||||
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]);
|
||||
for(i = 0; i<IbmVethNumBufferPools; i++)
|
||||
ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[i]);
|
||||
}
|
||||
|
||||
static int ibmveth_open(struct net_device *netdev)
|
||||
{
|
||||
struct ibmveth_adapter *adapter = netdev->priv;
|
||||
u64 mac_address = 0;
|
||||
int rxq_entries;
|
||||
int rxq_entries = 1;
|
||||
unsigned long lpar_rc;
|
||||
int rc;
|
||||
union ibmveth_buf_desc rxq_desc;
|
||||
int i;
|
||||
|
||||
ibmveth_debug_printk("open starting\n");
|
||||
|
||||
rxq_entries =
|
||||
adapter->rx_buff_pool[0].size +
|
||||
adapter->rx_buff_pool[1].size +
|
||||
adapter->rx_buff_pool[2].size + 1;
|
||||
for(i = 0; i<IbmVethNumBufferPools; i++)
|
||||
rxq_entries += adapter->rx_buff_pool[i].size;
|
||||
|
||||
adapter->buffer_list_addr = (void*) get_zeroed_page(GFP_KERNEL);
|
||||
adapter->filter_list_addr = (void*) get_zeroed_page(GFP_KERNEL);
|
||||
|
@ -502,14 +490,8 @@ static int ibmveth_open(struct net_device *netdev)
|
|||
adapter->rx_queue.num_slots = rxq_entries;
|
||||
adapter->rx_queue.toggle = 1;
|
||||
|
||||
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;
|
||||
}
|
||||
/* call change_mtu to init the buffer pools based in initial mtu */
|
||||
ibmveth_change_mtu(netdev, netdev->mtu);
|
||||
|
||||
memcpy(&mac_address, netdev->dev_addr, netdev->addr_len);
|
||||
mac_address = mac_address >> 16;
|
||||
|
@ -552,10 +534,10 @@ static int ibmveth_open(struct net_device *netdev)
|
|||
return rc;
|
||||
}
|
||||
|
||||
netif_start_queue(netdev);
|
||||
ibmveth_debug_printk("initial replenish cycle\n");
|
||||
ibmveth_replenish_task(adapter);
|
||||
|
||||
ibmveth_debug_printk("scheduling initial replenish cycle\n");
|
||||
ibmveth_schedule_replenishing(adapter);
|
||||
netif_start_queue(netdev);
|
||||
|
||||
ibmveth_debug_printk("open complete\n");
|
||||
|
||||
|
@ -573,9 +555,6 @@ 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));
|
||||
|
@ -640,12 +619,18 @@ 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) {
|
||||
adapter->stats.tx_dropped++;
|
||||
dev_kfree_skb(skb);
|
||||
return 0;
|
||||
tx_dropped++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
|
@ -664,10 +649,9 @@ 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");
|
||||
adapter->tx_map_failed++;
|
||||
adapter->stats.tx_dropped++;
|
||||
dev_kfree_skb(skb);
|
||||
return 0;
|
||||
tx_map_failed++;
|
||||
tx_dropped++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
curfrag = nfrags;
|
||||
|
@ -684,8 +668,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);
|
||||
adapter->tx_map_failed++;
|
||||
adapter->stats.tx_dropped++;
|
||||
tx_map_failed++;
|
||||
tx_dropped++;
|
||||
/* Free all the mappings we just created */
|
||||
while(curfrag < nfrags) {
|
||||
dma_unmap_single(&adapter->vdev->dev,
|
||||
|
@ -694,8 +678,7 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev)
|
|||
DMA_TO_DEVICE);
|
||||
curfrag++;
|
||||
}
|
||||
dev_kfree_skb(skb);
|
||||
return 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -720,11 +703,12 @@ 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);
|
||||
}
|
||||
adapter->tx_send_failed++;
|
||||
adapter->stats.tx_dropped++;
|
||||
tx_send_failed++;
|
||||
tx_dropped++;
|
||||
} else {
|
||||
adapter->stats.tx_packets++;
|
||||
adapter->stats.tx_bytes += skb->len;
|
||||
tx_packets++;
|
||||
tx_bytes += skb->len;
|
||||
netdev->trans_start = jiffies;
|
||||
}
|
||||
|
||||
do {
|
||||
|
@ -733,6 +717,14 @@ 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;
|
||||
}
|
||||
|
@ -776,13 +768,14 @@ 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_schedule_replenishing(adapter);
|
||||
ibmveth_replenish_task(adapter);
|
||||
|
||||
if(more_work) {
|
||||
/* more work to do - return that we are not done yet */
|
||||
|
@ -883,17 +876,54 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
|
|||
|
||||
static int ibmveth_change_mtu(struct net_device *dev, int new_mtu)
|
||||
{
|
||||
if ((new_mtu < 68) || (new_mtu > (1<<20)))
|
||||
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))
|
||||
return -EINVAL;
|
||||
|
||||
for(i = 0; i<IbmVethNumBufferPools; i++) {
|
||||
int activate = 0;
|
||||
if (new_mtu > (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;
|
||||
int rc, i;
|
||||
struct net_device *netdev;
|
||||
struct ibmveth_adapter *adapter;
|
||||
struct ibmveth_adapter *adapter = NULL;
|
||||
|
||||
unsigned char *mac_addr_p;
|
||||
unsigned int *mcastFilterSize_p;
|
||||
|
@ -960,23 +990,21 @@ 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);
|
||||
|
||||
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);
|
||||
for(i = 0; i<IbmVethNumBufferPools; i++)
|
||||
ibmveth_init_buffer_pool(&adapter->rx_buff_pool[i], i,
|
||||
pool_count[i], pool_size[i]);
|
||||
|
||||
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);
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#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) \
|
||||
|
@ -69,13 +70,15 @@
|
|||
#define h_change_logical_lan_mac(ua, mac) \
|
||||
plpar_hcall_norets(H_CHANGE_LOGICAL_LAN_MAC, ua, mac)
|
||||
|
||||
#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 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 IBM_VETH_INVALID_MAP ((u16)0xffff)
|
||||
|
||||
|
@ -90,6 +93,7 @@ struct ibmveth_buff_pool {
|
|||
u16 *free_map;
|
||||
dma_addr_t *dma_addr;
|
||||
struct sk_buff **skbuff;
|
||||
int active;
|
||||
};
|
||||
|
||||
struct ibmveth_rx_q {
|
||||
|
@ -114,10 +118,6 @@ 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,6 +131,7 @@ struct ibmveth_adapter {
|
|||
u64 tx_linearize_failed;
|
||||
u64 tx_map_failed;
|
||||
u64 tx_send_failed;
|
||||
spinlock_t stats_lock;
|
||||
};
|
||||
|
||||
struct ibmveth_buf_desc_fields {
|
||||
|
|
|
@ -1695,11 +1695,9 @@ toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid)
|
|||
|
||||
freebufs:
|
||||
for (i = 0; i < TX_SLOTS; ++i)
|
||||
if (self->tx_bufs[i])
|
||||
kfree (self->tx_bufs[i]);
|
||||
kfree (self->tx_bufs[i]);
|
||||
for (i = 0; i < RX_SLOTS; ++i)
|
||||
if (self->rx_bufs[i])
|
||||
kfree (self->rx_bufs[i]);
|
||||
kfree (self->rx_bufs[i]);
|
||||
kfree(self->ringbuf);
|
||||
|
||||
freeregion:
|
||||
|
|
|
@ -1168,10 +1168,8 @@ static inline void irda_usb_close(struct irda_usb_cb *self)
|
|||
unregister_netdev(self->netdev);
|
||||
|
||||
/* Remove the speed buffer */
|
||||
if (self->speed_buff != NULL) {
|
||||
kfree(self->speed_buff);
|
||||
self->speed_buff = NULL;
|
||||
}
|
||||
kfree(self->speed_buff);
|
||||
self->speed_buff = NULL;
|
||||
}
|
||||
|
||||
/********************** USB CONFIG SUBROUTINES **********************/
|
||||
|
|
|
@ -235,8 +235,7 @@ static int irport_close(struct irport_cb *self)
|
|||
__FUNCTION__, self->io.sir_base);
|
||||
release_region(self->io.sir_base, self->io.sir_ext);
|
||||
|
||||
if (self->tx_buff.head)
|
||||
kfree(self->tx_buff.head);
|
||||
kfree(self->tx_buff.head);
|
||||
|
||||
if (self->rx_buff.skb)
|
||||
kfree_skb(self->rx_buff.skb);
|
||||
|
|
|
@ -490,8 +490,7 @@ static void sirdev_free_buffers(struct sir_dev *dev)
|
|||
{
|
||||
if (dev->rx_buff.skb)
|
||||
kfree_skb(dev->rx_buff.skb);
|
||||
if (dev->tx_buff.head)
|
||||
kfree(dev->tx_buff.head);
|
||||
kfree(dev->tx_buff.head);
|
||||
dev->rx_buff.head = dev->tx_buff.head = NULL;
|
||||
dev->rx_buff.skb = NULL;
|
||||
}
|
||||
|
|
|
@ -473,8 +473,7 @@ 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);
|
||||
if (rd->buf)
|
||||
kfree(rd->buf);
|
||||
kfree(rd->buf);
|
||||
}
|
||||
kfree(r);
|
||||
return 0;
|
||||
|
|
|
@ -1035,10 +1035,8 @@ static void __exit mace_cleanup(void)
|
|||
{
|
||||
macio_unregister_driver(&mace_driver);
|
||||
|
||||
if (dummy_buf) {
|
||||
kfree(dummy_buf);
|
||||
dummy_buf = NULL;
|
||||
}
|
||||
kfree(dummy_buf);
|
||||
dummy_buf = NULL;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Paul Mackerras");
|
||||
|
|
|
@ -675,7 +675,6 @@ 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);
|
||||
|
||||
|
|
|
@ -696,8 +696,7 @@ static void ni65_free_buffer(struct priv *p)
|
|||
return;
|
||||
|
||||
for(i=0;i<TMDNUM;i++) {
|
||||
if(p->tmdbounce[i])
|
||||
kfree(p->tmdbounce[i]);
|
||||
kfree(p->tmdbounce[i]);
|
||||
#ifdef XMT_VIA_SKB
|
||||
if(p->tmd_skb[i])
|
||||
dev_kfree_skb(p->tmd_skb[i]);
|
||||
|
@ -710,12 +709,10 @@ static void ni65_free_buffer(struct priv *p)
|
|||
if(p->recv_skb[i])
|
||||
dev_kfree_skb(p->recv_skb[i]);
|
||||
#else
|
||||
if(p->recvbounce[i])
|
||||
kfree(p->recvbounce[i]);
|
||||
kfree(p->recvbounce[i]);
|
||||
#endif
|
||||
}
|
||||
if(p->self)
|
||||
kfree(p->self);
|
||||
kfree(p->self);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1020,6 +1020,12 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1710,10 +1710,8 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
|||
error = -EFAULT;
|
||||
}
|
||||
wf_out:
|
||||
if (oldimage)
|
||||
kfree(oldimage);
|
||||
if (image)
|
||||
kfree(image);
|
||||
kfree(oldimage);
|
||||
kfree(image);
|
||||
return error;
|
||||
|
||||
case SIOCRRID:
|
||||
|
|
|
@ -705,8 +705,7 @@ static void free_shared_mem(struct s2io_nic *nic)
|
|||
}
|
||||
kfree(mac_control->rings[i].ba[j]);
|
||||
}
|
||||
if (mac_control->rings[i].ba)
|
||||
kfree(mac_control->rings[i].ba);
|
||||
kfree(mac_control->rings[i].ba);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -997,10 +997,7 @@ static void __devexit saa9730_remove_one(struct pci_dev *pdev)
|
|||
|
||||
if (dev) {
|
||||
unregister_netdev(dev);
|
||||
|
||||
if (dev->priv)
|
||||
kfree(dev->priv);
|
||||
|
||||
kfree(dev->priv);
|
||||
free_netdev(dev);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
|
@ -1096,8 +1093,7 @@ static int lan_saa9730_init(struct net_device *dev, int ioaddr, int irq)
|
|||
return 0;
|
||||
|
||||
out:
|
||||
if (dev->priv)
|
||||
kfree(dev->priv);
|
||||
kfree(dev->priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) >> 26;
|
||||
ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f;
|
||||
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
|
||||
rx_mode |= AcceptMulticast;
|
||||
}
|
||||
|
|
|
@ -1696,15 +1696,20 @@ 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)) {
|
||||
|
@ -1732,9 +1737,11 @@ 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_INFO "%s: NULL pointer "
|
||||
"encountered in Rx ring, skipping\n",
|
||||
net_dev->name);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1770,6 +1777,7 @@ 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;
|
||||
|
@ -1787,7 +1795,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 > 0; sis_priv->dirty_rx++) {
|
||||
for (; sis_priv->cur_rx != sis_priv->dirty_rx; sis_priv->dirty_rx++) {
|
||||
struct sk_buff *skb;
|
||||
|
||||
entry = sis_priv->dirty_rx % NUM_RX_DESC;
|
||||
|
|
|
@ -1983,6 +1983,10 @@ 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;
|
||||
|
|
|
@ -1091,8 +1091,10 @@ 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 == 0)
|
||||
if (np->queue_mem == NULL) {
|
||||
free_irq(dev->irq, dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
np->tx_done_q = np->queue_mem;
|
||||
np->tx_done_q_dma = np->queue_mem_dma;
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
I/O access could affect performance in ARM-based system
|
||||
- Add Linux software VLAN support
|
||||
|
||||
Version LK1.08 (D-Link):
|
||||
Version LK1.08 (Philippe De Muyter phdm@macqel.be):
|
||||
- Fix bug of custom mac address
|
||||
(StationAddr register only accept word write)
|
||||
|
||||
|
@ -91,11 +91,14 @@
|
|||
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.09a"
|
||||
#define DRV_RELDATE "10-Jul-2003"
|
||||
#define DRV_VERSION "1.01+LK1.10"
|
||||
#define DRV_RELDATE "28-Oct-2005"
|
||||
|
||||
|
||||
/* The user-configurable values.
|
||||
|
@ -263,8 +266,10 @@ IV. Notes
|
|||
IVb. References
|
||||
|
||||
The Sundance ST201 datasheet, preliminary version.
|
||||
http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html
|
||||
http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
|
||||
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
|
||||
|
||||
IVc. Errata
|
||||
|
||||
|
@ -500,6 +505,25 @@ 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)
|
||||
{
|
||||
|
@ -1190,23 +1214,33 @@ 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 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);
|
||||
/*
|
||||
** 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 */
|
||||
}
|
||||
if (tx_status & 0x1e) /* Restart the Tx. */
|
||||
iowrite16 (TxEnable,
|
||||
ioaddr + MACCtrl1);
|
||||
/* Restart the Tx. */
|
||||
iowrite16 (TxEnable, ioaddr + MACCtrl1);
|
||||
}
|
||||
/* Yup, this is a documentation bug. It cost me *hours*. */
|
||||
iowrite16 (0, ioaddr + TxStatus);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <linux/tcp.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/prefetch.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <net/checksum.h>
|
||||
|
||||
|
@ -67,8 +68,8 @@
|
|||
|
||||
#define DRV_MODULE_NAME "tg3"
|
||||
#define PFX DRV_MODULE_NAME ": "
|
||||
#define DRV_MODULE_VERSION "3.42"
|
||||
#define DRV_MODULE_RELDATE "Oct 3, 2005"
|
||||
#define DRV_MODULE_VERSION "3.43"
|
||||
#define DRV_MODULE_RELDATE "Oct 24, 2005"
|
||||
|
||||
#define TG3_DEF_MAC_MODE 0
|
||||
#define TG3_DEF_RX_MODE 0
|
||||
|
@ -219,6 +220,10 @@ 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,
|
||||
|
@ -466,6 +471,15 @@ 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;
|
||||
|
@ -570,7 +584,7 @@ static void tg3_switch_clocks(struct tg3 *tp)
|
|||
u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL);
|
||||
u32 orig_clock_ctrl;
|
||||
|
||||
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)
|
||||
if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
|
||||
return;
|
||||
|
||||
orig_clock_ctrl = clock_ctrl;
|
||||
|
@ -1210,7 +1224,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
|
|||
CLOCK_CTRL_ALTCLK |
|
||||
CLOCK_CTRL_PWRDOWN_PLL133);
|
||||
udelay(40);
|
||||
} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) {
|
||||
} else if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
|
||||
/* do nothing */
|
||||
} else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
|
||||
(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) {
|
||||
|
@ -3712,14 +3726,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 (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) {
|
||||
if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
|
||||
tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE;
|
||||
ethtool_op_set_tso(dev, 0);
|
||||
}
|
||||
else
|
||||
tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE;
|
||||
} else {
|
||||
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)
|
||||
if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
|
||||
tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
|
||||
tp->tg3_flags &= ~TG3_FLAG_JUMBO_RING_ENABLE;
|
||||
}
|
||||
|
@ -3850,7 +3864,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 ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) &&
|
||||
if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) &&
|
||||
(tp->dev->mtu > ETH_DATA_LEN))
|
||||
tp->rx_pkt_buf_sz = RX_JUMBO_PKT_BUF_SZ;
|
||||
|
||||
|
@ -3905,10 +3919,8 @@ static void tg3_init_rings(struct tg3 *tp)
|
|||
*/
|
||||
static void tg3_free_consistent(struct tg3 *tp)
|
||||
{
|
||||
if (tp->rx_std_buffers) {
|
||||
kfree(tp->rx_std_buffers);
|
||||
tp->rx_std_buffers = NULL;
|
||||
}
|
||||
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);
|
||||
|
@ -4347,7 +4359,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 (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) {
|
||||
if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
|
||||
u32 val;
|
||||
|
||||
/* Chip reset on 5780 will reset MSI enable bit,
|
||||
|
@ -6003,7 +6015,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) &&
|
||||
(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780))
|
||||
!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
|
||||
limit = 8;
|
||||
else
|
||||
limit = 16;
|
||||
|
@ -6191,14 +6203,16 @@ static void tg3_timer(unsigned long __opaque)
|
|||
tp->timer_counter = tp->timer_multiplier;
|
||||
}
|
||||
|
||||
/* Heartbeat is only sent once every 120 seconds. */
|
||||
/* Heartbeat is only sent once every 2 seconds. */
|
||||
if (!--tp->asf_counter) {
|
||||
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
|
||||
u32 val;
|
||||
|
||||
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);
|
||||
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);
|
||||
val = tr32(GRC_RX_CPU_EVENT);
|
||||
val |= (1 << 14);
|
||||
tw32(GRC_RX_CPU_EVENT, val);
|
||||
|
@ -6409,7 +6423,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) * 120);
|
||||
((HZ / tp->timer_offset) * 2);
|
||||
|
||||
init_timer(&tp->timer);
|
||||
tp->timer.expires = jiffies + tp->timer_offset;
|
||||
|
@ -7237,7 +7251,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_PHY_SERDES))
|
||||
if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES))
|
||||
cmd->supported |= (SUPPORTED_100baseT_Half |
|
||||
SUPPORTED_100baseT_Full |
|
||||
SUPPORTED_10baseT_Half |
|
||||
|
@ -7264,7 +7278,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_PHY_SERDES) {
|
||||
if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
|
||||
/* These are the only valid advertisement bits allowed. */
|
||||
if (cmd->autoneg == AUTONEG_ENABLE &&
|
||||
(cmd->advertising & ~(ADVERTISED_1000baseT_Half |
|
||||
|
@ -7272,7 +7286,17 @@ 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);
|
||||
|
||||
|
@ -8380,7 +8404,7 @@ static void __devinit tg3_get_nvram_info(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_5780)) {
|
||||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
|
||||
switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) {
|
||||
case FLASH_VENDOR_ATMEL_FLASH_BUFFERED:
|
||||
tp->nvram_jedecnum = JEDEC_ATMEL;
|
||||
|
@ -8980,7 +9004,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
|
|||
|
||||
tp->phy_id = eeprom_phy_id;
|
||||
if (eeprom_phy_serdes) {
|
||||
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)
|
||||
if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
|
||||
tp->tg3_flags2 |= TG3_FLG2_MII_SERDES;
|
||||
else
|
||||
tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
|
||||
|
@ -9393,8 +9417,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
|
|||
}
|
||||
|
||||
/* Find msi capability. */
|
||||
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)
|
||||
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;
|
||||
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 &
|
||||
|
@ -9412,7 +9439,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 ||
|
||||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)
|
||||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
|
||||
tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
|
||||
|
||||
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) ||
|
||||
|
@ -9607,7 +9634,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
|
|||
* ether_setup() via the alloc_etherdev() call
|
||||
*/
|
||||
if (tp->dev->mtu > ETH_DATA_LEN &&
|
||||
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780)
|
||||
!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
|
||||
tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE;
|
||||
|
||||
/* Determine WakeOnLan speed to use. */
|
||||
|
@ -9830,7 +9857,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)) ||
|
||||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) {
|
||||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
|
||||
if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
|
||||
mac_offset = 0xcc;
|
||||
if (tg3_nvram_lock(tp))
|
||||
|
@ -10148,6 +10175,9 @@ 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;
|
||||
}
|
||||
|
@ -10347,6 +10377,7 @@ 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";
|
||||
|
@ -10492,17 +10523,17 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
|
|||
}
|
||||
|
||||
/* Configure DMA attributes. */
|
||||
err = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
|
||||
err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
|
||||
if (!err) {
|
||||
pci_using_dac = 1;
|
||||
err = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
|
||||
err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
|
||||
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, 0xffffffffULL);
|
||||
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "No usable DMA configuration, "
|
||||
"aborting.\n");
|
||||
|
|
|
@ -137,6 +137,7 @@
|
|||
#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
|
||||
|
@ -531,6 +532,8 @@
|
|||
#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
|
||||
|
@ -1329,6 +1332,8 @@
|
|||
#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
|
||||
|
@ -1507,6 +1512,7 @@
|
|||
#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
|
||||
|
@ -2175,6 +2181,7 @@ 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
|
||||
|
@ -2222,6 +2229,7 @@ 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
|
||||
|
@ -2246,8 +2254,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_BCM5780 || \
|
||||
(X) == PHY_ID_BCM8002)
|
||||
(X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \
|
||||
(X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM8002)
|
||||
|
||||
struct tg3_hw_stats *hw_stats;
|
||||
dma_addr_t stats_mapping;
|
||||
|
|
|
@ -2076,8 +2076,7 @@ static int __init de_init_one (struct pci_dev *pdev,
|
|||
return 0;
|
||||
|
||||
err_out_iomap:
|
||||
if (de->ee_data)
|
||||
kfree(de->ee_data);
|
||||
kfree(de->ee_data);
|
||||
iounmap(regs);
|
||||
err_out_res:
|
||||
pci_release_regions(pdev);
|
||||
|
@ -2096,8 +2095,7 @@ static void __exit de_remove_one (struct pci_dev *pdev)
|
|||
if (!dev)
|
||||
BUG();
|
||||
unregister_netdev(dev);
|
||||
if (de->ee_data)
|
||||
kfree(de->ee_data);
|
||||
kfree(de->ee_data);
|
||||
iounmap(de->regs);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
|
|
|
@ -1727,8 +1727,7 @@ err_out_free_ring:
|
|||
tp->rx_ring, tp->rx_ring_dma);
|
||||
|
||||
err_out_mtable:
|
||||
if (tp->mtable)
|
||||
kfree (tp->mtable);
|
||||
kfree (tp->mtable);
|
||||
pci_iounmap(pdev, ioaddr);
|
||||
|
||||
err_out_free_res:
|
||||
|
@ -1806,8 +1805,7 @@ 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);
|
||||
if (tp->mtable)
|
||||
kfree (tp->mtable);
|
||||
kfree (tp->mtable);
|
||||
pci_iounmap(pdev, tp->base_addr);
|
||||
free_netdev (dev);
|
||||
pci_release_regions (pdev);
|
||||
|
|
|
@ -1212,10 +1212,8 @@ static void velocity_free_td_ring(struct velocity_info *vptr)
|
|||
velocity_free_td_ring_entry(vptr, j, i);
|
||||
|
||||
}
|
||||
if (vptr->td_infos[j]) {
|
||||
kfree(vptr->td_infos[j]);
|
||||
vptr->td_infos[j] = NULL;
|
||||
}
|
||||
kfree(vptr->td_infos[j]);
|
||||
vptr->td_infos[j] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2381,14 +2381,10 @@ void stop_airo_card( struct net_device *dev, int freeres )
|
|||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
if (ai->flash)
|
||||
kfree(ai->flash);
|
||||
if (ai->rssi)
|
||||
kfree(ai->rssi);
|
||||
if (ai->APList)
|
||||
kfree(ai->APList);
|
||||
if (ai->SSID)
|
||||
kfree(ai->SSID);
|
||||
kfree(ai->flash);
|
||||
kfree(ai->rssi);
|
||||
kfree(ai->APList);
|
||||
kfree(ai->SSID);
|
||||
if (freeres) {
|
||||
/* PCMCIA frees this stuff, so only for PCI and ISA */
|
||||
release_region( dev->base_addr, 64 );
|
||||
|
@ -3626,10 +3622,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
|
|||
int rc;
|
||||
|
||||
memset( &mySsid, 0, sizeof( mySsid ) );
|
||||
if (ai->flash) {
|
||||
kfree (ai->flash);
|
||||
ai->flash = NULL;
|
||||
}
|
||||
kfree (ai->flash);
|
||||
ai->flash = NULL;
|
||||
|
||||
/* The NOP is the first step in getting the card going */
|
||||
cmd.cmd = NOP;
|
||||
|
@ -3666,14 +3660,10 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
|
|||
tdsRssiRid rssi_rid;
|
||||
CapabilityRid cap_rid;
|
||||
|
||||
if (ai->APList) {
|
||||
kfree(ai->APList);
|
||||
ai->APList = NULL;
|
||||
}
|
||||
if (ai->SSID) {
|
||||
kfree(ai->SSID);
|
||||
ai->SSID = NULL;
|
||||
}
|
||||
kfree(ai->APList);
|
||||
ai->APList = NULL;
|
||||
kfree(ai->SSID);
|
||||
ai->SSID = NULL;
|
||||
// general configuration (read/modify/write)
|
||||
status = readConfigRid(ai, lock);
|
||||
if ( status != SUCCESS ) return ERROR;
|
||||
|
@ -3687,10 +3677,8 @@ 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 {
|
||||
if (ai->rssi) {
|
||||
kfree(ai->rssi);
|
||||
ai->rssi = NULL;
|
||||
}
|
||||
kfree(ai->rssi);
|
||||
ai->rssi = NULL;
|
||||
if (cap_rid.softCap & 8)
|
||||
ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
|
||||
else
|
||||
|
@ -5369,11 +5357,13 @@ 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 = (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 );
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -258,9 +258,7 @@ static void airo_detach(dev_link_t *link)
|
|||
|
||||
/* Unlink device structure, free pieces */
|
||||
*linkp = link->next;
|
||||
if (link->priv) {
|
||||
kfree(link->priv);
|
||||
}
|
||||
kfree(link->priv);
|
||||
kfree(link);
|
||||
|
||||
} /* airo_detach */
|
||||
|
|
|
@ -1653,8 +1653,7 @@ void stop_atmel_card(struct net_device *dev, int freeres)
|
|||
unregister_netdev(dev);
|
||||
remove_proc_entry("driver/atmel", NULL);
|
||||
free_irq(dev->irq, dev);
|
||||
if (priv->firmware)
|
||||
kfree(priv->firmware);
|
||||
kfree(priv->firmware);
|
||||
if (freeres) {
|
||||
/* PCMCIA frees this stuff, so only for PCI */
|
||||
release_region(dev->base_addr, 64);
|
||||
|
@ -2450,8 +2449,7 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
|||
break;
|
||||
}
|
||||
|
||||
if (priv->firmware)
|
||||
kfree(priv->firmware);
|
||||
kfree(priv->firmware);
|
||||
|
||||
priv->firmware = new_firmware;
|
||||
priv->firmware_length = com.len;
|
||||
|
|
|
@ -259,8 +259,7 @@ static void atmel_detach(dev_link_t *link)
|
|||
|
||||
/* Unlink device structure, free pieces */
|
||||
*linkp = link->next;
|
||||
if (link->priv)
|
||||
kfree(link->priv);
|
||||
kfree(link->priv);
|
||||
kfree(link);
|
||||
}
|
||||
|
||||
|
|
|
@ -444,6 +444,43 @@ 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
|
||||
|
@ -531,6 +568,7 @@ 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);
|
||||
|
||||
|
|
|
@ -376,6 +376,8 @@ 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,
|
||||
|
|
|
@ -552,7 +552,6 @@ static int prism2_ioctl_giwaplist(struct net_device *dev,
|
|||
|
||||
kfree(addr);
|
||||
kfree(qual);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3081,9 +3080,7 @@ static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p)
|
|||
ret = local->func->download(local, param);
|
||||
|
||||
out:
|
||||
if (param != NULL)
|
||||
kfree(param);
|
||||
|
||||
kfree(param);
|
||||
return ret;
|
||||
}
|
||||
#endif /* PRISM2_DOWNLOAD_SUPPORT */
|
||||
|
@ -3890,9 +3887,7 @@ static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p)
|
|||
}
|
||||
|
||||
out:
|
||||
if (param != NULL)
|
||||
kfree(param);
|
||||
|
||||
kfree(param);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -4030,6 +4030,10 @@ 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);
|
||||
|
|
|
@ -490,7 +490,8 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Check packet length, pad short packets, round up odd length */
|
||||
/* Length of the packet body */
|
||||
/* FIXME: what if the skb is smaller than this? */
|
||||
len = max_t(int, ALIGN(skb->len, 2), ETH_ZLEN);
|
||||
skb = skb_padto(skb, len);
|
||||
if (skb == NULL)
|
||||
|
@ -541,13 +542,21 @@ 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(hw, USER_BAP, p, data_len,
|
||||
err = hermes_bap_pwrite_pad(hw, USER_BAP, p, data_len, len,
|
||||
txfid, data_off);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
|
||||
|
|
|
@ -754,8 +754,7 @@ islpci_free_memory(islpci_private *priv)
|
|||
pci_unmap_single(priv->pdev, buf->pci_addr,
|
||||
buf->size, PCI_DMA_FROMDEVICE);
|
||||
buf->pci_addr = 0;
|
||||
if (buf->mem)
|
||||
kfree(buf->mem);
|
||||
kfree(buf->mem);
|
||||
buf->size = 0;
|
||||
buf->mem = NULL;
|
||||
}
|
||||
|
|
|
@ -97,12 +97,6 @@ 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)) {
|
||||
|
@ -213,6 +207,7 @@ 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);
|
||||
|
@ -246,12 +241,10 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
|
|||
return 0;
|
||||
|
||||
drop_free:
|
||||
/* free the skbuf structure before aborting */
|
||||
dev_kfree_skb(skb);
|
||||
skb = NULL;
|
||||
|
||||
priv->statistics.tx_dropped++;
|
||||
spin_unlock_irqrestore(&priv->slock, flags);
|
||||
dev_kfree_skb(skb);
|
||||
skb = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -268,11 +268,10 @@ mgt_clean(islpci_private *priv)
|
|||
|
||||
if (!priv->mib)
|
||||
return;
|
||||
for (i = 0; i < OID_NUM_LAST; i++)
|
||||
if (priv->mib[i]) {
|
||||
kfree(priv->mib[i]);
|
||||
priv->mib[i] = NULL;
|
||||
}
|
||||
for (i = 0; i < OID_NUM_LAST; i++) {
|
||||
kfree(priv->mib[i]);
|
||||
priv->mib[i] = NULL;
|
||||
}
|
||||
kfree(priv->mib);
|
||||
priv->mib = NULL;
|
||||
}
|
||||
|
|
|
@ -860,12 +860,9 @@ static int allocate_buffers(struct strip *strip_info, int mtu)
|
|||
strip_info->mtu = dev->mtu = mtu;
|
||||
return (1);
|
||||
}
|
||||
if (r)
|
||||
kfree(r);
|
||||
if (s)
|
||||
kfree(s);
|
||||
if (t)
|
||||
kfree(t);
|
||||
kfree(r);
|
||||
kfree(s);
|
||||
kfree(t);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -922,13 +919,9 @@ 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);
|
||||
|
||||
if (orbuff)
|
||||
kfree(orbuff);
|
||||
if (osbuff)
|
||||
kfree(osbuff);
|
||||
if (otbuff)
|
||||
kfree(otbuff);
|
||||
|
||||
kfree(orbuff);
|
||||
kfree(osbuff);
|
||||
kfree(otbuff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2498,18 +2491,13 @@ static int strip_close_low(struct net_device *dev)
|
|||
/*
|
||||
* Free all STRIP frame buffers.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
del_timer(&strip_info->idle_timer);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Platform information definitions for the
|
||||
* universal Freescale Ethernet driver.
|
||||
*
|
||||
* Copyright (c) 2003 Intracom S.A.
|
||||
* by Pantelis Antoniou <panto@intracom.gr>
|
||||
*
|
||||
* 2005 (c) MontaVista Software, Inc.
|
||||
* Vitaly Bordug <vbordug@ru.mvista.com>
|
||||
*
|
||||
* 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 <linux/version.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
#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
|
|
@ -1788,11 +1788,13 @@
|
|||
#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
|
||||
|
|
|
@ -237,8 +237,7 @@ typedef struct ax25_cb {
|
|||
static __inline__ void ax25_cb_put(ax25_cb *ax25)
|
||||
{
|
||||
if (atomic_dec_and_test(&ax25->refcount)) {
|
||||
if (ax25->digipeat)
|
||||
kfree(ax25->digipeat);
|
||||
kfree(ax25->digipeat);
|
||||
kfree(ax25);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,8 +136,7 @@ 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)) {
|
||||
if (nr_neigh->digipeat != NULL)
|
||||
kfree(nr_neigh->digipeat);
|
||||
kfree(nr_neigh->digipeat);
|
||||
kfree(nr_neigh);
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче