Commit fc32b0e2 authored by Lennert Buytenhek's avatar Lennert Buytenhek

mv643xx_eth: general cleanup

General cleanup of the mv643xx_eth driver.  Mainly fixes coding
style / indentation issues, get rid of some useless 'volatile's,
kill some more superfluous comments, and such.
Signed-off-by: default avatarLennert Buytenhek <buytenh@marvell.com>
Acked-by: default avatarDale Farnsworth <dale@farnsworth.org>
parent ffd86bbe
...@@ -67,8 +67,6 @@ static char mv643xx_eth_driver_version[] = "1.0"; ...@@ -67,8 +67,6 @@ static char mv643xx_eth_driver_version[] = "1.0";
#define MAX_DESCS_PER_SKB 1 #define MAX_DESCS_PER_SKB 1
#endif #endif
#define ETH_HW_IP_ALIGN 2
/* /*
* Registers shared between all ports. * Registers shared between all ports.
*/ */
...@@ -158,12 +156,6 @@ static char mv643xx_eth_driver_version[] = "1.0"; ...@@ -158,12 +156,6 @@ static char mv643xx_eth_driver_version[] = "1.0";
#define DEFAULT_RX_QUEUE_SIZE 400 #define DEFAULT_RX_QUEUE_SIZE 400
#define DEFAULT_TX_QUEUE_SIZE 800 #define DEFAULT_TX_QUEUE_SIZE 800
/* SMI reg */
#define SMI_BUSY 0x10000000 /* 0 - Write, 1 - Read */
#define SMI_READ_VALID 0x08000000 /* 0 - Write, 1 - Read */
#define SMI_OPCODE_WRITE 0 /* Completion of Read */
#define SMI_OPCODE_READ 0x04000000 /* Operation is in progress */
/* /*
* RX/TX descriptors. * RX/TX descriptors.
...@@ -231,13 +223,24 @@ struct tx_desc { ...@@ -231,13 +223,24 @@ struct tx_desc {
/* global *******************************************************************/ /* global *******************************************************************/
struct mv643xx_eth_shared_private { struct mv643xx_eth_shared_private {
/*
* Ethernet controller base address.
*/
void __iomem *base; void __iomem *base;
/* used to protect SMI_REG, which is shared across ports */ /*
* Protects access to SMI_REG, which is shared between ports.
*/
spinlock_t phy_lock; spinlock_t phy_lock;
/*
* Per-port MBUS window access register value.
*/
u32 win_protect; u32 win_protect;
/*
* Hardware-specific parameters.
*/
unsigned int t_clk; unsigned int t_clk;
}; };
...@@ -306,16 +309,17 @@ struct tx_queue { ...@@ -306,16 +309,17 @@ struct tx_queue {
struct mv643xx_eth_private { struct mv643xx_eth_private {
struct mv643xx_eth_shared_private *shared; struct mv643xx_eth_shared_private *shared;
int port_num; /* User Ethernet port number */ int port_num;
struct mv643xx_eth_shared_private *shared_smi; struct net_device *dev;
struct work_struct tx_timeout_task; struct mv643xx_eth_shared_private *shared_smi;
int phy_addr;
struct net_device *dev;
struct mib_counters mib_counters;
spinlock_t lock; spinlock_t lock;
struct mib_counters mib_counters;
struct work_struct tx_timeout_task;
struct mii_if_info mii; struct mii_if_info mii;
/* /*
...@@ -450,7 +454,12 @@ static void rxq_refill(struct rx_queue *rxq) ...@@ -450,7 +454,12 @@ static void rxq_refill(struct rx_queue *rxq)
RX_ENABLE_INTERRUPT; RX_ENABLE_INTERRUPT;
wmb(); wmb();
skb_reserve(skb, ETH_HW_IP_ALIGN); /*
* The hardware automatically prepends 2 bytes of
* dummy data to each received packet, so that the
* IP header ends up 16-byte aligned.
*/
skb_reserve(skb, 2);
} }
if (rxq->rx_desc_count == 0) { if (rxq->rx_desc_count == 0) {
...@@ -474,9 +483,9 @@ static int rxq_process(struct rx_queue *rxq, int budget) ...@@ -474,9 +483,9 @@ static int rxq_process(struct rx_queue *rxq, int budget)
rx = 0; rx = 0;
while (rx < budget) { while (rx < budget) {
struct sk_buff *skb; struct rx_desc *rx_desc;
volatile struct rx_desc *rx_desc;
unsigned int cmd_sts; unsigned int cmd_sts;
struct sk_buff *skb;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&mp->lock, flags); spin_lock_irqsave(&mp->lock, flags);
...@@ -497,34 +506,40 @@ static int rxq_process(struct rx_queue *rxq, int budget) ...@@ -497,34 +506,40 @@ static int rxq_process(struct rx_queue *rxq, int budget)
spin_unlock_irqrestore(&mp->lock, flags); spin_unlock_irqrestore(&mp->lock, flags);
dma_unmap_single(NULL, rx_desc->buf_ptr + ETH_HW_IP_ALIGN, dma_unmap_single(NULL, rx_desc->buf_ptr + 2,
mp->dev->mtu + 24, DMA_FROM_DEVICE); mp->dev->mtu + 24, DMA_FROM_DEVICE);
rxq->rx_desc_count--; rxq->rx_desc_count--;
rx++; rx++;
/* /*
* Update statistics. * Update statistics.
* Note byte count includes 4 byte CRC count *
* Note that the descriptor byte count includes 2 dummy
* bytes automatically inserted by the hardware at the
* start of the packet (which we don't count), and a 4
* byte CRC at the end of the packet (which we do count).
*/ */
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += rx_desc->byte_cnt - ETH_HW_IP_ALIGN; stats->rx_bytes += rx_desc->byte_cnt - 2;
/* /*
* In case received a packet without first / last bits on OR * In case we received a packet without first / last bits
* the error summary bit is on, the packets needs to be dropeed. * on, or the error summary bit is set, the packet needs
* to be dropped.
*/ */
if (((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != if (((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) !=
(RX_FIRST_DESC | RX_LAST_DESC)) (RX_FIRST_DESC | RX_LAST_DESC))
|| (cmd_sts & ERROR_SUMMARY)) { || (cmd_sts & ERROR_SUMMARY)) {
stats->rx_dropped++; stats->rx_dropped++;
if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) !=
(RX_FIRST_DESC | RX_LAST_DESC)) { (RX_FIRST_DESC | RX_LAST_DESC)) {
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_ERR dev_printk(KERN_ERR, &mp->dev->dev,
"%s: Received packet spread " "received packet spanning "
"on multiple descriptors\n", "multiple descriptors\n");
mp->dev->name);
} }
if (cmd_sts & ERROR_SUMMARY) if (cmd_sts & ERROR_SUMMARY)
stats->rx_errors++; stats->rx_errors++;
...@@ -534,7 +549,7 @@ static int rxq_process(struct rx_queue *rxq, int budget) ...@@ -534,7 +549,7 @@ static int rxq_process(struct rx_queue *rxq, int budget)
* The -4 is for the CRC in the trailer of the * The -4 is for the CRC in the trailer of the
* received packet * received packet
*/ */
skb_put(skb, rx_desc->byte_cnt - ETH_HW_IP_ALIGN - 4); skb_put(skb, rx_desc->byte_cnt - 2 - 4);
if (cmd_sts & LAYER_4_CHECKSUM_OK) { if (cmd_sts & LAYER_4_CHECKSUM_OK) {
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
...@@ -548,8 +563,10 @@ static int rxq_process(struct rx_queue *rxq, int budget) ...@@ -548,8 +563,10 @@ static int rxq_process(struct rx_queue *rxq, int budget)
netif_rx(skb); netif_rx(skb);
#endif #endif
} }
mp->dev->last_rx = jiffies; mp->dev->last_rx = jiffies;
} }
rxq_refill(rxq); rxq_refill(rxq);
return rx; return rx;
...@@ -716,7 +733,7 @@ static void txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb) ...@@ -716,7 +733,7 @@ static void txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb)
txq->tx_desc_count += nr_frags + 1; txq->tx_desc_count += nr_frags + 1;
} }
static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) static int mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct mv643xx_eth_private *mp = netdev_priv(dev); struct mv643xx_eth_private *mp = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats; struct net_device_stats *stats = &dev->stats;
...@@ -727,8 +744,9 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -727,8 +744,9 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (has_tiny_unaligned_frags(skb) && __skb_linearize(skb)) { if (has_tiny_unaligned_frags(skb) && __skb_linearize(skb)) {
stats->tx_dropped++; stats->tx_dropped++;
printk(KERN_DEBUG "%s: failed to linearize tiny " dev_printk(KERN_DEBUG, &dev->dev,
"unaligned fragment\n", dev->name); "failed to linearize skb with tiny "
"unaligned fragment\n");
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
...@@ -758,13 +776,15 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -758,13 +776,15 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* mii management interface *************************************************/ /* mii management interface *************************************************/
static int phy_addr_get(struct mv643xx_eth_private *mp); #define SMI_BUSY 0x10000000
#define SMI_READ_VALID 0x08000000
#define SMI_OPCODE_READ 0x04000000
#define SMI_OPCODE_WRITE 0x00000000
static void read_smi_reg(struct mv643xx_eth_private *mp, static void smi_reg_read(struct mv643xx_eth_private *mp, unsigned int addr,
unsigned int phy_reg, unsigned int *value) unsigned int reg, unsigned int *value)
{ {
void __iomem *smi_reg = mp->shared_smi->base + SMI_REG; void __iomem *smi_reg = mp->shared_smi->base + SMI_REG;
int phy_addr = phy_addr_get(mp);
unsigned long flags; unsigned long flags;
int i; int i;
...@@ -780,7 +800,7 @@ static void read_smi_reg(struct mv643xx_eth_private *mp, ...@@ -780,7 +800,7 @@ static void read_smi_reg(struct mv643xx_eth_private *mp,
udelay(10); udelay(10);
} }
writel((phy_addr << 16) | (phy_reg << 21) | SMI_OPCODE_READ, smi_reg); writel(SMI_OPCODE_READ | (reg << 21) | (addr << 16), smi_reg);
/* now wait for the data to be valid */ /* now wait for the data to be valid */
for (i = 0; !(readl(smi_reg) & SMI_READ_VALID); i++) { for (i = 0; !(readl(smi_reg) & SMI_READ_VALID); i++) {
...@@ -796,11 +816,11 @@ static void read_smi_reg(struct mv643xx_eth_private *mp, ...@@ -796,11 +816,11 @@ static void read_smi_reg(struct mv643xx_eth_private *mp,
spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags); spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags);
} }
static void write_smi_reg(struct mv643xx_eth_private *mp, static void smi_reg_write(struct mv643xx_eth_private *mp,
unsigned int phy_reg, unsigned int value) unsigned int addr,
unsigned int reg, unsigned int value)
{ {
void __iomem *smi_reg = mp->shared_smi->base + SMI_REG; void __iomem *smi_reg = mp->shared_smi->base + SMI_REG;
int phy_addr = phy_addr_get(mp);
unsigned long flags; unsigned long flags;
int i; int i;
...@@ -816,65 +836,63 @@ static void write_smi_reg(struct mv643xx_eth_private *mp, ...@@ -816,65 +836,63 @@ static void write_smi_reg(struct mv643xx_eth_private *mp,
udelay(10); udelay(10);
} }
writel((phy_addr << 16) | (phy_reg << 21) | writel(SMI_OPCODE_WRITE | (reg << 21) |
SMI_OPCODE_WRITE | (value & 0xffff), smi_reg); (addr << 16) | (value & 0xffff), smi_reg);
out: out:
spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags); spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags);
} }
/* mib counters *************************************************************/ /* mib counters *************************************************************/
static void clear_mib_counters(struct mv643xx_eth_private *mp) static inline u32 mib_read(struct mv643xx_eth_private *mp, int offset)
{ {
unsigned int port_num = mp->port_num; return rdl(mp, MIB_COUNTERS(mp->port_num) + offset);
int i;
/* Perform dummy reads from MIB counters */
for (i = 0; i < 0x80; i += 4)
rdl(mp, MIB_COUNTERS(port_num) + i);
} }
static inline u32 read_mib(struct mv643xx_eth_private *mp, int offset) static void mib_counters_clear(struct mv643xx_eth_private *mp)
{ {
return rdl(mp, MIB_COUNTERS(mp->port_num) + offset); int i;
for (i = 0; i < 0x80; i += 4)
mib_read(mp, i);
} }
static void update_mib_counters(struct mv643xx_eth_private *mp) static void mib_counters_update(struct mv643xx_eth_private *mp)
{ {
struct mib_counters *p = &mp->mib_counters; struct mib_counters *p = &mp->mib_counters;
p->good_octets_received += read_mib(mp, 0x00); p->good_octets_received += mib_read(mp, 0x00);
p->good_octets_received += (u64)read_mib(mp, 0x04) << 32; p->good_octets_received += (u64)mib_read(mp, 0x04) << 32;
p->bad_octets_received += read_mib(mp, 0x08); p->bad_octets_received += mib_read(mp, 0x08);
p->internal_mac_transmit_err += read_mib(mp, 0x0c); p->internal_mac_transmit_err += mib_read(mp, 0x0c);
p->good_frames_received += read_mib(mp, 0x10); p->good_frames_received += mib_read(mp, 0x10);
p->bad_frames_received += read_mib(mp, 0x14); p->bad_frames_received += mib_read(mp, 0x14);
p->broadcast_frames_received += read_mib(mp, 0x18); p->broadcast_frames_received += mib_read(mp, 0x18);
p->multicast_frames_received += read_mib(mp, 0x1c); p->multicast_frames_received += mib_read(mp, 0x1c);
p->frames_64_octets += read_mib(mp, 0x20); p->frames_64_octets += mib_read(mp, 0x20);
p->frames_65_to_127_octets += read_mib(mp, 0x24); p->frames_65_to_127_octets += mib_read(mp, 0x24);
p->frames_128_to_255_octets += read_mib(mp, 0x28); p->frames_128_to_255_octets += mib_read(mp, 0x28);
p->frames_256_to_511_octets += read_mib(mp, 0x2c); p->frames_256_to_511_octets += mib_read(mp, 0x2c);
p->frames_512_to_1023_octets += read_mib(mp, 0x30); p->frames_512_to_1023_octets += mib_read(mp, 0x30);
p->frames_1024_to_max_octets += read_mib(mp, 0x34); p->frames_1024_to_max_octets += mib_read(mp, 0x34);
p->good_octets_sent += read_mib(mp, 0x38); p->good_octets_sent += mib_read(mp, 0x38);
p->good_octets_sent += (u64)read_mib(mp, 0x3c) << 32; p->good_octets_sent += (u64)mib_read(mp, 0x3c) << 32;
p->good_frames_sent += read_mib(mp, 0x40); p->good_frames_sent += mib_read(mp, 0x40);
p->excessive_collision += read_mib(mp, 0x44); p->excessive_collision += mib_read(mp, 0x44);
p->multicast_frames_sent += read_mib(mp, 0x48); p->multicast_frames_sent += mib_read(mp, 0x48);
p->broadcast_frames_sent += read_mib(mp, 0x4c); p->broadcast_frames_sent += mib_read(mp, 0x4c);
p->unrec_mac_control_received += read_mib(mp, 0x50); p->unrec_mac_control_received += mib_read(mp, 0x50);
p->fc_sent += read_mib(mp, 0x54); p->fc_sent += mib_read(mp, 0x54);
p->good_fc_received += read_mib(mp, 0x58); p->good_fc_received += mib_read(mp, 0x58);
p->bad_fc_received += read_mib(mp, 0x5c); p->bad_fc_received += mib_read(mp, 0x5c);
p->undersize_received += read_mib(mp, 0x60); p->undersize_received += mib_read(mp, 0x60);
p->fragments_received += read_mib(mp, 0x64); p->fragments_received += mib_read(mp, 0x64);
p->oversize_received += read_mib(mp, 0x68); p->oversize_received += mib_read(mp, 0x68);
p->jabber_received += read_mib(mp, 0x6c); p->jabber_received += mib_read(mp, 0x6c);
p->mac_receive_error += read_mib(mp, 0x70); p->mac_receive_error += mib_read(mp, 0x70);
p->bad_crc_event += read_mib(mp, 0x74); p->bad_crc_event += mib_read(mp, 0x74);
p->collision += read_mib(mp, 0x78); p->collision += mib_read(mp, 0x78);
p->late_collision += read_mib(mp, 0x7c); p->late_collision += mib_read(mp, 0x7c);
} }
...@@ -944,7 +962,9 @@ static int mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd * ...@@ -944,7 +962,9 @@ static int mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *
err = mii_ethtool_gset(&mp->mii, cmd); err = mii_ethtool_gset(&mp->mii, cmd);
spin_unlock_irq(&mp->lock); spin_unlock_irq(&mp->lock);
/* The PHY may support 1000baseT_Half, but the mv643xx does not */ /*
* The MAC does not support 1000baseT_Half.
*/
cmd->supported &= ~SUPPORTED_1000baseT_Half; cmd->supported &= ~SUPPORTED_1000baseT_Half;
cmd->advertising &= ~ADVERTISED_1000baseT_Half; cmd->advertising &= ~ADVERTISED_1000baseT_Half;
...@@ -956,6 +976,11 @@ static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd * ...@@ -956,6 +976,11 @@ static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *
struct mv643xx_eth_private *mp = netdev_priv(dev); struct mv643xx_eth_private *mp = netdev_priv(dev);
int err; int err;
/*
* The MAC does not support 1000baseT_Half.
*/
cmd->advertising &= ~ADVERTISED_1000baseT_Half;
spin_lock_irq(&mp->lock); spin_lock_irq(&mp->lock);
err = mii_ethtool_sset(&mp->mii, cmd); err = mii_ethtool_sset(&mp->mii, cmd);
spin_unlock_irq(&mp->lock); spin_unlock_irq(&mp->lock);
...@@ -963,17 +988,17 @@ static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd * ...@@ -963,17 +988,17 @@ static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *
return err; return err;
} }
static void mv643xx_eth_get_drvinfo(struct net_device *netdev, static void mv643xx_eth_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *drvinfo) struct ethtool_drvinfo *drvinfo)
{ {
strncpy(drvinfo->driver, mv643xx_eth_driver_name, 32); strncpy(drvinfo->driver, mv643xx_eth_driver_name, 32);
strncpy(drvinfo->version, mv643xx_eth_driver_version, 32); strncpy(drvinfo->version, mv643xx_eth_driver_version, 32);
strncpy(drvinfo->fw_version, "N/A", 32); strncpy(drvinfo->fw_version, "N/A", 32);
strncpy(drvinfo->bus_info, "mv643xx", 32); strncpy(drvinfo->bus_info, "platform", 32);
drvinfo->n_stats = ARRAY_SIZE(mv643xx_eth_stats); drvinfo->n_stats = ARRAY_SIZE(mv643xx_eth_stats);
} }
static int mv643xx_eth_nway_restart(struct net_device *dev) static int mv643xx_eth_nway_reset(struct net_device *dev)
{ {
struct mv643xx_eth_private *mp = netdev_priv(dev); struct mv643xx_eth_private *mp = netdev_priv(dev);
...@@ -987,29 +1012,28 @@ static u32 mv643xx_eth_get_link(struct net_device *dev) ...@@ -987,29 +1012,28 @@ static u32 mv643xx_eth_get_link(struct net_device *dev)
return mii_link_ok(&mp->mii); return mii_link_ok(&mp->mii);
} }
static void mv643xx_eth_get_strings(struct net_device *netdev, uint32_t stringset, static void mv643xx_eth_get_strings(struct net_device *dev,
uint8_t *data) uint32_t stringset, uint8_t *data)
{ {
int i; int i;
switch(stringset) { if (stringset == ETH_SS_STATS) {
case ETH_SS_STATS: for (i = 0; i < ARRAY_SIZE(mv643xx_eth_stats); i++) {
for (i=0; i < ARRAY_SIZE(mv643xx_eth_stats); i++) {
memcpy(data + i * ETH_GSTRING_LEN, memcpy(data + i * ETH_GSTRING_LEN,
mv643xx_eth_stats[i].stat_string, mv643xx_eth_stats[i].stat_string,
ETH_GSTRING_LEN); ETH_GSTRING_LEN);
} }
break;
} }
} }
static void mv643xx_eth_get_ethtool_stats(struct net_device *netdev, static void mv643xx_eth_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, uint64_t *data) struct ethtool_stats *stats,
uint64_t *data)
{ {
struct mv643xx_eth_private *mp = netdev->priv; struct mv643xx_eth_private *mp = dev->priv;
int i; int i;
update_mib_counters(mp); mib_counters_update(mp);
for (i = 0; i < ARRAY_SIZE(mv643xx_eth_stats); i++) { for (i = 0; i < ARRAY_SIZE(mv643xx_eth_stats); i++) {
const struct mv643xx_eth_stats *stat; const struct mv643xx_eth_stats *stat;
...@@ -1027,38 +1051,35 @@ static void mv643xx_eth_get_ethtool_stats(struct net_device *netdev, ...@@ -1027,38 +1051,35 @@ static void mv643xx_eth_get_ethtool_stats(struct net_device *netdev,
} }
} }
static int mv643xx_eth_get_sset_count(struct net_device *netdev, int sset) static int mv643xx_eth_get_sset_count(struct net_device *dev, int sset)
{ {
switch (sset) { if (sset == ETH_SS_STATS)
case ETH_SS_STATS:
return ARRAY_SIZE(mv643xx_eth_stats); return ARRAY_SIZE(mv643xx_eth_stats);
default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
}
} }
static const struct ethtool_ops mv643xx_eth_ethtool_ops = { static const struct ethtool_ops mv643xx_eth_ethtool_ops = {
.get_settings = mv643xx_eth_get_settings, .get_settings = mv643xx_eth_get_settings,
.set_settings = mv643xx_eth_set_settings, .set_settings = mv643xx_eth_set_settings,
.get_drvinfo = mv643xx_eth_get_drvinfo, .get_drvinfo = mv643xx_eth_get_drvinfo,
.nway_reset = mv643xx_eth_nway_reset,
.get_link = mv643xx_eth_get_link, .get_link = mv643xx_eth_get_link,
.set_sg = ethtool_op_set_sg, .set_sg = ethtool_op_set_sg,
.get_sset_count = mv643xx_eth_get_sset_count,
.get_ethtool_stats = mv643xx_eth_get_ethtool_stats,
.get_strings = mv643xx_eth_get_strings, .get_strings = mv643xx_eth_get_strings,
.nway_reset = mv643xx_eth_nway_restart, .get_ethtool_stats = mv643xx_eth_get_ethtool_stats,
.get_sset_count = mv643xx_eth_get_sset_count,
}; };
/* address handling *********************************************************/ /* address handling *********************************************************/
static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr) static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr)
{ {
unsigned int port_num = mp->port_num;
unsigned int mac_h; unsigned int mac_h;
unsigned int mac_l; unsigned int mac_l;
mac_h = rdl(mp, MAC_ADDR_HIGH(port_num)); mac_h = rdl(mp, MAC_ADDR_HIGH(mp->port_num));
mac_l = rdl(mp, MAC_ADDR_LOW(port_num)); mac_l = rdl(mp, MAC_ADDR_LOW(mp->port_num));
addr[0] = (mac_h >> 24) & 0xff; addr[0] = (mac_h >> 24) & 0xff;
addr[1] = (mac_h >> 16) & 0xff; addr[1] = (mac_h >> 16) & 0xff;
...@@ -1070,72 +1091,54 @@ static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr) ...@@ -1070,72 +1091,54 @@ static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr)
static void init_mac_tables(struct mv643xx_eth_private *mp) static void init_mac_tables(struct mv643xx_eth_private *mp)
{ {
unsigned int port_num = mp->port_num; int i;
int table_index;
/* Clear DA filter unicast table (Ex_dFUT) */
for (table_index = 0; table_index <= 0xC; table_index += 4)
wrl(mp, UNICAST_TABLE(port_num) + table_index, 0);
for (table_index = 0; table_index <= 0xFC; table_index += 4) { for (i = 0; i < 0x100; i += 4) {
/* Clear DA filter special multicast table (Ex_dFSMT) */ wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, 0);
wrl(mp, SPECIAL_MCAST_TABLE(port_num) + table_index, 0); wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, 0);
/* Clear DA filter other multicast table (Ex_dFOMT) */
wrl(mp, OTHER_MCAST_TABLE(port_num) + table_index, 0);
} }
for (i = 0; i < 0x10; i += 4)
wrl(mp, UNICAST_TABLE(mp->port_num) + i, 0);
} }
static void set_filter_table_entry(struct mv643xx_eth_private *mp, static void set_filter_table_entry(struct mv643xx_eth_private *mp,
int table, unsigned char entry) int table, unsigned char entry)
{ {
unsigned int table_reg; unsigned int table_reg;
unsigned int tbl_offset;
unsigned int reg_offset;
tbl_offset = (entry / 4) * 4; /* Register offset of DA table entry */
reg_offset = entry % 4; /* Entry offset within the register */
/* Set "accepts frame bit" at specified table entry */ /* Set "accepts frame bit" at specified table entry */
table_reg = rdl(mp, table + tbl_offset); table_reg = rdl(mp, table + (entry & 0xfc));
table_reg |= 0x01 << (8 * reg_offset); table_reg |= 0x01 << (8 * (entry & 3));
wrl(mp, table + tbl_offset, table_reg); wrl(mp, table + (entry & 0xfc), table_reg);
} }
static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr) static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr)
{ {
unsigned int port_num = mp->port_num;
unsigned int mac_h; unsigned int mac_h;
unsigned int mac_l; unsigned int mac_l;
int table; int table;
mac_l = (addr[4] << 8) | (addr[5]); mac_l = (addr[4] << 8) | addr[5];
mac_h = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | mac_h = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
(addr[3] << 0);
wrl(mp, MAC_ADDR_LOW(port_num), mac_l); wrl(mp, MAC_ADDR_LOW(mp->port_num), mac_l);
wrl(mp, MAC_ADDR_HIGH(port_num), mac_h); wrl(mp, MAC_ADDR_HIGH(mp->port_num), mac_h);
/* Accept frames with this address */ table = UNICAST_TABLE(mp->port_num);
table = UNICAST_TABLE(port_num);
set_filter_table_entry(mp, table, addr[5] & 0x0f); set_filter_table_entry(mp, table, addr[5] & 0x0f);
} }
static void mv643xx_eth_update_mac_address(struct net_device *dev) static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr)
{ {
struct mv643xx_eth_private *mp = netdev_priv(dev); struct mv643xx_eth_private *mp = netdev_priv(dev);
/* +2 is for the offset of the HW addr type */
memcpy(dev->dev_addr, addr + 2, 6);
init_mac_tables(mp); init_mac_tables(mp);
uc_addr_set(mp, dev->dev_addr); uc_addr_set(mp, dev->dev_addr);
}
static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr)
{
int i;
for (i = 0; i < 6; i++)
/* +2 is for the offset of the HW addr type */
dev->dev_addr[i] = ((unsigned char *)addr)[i + 2];
mv643xx_eth_update_mac_address(dev);
return 0; return 0;
} }
...@@ -1157,95 +1160,53 @@ static int addr_crc(unsigned char *addr) ...@@ -1157,95 +1160,53 @@ static int addr_crc(unsigned char *addr)
return crc; return crc;
} }
static void mc_addr(struct mv643xx_eth_private *mp, unsigned char *addr) static void mv643xx_eth_set_rx_mode(struct net_device *dev)
{ {
unsigned int port_num = mp->port_num; struct mv643xx_eth_private *mp = netdev_priv(dev);
int table; u32 port_config;
int crc; struct dev_addr_list *addr;
int i;
if ((addr[0] == 0x01) && (addr[1] == 0x00) &&
(addr[2] == 0x5E) && (addr[3] == 0x00) && (addr[4] == 0x00)) {
table = SPECIAL_MCAST_TABLE(port_num);
set_filter_table_entry(mp, table, addr[5]);
return;
}
crc = addr_crc(addr);
table = OTHER_MCAST_TABLE(port_num);
set_filter_table_entry(mp, table, crc);
}
static void set_multicast_list(struct net_device *dev) port_config = rdl(mp, PORT_CONFIG(mp->port_num));
{ if (dev->flags & IFF_PROMISC)
port_config |= UNICAST_PROMISCUOUS_MODE;
else
port_config &= ~UNICAST_PROMISCUOUS_MODE;
wrl(mp, PORT_CONFIG(mp->port_num), port_config);
struct dev_mc_list *mc_list; if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
int i; int port_num = mp->port_num;
int table_index; u32 accept = 0x01010101;
struct mv643xx_eth_private *mp = netdev_priv(dev);
unsigned int port_num = mp->port_num;
/* If the device is in promiscuous mode or in all multicast mode, for (i = 0; i < 0x100; i += 4) {
* we will fully populate both multicast tables with accept. wrl(mp, SPECIAL_MCAST_TABLE(port_num) + i, accept);
* This is guaranteed to yield a match on all multicast addresses... wrl(mp, OTHER_MCAST_TABLE(port_num) + i, accept);
*/
if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI)) {
for (table_index = 0; table_index <= 0xFC; table_index += 4) {
/* Set all entries in DA filter special multicast
* table (Ex_dFSMT)
* Set for ETH_Q0 for now
* Bits
* 0 Accept=1, Drop=0
* 3-1 Queue ETH_Q0=0
* 7-4 Reserved = 0;
*/
wrl(mp, SPECIAL_MCAST_TABLE(port_num) + table_index, 0x01010101);
/* Set all entries in DA filter other multicast
* table (Ex_dFOMT)
* Set for ETH_Q0 for now
* Bits
* 0 Accept=1, Drop=0
* 3-1 Queue ETH_Q0=0
* 7-4 Reserved = 0;
*/
wrl(mp, OTHER_MCAST_TABLE(port_num) + table_index, 0x01010101);
} }
return; return;
} }
/* We will clear out multicast tables every time we get the list. for (i = 0; i < 0x100; i += 4) {
* Then add the entire new list... wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, 0);
*/ wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, 0);
for (table_index = 0; table_index <= 0xFC; table_index += 4) {
/* Clear DA filter special multicast table (Ex_dFSMT) */
wrl(mp, SPECIAL_MCAST_TABLE(port_num) + table_index, 0);
/* Clear DA filter other multicast table (Ex_dFOMT) */
wrl(mp, OTHER_MCAST_TABLE(port_num) + table_index, 0);
} }
/* Get pointer to net_device multicast list and add each one... */ for (addr = dev->mc_list; addr != NULL; addr = addr->next) {
for (i = 0, mc_list = dev->mc_list; u8 *a = addr->da_addr;
(i < 256) && (mc_list != NULL) && (i < dev->mc_count); int table;
i++, mc_list = mc_list->next)
if (mc_list->dmi_addrlen == 6)
mc_addr(mp, mc_list->dmi_addr);
}
static void mv643xx_eth_set_rx_mode(struct net_device *dev) if (addr->da_addrlen != 6)
{ continue;
struct mv643xx_eth_private *mp = netdev_priv(dev);
u32 config_reg;
config_reg = rdl(mp, PORT_CONFIG(mp->port_num)); if (memcmp(a, "\x01\x00\x5e\x00\x00", 5) == 0) {
if (dev->flags & IFF_PROMISC) table = SPECIAL_MCAST_TABLE(mp->port_num);
config_reg |= UNICAST_PROMISCUOUS_MODE; set_filter_table_entry(mp, table, a[5]);
else } else {
config_reg &= ~UNICAST_PROMISCUOUS_MODE; int crc = addr_crc(a);
wrl(mp, PORT_CONFIG(mp->port_num), config_reg);
set_multicast_list(dev); table = OTHER_MCAST_TABLE(mp->port_num);
set_filter_table_entry(mp, table, crc);
}
}
} }
...@@ -1483,10 +1444,7 @@ static void txq_deinit(struct tx_queue *txq) ...@@ -1483,10 +1444,7 @@ static void txq_deinit(struct tx_queue *txq)
/* netdev ops and related ***************************************************/ /* netdev ops and related ***************************************************/
static void port_reset(struct mv643xx_eth_private *mp); static void update_pscr(struct mv643xx_eth_private *mp, int speed, int duplex)
static void mv643xx_eth_update_pscr(struct mv643xx_eth_private *mp,
struct ethtool_cmd *ecmd)
{ {
u32 pscr_o; u32 pscr_o;
u32 pscr_n; u32 pscr_n;
...@@ -1499,15 +1457,15 @@ static void mv643xx_eth_update_pscr(struct mv643xx_eth_private *mp, ...@@ -1499,15 +1457,15 @@ static void mv643xx_eth_update_pscr(struct mv643xx_eth_private *mp,
SET_FULL_DUPLEX_MODE | SET_FULL_DUPLEX_MODE |
MAX_RX_PACKET_MASK); MAX_RX_PACKET_MASK);
if (ecmd->speed == SPEED_1000) { if (speed == SPEED_1000) {
pscr_n |= SET_GMII_SPEED_TO_1000 | MAX_RX_PACKET_9700BYTE; pscr_n |= SET_GMII_SPEED_TO_1000 | MAX_RX_PACKET_9700BYTE;
} else { } else {
if (ecmd->speed == SPEED_100) if (speed == SPEED_100)
pscr_n |= SET_MII_SPEED_TO_100; pscr_n |= SET_MII_SPEED_TO_100;
pscr_n |= MAX_RX_PACKET_1522BYTE; pscr_n |= MAX_RX_PACKET_1522BYTE;
} }
if (ecmd->duplex == DUPLEX_FULL) if (duplex == DUPLEX_FULL)
pscr_n |= SET_FULL_DUPLEX_MODE; pscr_n |= SET_FULL_DUPLEX_MODE;
if (pscr_n != pscr_o) { if (pscr_n != pscr_o) {
...@@ -1524,27 +1482,30 @@ static void mv643xx_eth_update_pscr(struct mv643xx_eth_private *mp, ...@@ -1524,27 +1482,30 @@ static void mv643xx_eth_update_pscr(struct mv643xx_eth_private *mp,
} }
} }
static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id) static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id)
{ {
struct net_device *dev = (struct net_device *)dev_id; struct net_device *dev = (struct net_device *)dev_id;
struct mv643xx_eth_private *mp = netdev_priv(dev); struct mv643xx_eth_private *mp = netdev_priv(dev);
u32 int_cause, int_cause_ext = 0; u32 int_cause;
u32 int_cause_ext;
/* Read interrupt cause registers */
int_cause = rdl(mp, INT_CAUSE(mp->port_num)) & (INT_RX | INT_EXT); int_cause = rdl(mp, INT_CAUSE(mp->port_num)) & (INT_RX | INT_EXT);
if (int_cause == 0)
return IRQ_NONE;
int_cause_ext = 0;
if (int_cause & INT_EXT) { if (int_cause & INT_EXT) {
int_cause_ext = rdl(mp, INT_CAUSE_EXT(mp->port_num)) int_cause_ext = rdl(mp, INT_CAUSE_EXT(mp->port_num))
& (INT_EXT_LINK | INT_EXT_PHY | INT_EXT_TX); & (INT_EXT_LINK | INT_EXT_PHY | INT_EXT_TX);
wrl(mp, INT_CAUSE_EXT(mp->port_num), ~int_cause_ext); wrl(mp, INT_CAUSE_EXT(mp->port_num), ~int_cause_ext);
} }
/* PHY status changed */ if (int_cause_ext & (INT_EXT_PHY | INT_EXT_LINK)) {
if (int_cause_ext & (INT_EXT_LINK | INT_EXT_PHY)) {
if (mii_link_ok(&mp->mii)) { if (mii_link_ok(&mp->mii)) {
struct ethtool_cmd cmd; struct ethtool_cmd cmd;
mii_ethtool_gset(&mp->mii, &cmd); mii_ethtool_gset(&mp->mii, &cmd);
mv643xx_eth_update_pscr(mp, &cmd); update_pscr(mp, cmd.speed, cmd.duplex);
txq_enable(mp->txq); txq_enable(mp->txq);
if (!netif_carrier_ok(dev)) { if (!netif_carrier_ok(dev)) {
netif_carrier_on(dev); netif_carrier_on(dev);
...@@ -1558,10 +1519,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id) ...@@ -1558,10 +1519,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id)
#ifdef MV643XX_ETH_NAPI #ifdef MV643XX_ETH_NAPI
if (int_cause & INT_RX) { if (int_cause & INT_RX) {
/* schedule the NAPI poll routine to maintain port */
wrl(mp, INT_MASK(mp->port_num), 0x00000000); wrl(mp, INT_MASK(mp->port_num), 0x00000000);
/* wait for previous write to complete */
rdl(mp, INT_MASK(mp->port_num)); rdl(mp, INT_MASK(mp->port_num));
netif_rx_schedule(dev, &mp->napi); netif_rx_schedule(dev, &mp->napi);
...@@ -1570,40 +1528,31 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id) ...@@ -1570,40 +1528,31 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id)
if (int_cause & INT_RX) if (int_cause & INT_RX)
rxq_process(mp->rxq, INT_MAX); rxq_process(mp->rxq, INT_MAX);
#endif #endif
if (int_cause_ext & INT_EXT_TX) { if (int_cause_ext & INT_EXT_TX) {
txq_reclaim(mp->txq, 0); txq_reclaim(mp->txq, 0);
__txq_maybe_wake(mp->txq); __txq_maybe_wake(mp->txq);
} }
/*
* If no real interrupt occured, exit.
* This can happen when using gigE interrupt coalescing mechanism.
*/
if ((int_cause == 0x0) && (int_cause_ext == 0x0))
return IRQ_NONE;
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void phy_reset(struct mv643xx_eth_private *mp) static void phy_reset(struct mv643xx_eth_private *mp)
{ {
unsigned int phy_reg_data; unsigned int data;
/* Reset the PHY */ smi_reg_read(mp, mp->phy_addr, 0, &data);
read_smi_reg(mp, 0, &phy_reg_data); data |= 0x8000;
phy_reg_data |= 0x8000; /* Set bit 15 to reset the PHY */ smi_reg_write(mp, mp->phy_addr, 0, data);
write_smi_reg(mp, 0, phy_reg_data);
/* wait for PHY to come out of reset */
do { do {
udelay(1); udelay(1);
read_smi_reg(mp, 0, &phy_reg_data); smi_reg_read(mp, mp->phy_addr, 0, &data);
} while (phy_reg_data & 0x8000); } while (data & 0x8000);
} }
static void port_start(struct net_device *dev) static void port_start(struct mv643xx_eth_private *mp)
{ {
struct mv643xx_eth_private *mp = netdev_priv(dev);
u32 pscr; u32 pscr;
struct ethtool_cmd ethtool_cmd; struct ethtool_cmd ethtool_cmd;
int i; int i;
...@@ -1625,9 +1574,9 @@ static void port_start(struct net_device *dev) ...@@ -1625,9 +1574,9 @@ static void port_start(struct net_device *dev)
wrl(mp, SDMA_CONFIG(mp->port_num), PORT_SDMA_CONFIG_DEFAULT_VALUE); wrl(mp, SDMA_CONFIG(mp->port_num), PORT_SDMA_CONFIG_DEFAULT_VALUE);
mv643xx_eth_get_settings(dev, &ethtool_cmd); mv643xx_eth_get_settings(mp->dev, &ethtool_cmd);
phy_reset(mp); phy_reset(mp);
mv643xx_eth_set_settings(dev, &ethtool_cmd); mv643xx_eth_set_settings(mp->dev, &ethtool_cmd);
/* /*
* Configure TX path and queues. * Configure TX path and queues.
...@@ -1643,8 +1592,10 @@ static void port_start(struct net_device *dev) ...@@ -1643,8 +1592,10 @@ static void port_start(struct net_device *dev)
wrl(mp, off, addr); wrl(mp, off, addr);
} }
/* Add the assigned Ethernet address to the port's address table */ /*
uc_addr_set(mp, dev->dev_addr); * Add configured unicast address to address filter table.
*/
uc_addr_set(mp, mp->dev->dev_addr);
/* /*
* Receive all unmatched unicast, TCP, UDP, BPDU and broadcast * Receive all unmatched unicast, TCP, UDP, BPDU and broadcast
...@@ -1675,13 +1626,14 @@ static void port_start(struct net_device *dev) ...@@ -1675,13 +1626,14 @@ static void port_start(struct net_device *dev)
static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int delay) static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int delay)
{ {
unsigned int port_num = mp->port_num;
unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64; unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64;
/* Set RX Coalescing mechanism */ if (coal > 0x3fff)
wrl(mp, SDMA_CONFIG(port_num), coal = 0x3fff;
wrl(mp, SDMA_CONFIG(mp->port_num),
((coal & 0x3fff) << 8) | ((coal & 0x3fff) << 8) |
(rdl(mp, SDMA_CONFIG(port_num)) (rdl(mp, SDMA_CONFIG(mp->port_num))
& 0xffc000ff)); & 0xffc000ff));
} }
...@@ -1689,68 +1641,59 @@ static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int delay) ...@@ -1689,68 +1641,59 @@ static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int delay)
{ {
unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64; unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64;
/* Set TX Coalescing mechanism */ if (coal > 0x3fff)
wrl(mp, TX_FIFO_URGENT_THRESHOLD(mp->port_num), coal << 4); coal = 0x3fff;
} wrl(mp, TX_FIFO_URGENT_THRESHOLD(mp->port_num), (coal & 0x3fff) << 4);
static void port_init(struct mv643xx_eth_private *mp)
{
port_reset(mp);
init_mac_tables(mp);
} }
static int mv643xx_eth_open(struct net_device *dev) static int mv643xx_eth_open(struct net_device *dev)
{ {
struct mv643xx_eth_private *mp = netdev_priv(dev); struct mv643xx_eth_private *mp = netdev_priv(dev);
unsigned int port_num = mp->port_num;
int err; int err;
/* Clear any pending ethernet port interrupts */ wrl(mp, INT_CAUSE(mp->port_num), 0);
wrl(mp, INT_CAUSE(port_num), 0); wrl(mp, INT_CAUSE_EXT(mp->port_num), 0);
wrl(mp, INT_CAUSE_EXT(port_num), 0); rdl(mp, INT_CAUSE_EXT(mp->port_num));
/* wait for previous write to complete */
rdl(mp, INT_CAUSE_EXT(port_num));
err = request_irq(dev->irq, mv643xx_eth_int_handler, err = request_irq(dev->irq, mv643xx_eth_irq,
IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev); IRQF_SHARED | IRQF_SAMPLE_RANDOM,
dev->name, dev);
if (err) { if (err) {
printk(KERN_ERR "%s: Can not assign IRQ\n", dev->name); dev_printk(KERN_ERR, &dev->dev, "can't assign irq\n");
return -EAGAIN; return -EAGAIN;
} }
port_init(mp); init_mac_tables(mp);
err = rxq_init(mp); err = rxq_init(mp);
if (err) if (err)
goto out_free_irq; goto out;
rxq_refill(mp->rxq); rxq_refill(mp->rxq);
err = txq_init(mp); err = txq_init(mp);
if (err) if (err)
goto out_free_rx_skb; goto out_free;
#ifdef MV643XX_ETH_NAPI #ifdef MV643XX_ETH_NAPI
napi_enable(&mp->napi); napi_enable(&mp->napi);
#endif #endif
port_start(dev); port_start(mp);
set_rx_coal(mp, 0); set_rx_coal(mp, 0);
set_tx_coal(mp, 0); set_tx_coal(mp, 0);
/* Unmask phy and link status changes interrupts */ wrl(mp, INT_MASK_EXT(mp->port_num),
wrl(mp, INT_MASK_EXT(port_num), INT_EXT_LINK | INT_EXT_PHY | INT_EXT_TX); INT_EXT_LINK | INT_EXT_PHY | INT_EXT_TX);
/* Unmask RX buffer and TX end interrupt */ wrl(mp, INT_MASK(mp->port_num), INT_RX | INT_EXT);
wrl(mp, INT_MASK(port_num), INT_RX | INT_EXT);
return 0; return 0;
out_free_rx_skb: out_free:
rxq_deinit(mp->rxq); rxq_deinit(mp->rxq);
out_free_irq: out:
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
return err; return err;
...@@ -1758,34 +1701,27 @@ static int mv643xx_eth_open(struct net_device *dev) ...@@ -1758,34 +1701,27 @@ static int mv643xx_eth_open(struct net_device *dev)
static void port_reset(struct mv643xx_eth_private *mp) static void port_reset(struct mv643xx_eth_private *mp)
{ {
unsigned int port_num = mp->port_num; unsigned int data;
unsigned int reg_data;
txq_disable(mp->txq); txq_disable(mp->txq);
rxq_disable(mp->rxq); rxq_disable(mp->rxq);
while (!(rdl(mp, PORT_STATUS(mp->port_num)) & TX_FIFO_EMPTY)) while (!(rdl(mp, PORT_STATUS(mp->port_num)) & TX_FIFO_EMPTY))
udelay(10); udelay(10);
/* Clear all MIB counters */
clear_mib_counters(mp);
/* Reset the Enable bit in the Configuration Register */ /* Reset the Enable bit in the Configuration Register */
reg_data = rdl(mp, PORT_SERIAL_CONTROL(port_num)); data = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num));
reg_data &= ~(SERIAL_PORT_ENABLE | data &= ~(SERIAL_PORT_ENABLE |
DO_NOT_FORCE_LINK_FAIL | DO_NOT_FORCE_LINK_FAIL |
FORCE_LINK_PASS); FORCE_LINK_PASS);
wrl(mp, PORT_SERIAL_CONTROL(port_num), reg_data); wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), data);
} }
static int mv643xx_eth_stop(struct net_device *dev) static int mv643xx_eth_stop(struct net_device *dev)
{ {
struct mv643xx_eth_private *mp = netdev_priv(dev); struct mv643xx_eth_private *mp = netdev_priv(dev);
unsigned int port_num = mp->port_num;
/* Mask all interrupts on ethernet port */ wrl(mp, INT_MASK(mp->port_num), 0x00000000);
wrl(mp, INT_MASK(port_num), 0x00000000); rdl(mp, INT_MASK(mp->port_num));
/* wait for previous write to complete */
rdl(mp, INT_MASK(port_num));
#ifdef MV643XX_ETH_NAPI #ifdef MV643XX_ETH_NAPI
napi_disable(&mp->napi); napi_disable(&mp->napi);
...@@ -1793,17 +1729,18 @@ static int mv643xx_eth_stop(struct net_device *dev) ...@@ -1793,17 +1729,18 @@ static int mv643xx_eth_stop(struct net_device *dev)
netif_carrier_off(dev); netif_carrier_off(dev);
netif_stop_queue(dev); netif_stop_queue(dev);
free_irq(dev->irq, dev);
port_reset(mp); port_reset(mp);
mib_counters_update(mp);
txq_deinit(mp->txq); txq_deinit(mp->txq);
rxq_deinit(mp->rxq); rxq_deinit(mp->rxq);
free_irq(dev->irq, dev);
return 0; return 0;
} }
static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int mv643xx_eth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{ {
struct mv643xx_eth_private *mp = netdev_priv(dev); struct mv643xx_eth_private *mp = netdev_priv(dev);
...@@ -1812,7 +1749,7 @@ static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int c ...@@ -1812,7 +1749,7 @@ static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int c
static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu)
{ {
if ((new_mtu > 9500) || (new_mtu < 64)) if (new_mtu < 64 || new_mtu > 9500)
return -EINVAL; return -EINVAL;
dev->mtu = new_mtu; dev->mtu = new_mtu;
...@@ -1823,73 +1760,70 @@ static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) ...@@ -1823,73 +1760,70 @@ static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu)
* Stop and then re-open the interface. This will allocate RX * Stop and then re-open the interface. This will allocate RX
* skbs of the new MTU. * skbs of the new MTU.
* There is a possible danger that the open will not succeed, * There is a possible danger that the open will not succeed,
* due to memory being full, which might fail the open function. * due to memory being full.
*/ */
mv643xx_eth_stop(dev); mv643xx_eth_stop(dev);
if (mv643xx_eth_open(dev)) { if (mv643xx_eth_open(dev)) {
printk(KERN_ERR "%s: Fatal error on opening device\n", dev_printk(KERN_ERR, &dev->dev,
dev->name); "fatal error on re-opening device after "
"MTU change\n");
} }
return 0; return 0;
} }
static void mv643xx_eth_tx_timeout_task(struct work_struct *ugly) static void tx_timeout_task(struct work_struct *ugly)
{ {
struct mv643xx_eth_private *mp = container_of(ugly, struct mv643xx_eth_private, struct mv643xx_eth_private *mp;
tx_timeout_task);
struct net_device *dev = mp->dev;
if (!netif_running(dev))
return;
netif_stop_queue(dev); mp = container_of(ugly, struct mv643xx_eth_private, tx_timeout_task);
if (netif_running(mp->dev)) {
netif_stop_queue(mp->dev);
port_reset(mp); port_reset(mp);
port_start(dev); port_start(mp);
__txq_maybe_wake(mp->txq); __txq_maybe_wake(mp->txq);
}
} }
static void mv643xx_eth_tx_timeout(struct net_device *dev) static void mv643xx_eth_tx_timeout(struct net_device *dev)
{ {
struct mv643xx_eth_private *mp = netdev_priv(dev); struct mv643xx_eth_private *mp = netdev_priv(dev);
printk(KERN_INFO "%s: TX timeout ", dev->name); dev_printk(KERN_INFO, &dev->dev, "tx timeout\n");
/* Do the reset outside of interrupt context */
schedule_work(&mp->tx_timeout_task); schedule_work(&mp->tx_timeout_task);
} }
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
static void mv643xx_eth_netpoll(struct net_device *netdev) static void mv643xx_eth_netpoll(struct net_device *dev)
{ {
struct mv643xx_eth_private *mp = netdev_priv(netdev); struct mv643xx_eth_private *mp = netdev_priv(dev);
int port_num = mp->port_num;
wrl(mp, INT_MASK(port_num), 0x00000000); wrl(mp, INT_MASK(mp->port_num), 0x00000000);
/* wait for previous write to complete */ rdl(mp, INT_MASK(mp->port_num));
rdl(mp, INT_MASK(port_num));
mv643xx_eth_int_handler(netdev->irq, netdev); mv643xx_eth_irq(dev->irq, dev);
wrl(mp, INT_MASK(port_num), INT_RX | INT_CAUSE_EXT); wrl(mp, INT_MASK(mp->port_num), INT_RX | INT_CAUSE_EXT);
} }
#endif #endif
static int mv643xx_eth_mdio_read(struct net_device *dev, int phy_id, int location) static int mv643xx_eth_mdio_read(struct net_device *dev, int addr, int reg)
{ {
struct mv643xx_eth_private *mp = netdev_priv(dev); struct mv643xx_eth_private *mp = netdev_priv(dev);
int val; int val;
read_smi_reg(mp, location, &val); smi_reg_read(mp, addr, reg, &val);
return val; return val;
} }
static void mv643xx_eth_mdio_write(struct net_device *dev, int phy_id, int location, int val) static void mv643xx_eth_mdio_write(struct net_device *dev, int addr, int reg, int val)
{ {
struct mv643xx_eth_private *mp = netdev_priv(dev); struct mv643xx_eth_private *mp = netdev_priv(dev);
write_smi_reg(mp, location, val); smi_reg_write(mp, addr, reg, val);
} }
...@@ -1956,9 +1890,6 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) ...@@ -1956,9 +1890,6 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
goto out_free; goto out_free;
spin_lock_init(&msp->phy_lock); spin_lock_init(&msp->phy_lock);
msp->t_clk = (pd != NULL && pd->t_clk != 0) ? pd->t_clk : 133000000;
platform_set_drvdata(pdev, msp);
/* /*
* (Re-)program MBUS remapping windows if we are asked to. * (Re-)program MBUS remapping windows if we are asked to.
...@@ -1966,6 +1897,13 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) ...@@ -1966,6 +1897,13 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
if (pd != NULL && pd->dram != NULL) if (pd != NULL && pd->dram != NULL)
mv643xx_eth_conf_mbus_windows(msp, pd->dram); mv643xx_eth_conf_mbus_windows(msp, pd->dram);
/*
* Detect hardware parameters.
*/
msp->t_clk = (pd != NULL && pd->t_clk != 0) ? pd->t_clk : 133000000;
platform_set_drvdata(pdev, msp);
return 0; return 0;
out_free: out_free:
...@@ -1995,94 +1933,148 @@ static struct platform_driver mv643xx_eth_shared_driver = { ...@@ -1995,94 +1933,148 @@ static struct platform_driver mv643xx_eth_shared_driver = {
static void phy_addr_set(struct mv643xx_eth_private *mp, int phy_addr) static void phy_addr_set(struct mv643xx_eth_private *mp, int phy_addr)
{ {
u32 reg_data;
int addr_shift = 5 * mp->port_num; int addr_shift = 5 * mp->port_num;
u32 data;
reg_data = rdl(mp, PHY_ADDR); data = rdl(mp, PHY_ADDR);
reg_data &= ~(0x1f << addr_shift); data &= ~(0x1f << addr_shift);
reg_data |= (phy_addr & 0x1f) << addr_shift; data |= (phy_addr & 0x1f) << addr_shift;
wrl(mp, PHY_ADDR, reg_data); wrl(mp, PHY_ADDR, data);
} }
static int phy_addr_get(struct mv643xx_eth_private *mp) static int phy_addr_get(struct mv643xx_eth_private *mp)
{ {
unsigned int reg_data; unsigned int data;
reg_data = rdl(mp, PHY_ADDR); data = rdl(mp, PHY_ADDR);
return (data >> (5 * mp->port_num)) & 0x1f;
}
return ((reg_data >> (5 * mp->port_num)) & 0x1f); static void set_params(struct mv643xx_eth_private *mp,
struct mv643xx_eth_platform_data *pd)
{
struct net_device *dev = mp->dev;
if (is_valid_ether_addr(pd->mac_addr))
memcpy(dev->dev_addr, pd->mac_addr, 6);
else
uc_addr_get(mp, dev->dev_addr);
if (pd->phy_addr == -1) {
mp->shared_smi = NULL;
mp->phy_addr = -1;
} else {
mp->shared_smi = mp->shared;
if (pd->shared_smi != NULL)
mp->shared_smi = platform_get_drvdata(pd->shared_smi);
if (pd->force_phy_addr || pd->phy_addr) {
mp->phy_addr = pd->phy_addr & 0x3f;
phy_addr_set(mp, mp->phy_addr);
} else {
mp->phy_addr = phy_addr_get(mp);
}
}
mp->default_rx_ring_size = DEFAULT_RX_QUEUE_SIZE;
if (pd->rx_queue_size)
mp->default_rx_ring_size = pd->rx_queue_size;
mp->rx_desc_sram_addr = pd->rx_sram_addr;
mp->rx_desc_sram_size = pd->rx_sram_size;
mp->default_tx_ring_size = DEFAULT_TX_QUEUE_SIZE;
if (pd->tx_queue_size)
mp->default_tx_ring_size = pd->tx_queue_size;
mp->tx_desc_sram_addr = pd->tx_sram_addr;
mp->tx_desc_sram_size = pd->tx_sram_size;
} }
static int phy_detect(struct mv643xx_eth_private *mp) static int phy_detect(struct mv643xx_eth_private *mp)
{ {
unsigned int phy_reg_data0; unsigned int data;
int auto_neg; unsigned int data2;
smi_reg_read(mp, mp->phy_addr, 0, &data);
smi_reg_write(mp, mp->phy_addr, 0, data ^ 0x1000);
read_smi_reg(mp, 0, &phy_reg_data0); smi_reg_read(mp, mp->phy_addr, 0, &data2);
auto_neg = phy_reg_data0 & 0x1000; if (((data ^ data2) & 0x1000) == 0)
phy_reg_data0 ^= 0x1000; /* invert auto_neg */ return -ENODEV;
write_smi_reg(mp, 0, phy_reg_data0);
read_smi_reg(mp, 0, &phy_reg_data0); smi_reg_write(mp, mp->phy_addr, 0, data);
if ((phy_reg_data0 & 0x1000) == auto_neg)
return -ENODEV; /* change didn't take */
phy_reg_data0 ^= 0x1000;
write_smi_reg(mp, 0, phy_reg_data0);
return 0; return 0;
} }
static void mv643xx_init_ethtool_cmd(struct net_device *dev, int phy_address, static int phy_init(struct mv643xx_eth_private *mp,
int speed, int duplex, struct mv643xx_eth_platform_data *pd)
struct ethtool_cmd *cmd)
{ {
struct mv643xx_eth_private *mp = netdev_priv(dev); struct ethtool_cmd cmd;
int err;
memset(cmd, 0, sizeof(*cmd)); err = phy_detect(mp);
if (err) {
dev_printk(KERN_INFO, &mp->dev->dev,
"no PHY detected at addr %d\n", mp->phy_addr);
return err;
}
phy_reset(mp);
cmd->port = PORT_MII; mp->mii.phy_id = mp->phy_addr;
cmd->transceiver = XCVR_INTERNAL; mp->mii.phy_id_mask = 0x3f;
cmd->phy_address = phy_address; mp->mii.reg_num_mask = 0x1f;
mp->mii.dev = mp->dev;
mp->mii.mdio_read = mv643xx_eth_mdio_read;
mp->mii.mdio_write = mv643xx_eth_mdio_write;
if (speed == 0) { mp->mii.supports_gmii = mii_check_gmii_support(&mp->mii);
cmd->autoneg = AUTONEG_ENABLE;
/* mii lib checks, but doesn't use speed on AUTONEG_ENABLE */ memset(&cmd, 0, sizeof(cmd));
cmd->speed = SPEED_100;
cmd->advertising = ADVERTISED_10baseT_Half | cmd.port = PORT_MII;
cmd.transceiver = XCVR_INTERNAL;
cmd.phy_address = mp->phy_addr;
if (pd->speed == 0) {
cmd.autoneg = AUTONEG_ENABLE;
cmd.speed = SPEED_100;
cmd.advertising = ADVERTISED_10baseT_Half |
ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Full |
ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Half |
ADVERTISED_100baseT_Full; ADVERTISED_100baseT_Full;
if (mp->mii.supports_gmii) if (mp->mii.supports_gmii)
cmd->advertising |= ADVERTISED_1000baseT_Full; cmd.advertising |= ADVERTISED_1000baseT_Full;
} else { } else {
cmd->autoneg = AUTONEG_DISABLE; cmd.autoneg = AUTONEG_DISABLE;
cmd->speed = speed; cmd.speed = pd->speed;
cmd->duplex = duplex; cmd.duplex = pd->duplex;
} }
update_pscr(mp, cmd.speed, cmd.duplex);
mv643xx_eth_set_settings(mp->dev, &cmd);
return 0;
} }
static int mv643xx_eth_probe(struct platform_device *pdev) static int mv643xx_eth_probe(struct platform_device *pdev)
{ {
struct mv643xx_eth_platform_data *pd; struct mv643xx_eth_platform_data *pd;
int port_num;
struct mv643xx_eth_private *mp; struct mv643xx_eth_private *mp;
struct net_device *dev; struct net_device *dev;
u8 *p;
struct resource *res; struct resource *res;
int err;
struct ethtool_cmd cmd;
int duplex = DUPLEX_HALF;
int speed = 0; /* default to auto-negotiation */
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
int err;
pd = pdev->dev.platform_data; pd = pdev->dev.platform_data;
if (pd == NULL) { if (pd == NULL) {
printk(KERN_ERR "No mv643xx_eth_platform_data\n"); dev_printk(KERN_ERR, &pdev->dev,
"no mv643xx_eth_platform_data\n");
return -ENODEV; return -ENODEV;
} }
if (pd->shared == NULL) { if (pd->shared == NULL) {
printk(KERN_ERR "No mv643xx_eth_platform_data->shared\n"); dev_printk(KERN_ERR, &pdev->dev,
"no mv643xx_eth_platform_data->shared\n");
return -ENODEV; return -ENODEV;
} }
...@@ -2090,145 +2082,80 @@ static int mv643xx_eth_probe(struct platform_device *pdev) ...@@ -2090,145 +2082,80 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
if (!dev) if (!dev)
return -ENOMEM; return -ENOMEM;
platform_set_drvdata(pdev, dev);
mp = netdev_priv(dev); mp = netdev_priv(dev);
platform_set_drvdata(pdev, mp);
mp->shared = platform_get_drvdata(pd->shared);
mp->port_num = pd->port_number;
mp->dev = dev; mp->dev = dev;
#ifdef MV643XX_ETH_NAPI #ifdef MV643XX_ETH_NAPI
netif_napi_add(dev, &mp->napi, mv643xx_eth_poll, 64); netif_napi_add(dev, &mp->napi, mv643xx_eth_poll, 64);
#endif #endif
set_params(mp, pd);
spin_lock_init(&mp->lock);
mib_counters_clear(mp);
INIT_WORK(&mp->tx_timeout_task, tx_timeout_task);
err = phy_init(mp, pd);
if (err)
goto out;
SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
BUG_ON(!res); BUG_ON(!res);
dev->irq = res->start; dev->irq = res->start;
dev->hard_start_xmit = mv643xx_eth_xmit;
dev->open = mv643xx_eth_open; dev->open = mv643xx_eth_open;
dev->stop = mv643xx_eth_stop; dev->stop = mv643xx_eth_stop;
dev->hard_start_xmit = mv643xx_eth_start_xmit;
dev->set_mac_address = mv643xx_eth_set_mac_address;
dev->set_multicast_list = mv643xx_eth_set_rx_mode; dev->set_multicast_list = mv643xx_eth_set_rx_mode;
dev->set_mac_address = mv643xx_eth_set_mac_address;
/* No need to Tx Timeout */ dev->do_ioctl = mv643xx_eth_ioctl;
dev->change_mtu = mv643xx_eth_change_mtu;
dev->tx_timeout = mv643xx_eth_tx_timeout; dev->tx_timeout = mv643xx_eth_tx_timeout;
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = mv643xx_eth_netpoll; dev->poll_controller = mv643xx_eth_netpoll;
#endif #endif
dev->watchdog_timeo = 2 * HZ; dev->watchdog_timeo = 2 * HZ;
dev->base_addr = 0; dev->base_addr = 0;
dev->change_mtu = mv643xx_eth_change_mtu;
dev->do_ioctl = mv643xx_eth_do_ioctl;
SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops);
#ifdef MV643XX_ETH_CHECKSUM_OFFLOAD_TX #ifdef MV643XX_ETH_CHECKSUM_OFFLOAD_TX
#ifdef MAX_SKB_FRAGS
/* /*
* Zero copy can only work if we use Discovery II memory. Else, we will * Zero copy can only work if we use Discovery II memory. Else, we will
* have to map the buffers to ISA memory which is only 16 MB * have to map the buffers to ISA memory which is only 16 MB
*/ */
dev->features = NETIF_F_SG | NETIF_F_IP_CSUM; dev->features = NETIF_F_SG | NETIF_F_IP_CSUM;
#endif
#endif #endif
/* Configure the timeout task */ SET_NETDEV_DEV(dev, &pdev->dev);
INIT_WORK(&mp->tx_timeout_task, mv643xx_eth_tx_timeout_task);
spin_lock_init(&mp->lock);
mp->shared = platform_get_drvdata(pd->shared);
port_num = mp->port_num = pd->port_number;
if (mp->shared->win_protect) if (mp->shared->win_protect)
wrl(mp, WINDOW_PROTECT(port_num), mp->shared->win_protect); wrl(mp, WINDOW_PROTECT(mp->port_num), mp->shared->win_protect);
mp->shared_smi = mp->shared;
if (pd->shared_smi != NULL)
mp->shared_smi = platform_get_drvdata(pd->shared_smi);
/* set default config values */
uc_addr_get(mp, dev->dev_addr);
if (is_valid_ether_addr(pd->mac_addr))
memcpy(dev->dev_addr, pd->mac_addr, 6);
if (pd->phy_addr || pd->force_phy_addr)
phy_addr_set(mp, pd->phy_addr);
mp->default_rx_ring_size = DEFAULT_RX_QUEUE_SIZE;
if (pd->rx_queue_size)
mp->default_rx_ring_size = pd->rx_queue_size;
mp->default_tx_ring_size = DEFAULT_TX_QUEUE_SIZE;
if (pd->tx_queue_size)
mp->default_tx_ring_size = pd->tx_queue_size;
if (pd->tx_sram_size) {
mp->tx_desc_sram_size = pd->tx_sram_size;
mp->tx_desc_sram_addr = pd->tx_sram_addr;
}
if (pd->rx_sram_size) {
mp->rx_desc_sram_addr = pd->rx_sram_addr;
mp->rx_desc_sram_size = pd->rx_sram_size;
}
duplex = pd->duplex;
speed = pd->speed;
/* Hook up MII support for ethtool */
mp->mii.dev = dev;
mp->mii.mdio_read = mv643xx_eth_mdio_read;
mp->mii.mdio_write = mv643xx_eth_mdio_write;
mp->mii.phy_id = phy_addr_get(mp);
mp->mii.phy_id_mask = 0x3f;
mp->mii.reg_num_mask = 0x1f;
err = phy_detect(mp);
if (err) {
pr_debug("%s: No PHY detected at addr %d\n",
dev->name, phy_addr_get(mp));
goto out;
}
phy_reset(mp);
mp->mii.supports_gmii = mii_check_gmii_support(&mp->mii);
mv643xx_init_ethtool_cmd(dev, mp->mii.phy_id, speed, duplex, &cmd);
mv643xx_eth_update_pscr(mp, &cmd);
mv643xx_eth_set_settings(dev, &cmd);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_netdev(dev); err = register_netdev(dev);
if (err) if (err)
goto out; goto out;
p = dev->dev_addr; dev_printk(KERN_NOTICE, &dev->dev, "port %d with MAC address %s\n",
printk(KERN_NOTICE mp->port_num, print_mac(mac, dev->dev_addr));
"%s: port %d with MAC address %s\n",
dev->name, port_num, print_mac(mac, p));
if (dev->features & NETIF_F_SG) if (dev->features & NETIF_F_SG)
printk(KERN_NOTICE "%s: Scatter Gather Enabled\n", dev->name); dev_printk(KERN_NOTICE, &dev->dev, "scatter/gather enabled\n");
if (dev->features & NETIF_F_IP_CSUM) if (dev->features & NETIF_F_IP_CSUM)
printk(KERN_NOTICE "%s: TX TCP/IP Checksumming Supported\n", dev_printk(KERN_NOTICE, &dev->dev, "tx checksum offload\n");
dev->name);
#ifdef MV643XX_ETH_CHECKSUM_OFFLOAD_TX
printk(KERN_NOTICE "%s: RX TCP/UDP Checksum Offload ON \n", dev->name);
#endif
#ifdef MV643XX_ETH_COAL
printk(KERN_NOTICE "%s: TX and RX Interrupt Coalescing ON \n",
dev->name);
#endif
#ifdef MV643XX_ETH_NAPI #ifdef MV643XX_ETH_NAPI
printk(KERN_NOTICE "%s: RX NAPI Enabled \n", dev->name); dev_printk(KERN_NOTICE, &dev->dev, "napi enabled\n");
#endif #endif
if (mp->tx_desc_sram_size > 0) if (mp->tx_desc_sram_size > 0)
printk(KERN_NOTICE "%s: Using SRAM\n", dev->name); dev_printk(KERN_NOTICE, &dev->dev, "configured with sram\n");
return 0; return 0;
...@@ -2240,26 +2167,26 @@ static int mv643xx_eth_probe(struct platform_device *pdev) ...@@ -2240,26 +2167,26 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
static int mv643xx_eth_remove(struct platform_device *pdev) static int mv643xx_eth_remove(struct platform_device *pdev)
{ {
struct net_device *dev = platform_get_drvdata(pdev); struct mv643xx_eth_private *mp = platform_get_drvdata(pdev);
unregister_netdev(dev); unregister_netdev(mp->dev);
flush_scheduled_work(); flush_scheduled_work();
free_netdev(mp->dev);
free_netdev(dev);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
return 0; return 0;
} }
static void mv643xx_eth_shutdown(struct platform_device *pdev) static void mv643xx_eth_shutdown(struct platform_device *pdev)
{ {
struct net_device *dev = platform_get_drvdata(pdev); struct mv643xx_eth_private *mp = platform_get_drvdata(pdev);
struct mv643xx_eth_private *mp = netdev_priv(dev);
unsigned int port_num = mp->port_num;
/* Mask all interrupts on ethernet port */ /* Mask all interrupts on ethernet port */
wrl(mp, INT_MASK(port_num), 0); wrl(mp, INT_MASK(mp->port_num), 0);
rdl(mp, INT_MASK(port_num)); rdl(mp, INT_MASK(mp->port_num));
if (netif_running(mp->dev))
port_reset(mp); port_reset(mp);
} }
...@@ -2283,21 +2210,21 @@ static int __init mv643xx_eth_init_module(void) ...@@ -2283,21 +2210,21 @@ static int __init mv643xx_eth_init_module(void)
if (rc) if (rc)
platform_driver_unregister(&mv643xx_eth_shared_driver); platform_driver_unregister(&mv643xx_eth_shared_driver);
} }
return rc; return rc;
} }
module_init(mv643xx_eth_init_module);
static void __exit mv643xx_eth_cleanup_module(void) static void __exit mv643xx_eth_cleanup_module(void)
{ {
platform_driver_unregister(&mv643xx_eth_driver); platform_driver_unregister(&mv643xx_eth_driver);
platform_driver_unregister(&mv643xx_eth_shared_driver); platform_driver_unregister(&mv643xx_eth_shared_driver);
} }
module_init(mv643xx_eth_init_module);
module_exit(mv643xx_eth_cleanup_module); module_exit(mv643xx_eth_cleanup_module);
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Rabeeh Khoury, Assaf Hoffman, Matthew Dharm, Manish Lachwani "
MODULE_AUTHOR( "Rabeeh Khoury, Assaf Hoffman, Matthew Dharm, Manish Lachwani" "and Dale Farnsworth");
" and Dale Farnsworth");
MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX"); MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX");
MODULE_ALIAS("platform:" MV643XX_ETH_NAME); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" MV643XX_ETH_SHARED_NAME); MODULE_ALIAS("platform:" MV643XX_ETH_SHARED_NAME);
MODULE_ALIAS("platform:" MV643XX_ETH_NAME);
...@@ -21,26 +21,49 @@ struct mv643xx_eth_shared_platform_data { ...@@ -21,26 +21,49 @@ struct mv643xx_eth_shared_platform_data {
}; };
struct mv643xx_eth_platform_data { struct mv643xx_eth_platform_data {
/*
* Pointer back to our parent instance, and our port number.
*/
struct platform_device *shared; struct platform_device *shared;
int port_number; int port_number;
/*
* Whether a PHY is present, and if yes, at which address.
*/
struct platform_device *shared_smi; struct platform_device *shared_smi;
int force_phy_addr;
int phy_addr;
/*
* Use this MAC address if it is valid, overriding the
* address that is already in the hardware.
*/
u8 mac_addr[6];
/*
* If speed is 0, autonegotiation is enabled.
* Valid values for speed: 0, SPEED_10, SPEED_100, SPEED_1000.
* Valid values for duplex: DUPLEX_HALF, DUPLEX_FULL.
*/
int speed;
int duplex;
/*
* Override default RX/TX queue sizes if nonzero.
*/
int rx_queue_size;
int tx_queue_size;
u16 force_phy_addr; /* force override if phy_addr == 0 */ /*
u16 phy_addr; * Use on-chip SRAM for RX/TX descriptors if size is nonzero
* and sufficient to contain all descriptors for the requested
/* If speed is 0, then speed and duplex are autonegotiated. */ * ring sizes.
int speed; /* 0, SPEED_10, SPEED_100, SPEED_1000 */ */
int duplex; /* DUPLEX_HALF or DUPLEX_FULL */ unsigned long rx_sram_addr;
int rx_sram_size;
/* non-zero values of the following fields override defaults */ unsigned long tx_sram_addr;
u32 tx_queue_size; int tx_sram_size;
u32 rx_queue_size;
u32 tx_sram_addr;
u32 tx_sram_size;
u32 rx_sram_addr;
u32 rx_sram_size;
u8 mac_addr[6]; /* mac address if non-zero*/
}; };
#endif /* __LINUX_MV643XX_ETH_H */
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment