/*
* Aeroflex Gaisler GRETH 10/100/1G Ethernet MAC.
*
* 2005-2009 (c) Aeroflex Gaisler AB
*
* This driver supports GRETH 10/100 and GRETH 10/100/1G Ethernet MACs
* available in the GRLIB VHDL IP core library.
*
* Full documentation of both cores can be found here:
* http://www.gaisler.com/products/grlib/grip.pdf
*
* The Gigabit version supports scatter/gather DMA, any alignment of
* buffers and checksum offloading.
*
* 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.
*
* Contributors: Kristoffer Glembo
* Daniel Hellstrom
* Marko Isomaki
*/
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/skbuff.h>
#include <linux/io.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
#include <asm/cacheflush.h>
#include <asm/byteorder.h>
#ifdef CONFIG_SPARC
#include <asm/idprom.h>
#endif
#include "greth.h"
#define GRETH_DEF_MSG_ENABLE \
(NETIF_MSG_DRV | \
NETIF_MSG_PROBE | \
NETIF_MSG_LINK | \
NETIF_MSG_IFDOWN | \
NETIF_MSG_IFUP | \
NETIF_MSG_RX_ERR | \
NETIF_MSG_TX_ERR)
static int greth_debug = -1; /* -1 == use GRETH_DEF_MSG_ENABLE as value */
module_param(greth_debug, int, 0);
MODULE_PARM_DESC(greth_debug, "GRETH bitmapped debugging message enable value");
/* Accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */
static int macaddr[6];
module_param_array(macaddr, int, NULL, 0);
MODULE_PARM_DESC(macaddr, "GRETH Ethernet MAC address");
static int greth_edcl = 1;
module_param(greth_edcl, int, 0);
MODULE_PARM_DESC(greth_edcl, "GRETH EDCL usage indicator. Set to 1 if EDCL is used.");
static int greth_open(struct net_device *dev);
static netdev_tx_t greth_start_xmit(struct sk_buff *skb,
struct net_device *dev);
static netdev_tx_t greth_start_xmit_gbit(struct sk_buff *skb,
struct net_device *dev);
static int greth_rx(struct net_device *dev, int limit);
static int greth_rx_gbit(struct net_device *dev, int limit);
static void greth_clean_tx(struct net_device *dev);
static void greth_clean_tx_gbit(struct net_device *dev);
static irqreturn_t greth_interrupt(int irq, void *dev_id);
static int greth_close(struct net_device *dev);
static int greth_set_mac_add(struct net_device *dev, void *p);
static void greth_set_multicast_list(struct net_device *dev);
#define GRETH_REGLOAD(a) (be32_to_cpu(__raw_readl(&(a))))
#define GRETH_REGSAVE(a, v) (__raw_writel(cpu_to_be32(v), &(a)))
#define GRETH_REGORIN(a, v) (GRETH_REGSAVE(a, (GRETH_REGLOAD(a) | (v))))
#define GRETH_REGANDIN(a, v) (GRETH_REGSAVE(a, (GRETH_REGLOAD(a) & (v))))
#define NEXT_TX(N) (((N) + 1) & GRETH_TXBD_NUM_MASK)
#define SKIP_TX(N, C) (((N) + C) & GRETH_TXBD_NUM_MASK)
#define NEXT_RX(N) (((N) + 1) & GRETH_RXBD_NUM_MASK)
static void greth_print_rx_packet(void *addr, int len)
{
print_hex_dump(KERN_DEBUG, "RX: ", DUMP_PREFIX_OFFSET, 16, 1,
addr, len, true);
}
static void greth_print_tx_packet(struct sk_buff *skb)
{
int i;
int length;
if (skb_shinfo(skb)->nr_frags == 0)
length = skb->len;
else
length = skb_headlen(skb);
print_hex_dump(KERN_DEBUG, "TX: ", DUMP_PREFIX_OFFSET, 16, 1,
skb->data, length, true);
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
print_hex_dump(KERN_DEBUG, "TX: ", DUMP_PREFIX_OFFSET, 16, 1,
phys_to_virt(page_to_phys(skb_shinfo(skb)
|