#include <linux/bitops.h>
#include <linux/crc32.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/fcntl.h>
#include <linux/in.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/mii.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/random.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <asm/byteorder.h>
#include <asm/dma.h>
#include <asm/irq.h>
#ifdef CONFIG_SPARC
#include <asm/auxio.h>
#include <asm/idprom.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#endif
#include "sunhme.h"
#define DRV_NAME …
MODULE_AUTHOR(…) …;
MODULE_DESCRIPTION(…) …;
MODULE_LICENSE(…) …;
static int macaddr[6];
module_param_array(…);
MODULE_PARM_DESC(…) …;
#ifdef CONFIG_SBUS
static struct quattro *qfe_sbus_list;
#endif
#ifdef CONFIG_PCI
static struct quattro *qfe_pci_list;
#endif
#define hme_debug(fmt, ...) …
#define HMD …
#if 1
#define ASD …
#else
#define ASD …
#endif
#if 0
struct hme_tx_logent {
unsigned int tstamp;
int tx_new, tx_old;
unsigned int action;
#define TXLOG_ACTION_IRQ …
#define TXLOG_ACTION_TXMIT …
#define TXLOG_ACTION_TBUSY …
#define TXLOG_ACTION_NBUFS …
unsigned int status;
};
#define TX_LOG_LEN …
static struct hme_tx_logent tx_log[TX_LOG_LEN];
static int txlog_cur_entry;
static __inline__ void tx_add_log(struct happy_meal *hp, unsigned int a, unsigned int s)
{
struct hme_tx_logent *tlp;
unsigned long flags;
local_irq_save(flags);
tlp = &tx_log[txlog_cur_entry];
tlp->tstamp = (unsigned int)jiffies;
tlp->tx_new = hp->tx_new;
tlp->tx_old = hp->tx_old;
tlp->action = a;
tlp->status = s;
txlog_cur_entry = (txlog_cur_entry + 1) & (TX_LOG_LEN - 1);
local_irq_restore(flags);
}
static __inline__ void tx_dump_log(void)
{
int i, this;
this = txlog_cur_entry;
for (i = 0; i < TX_LOG_LEN; i++) {
pr_err("TXLOG[%d]: j[%08x] tx[N(%d)O(%d)] action[%08x] stat[%08x]\n", i,
tx_log[this].tstamp,
tx_log[this].tx_new, tx_log[this].tx_old,
tx_log[this].action, tx_log[this].status);
this = (this + 1) & (TX_LOG_LEN - 1);
}
}
#else
#define tx_add_log(hp, a, s) …
#define tx_dump_log() …
#endif
#define DEFAULT_IPG0 …
#define DEFAULT_IPG1 …
#define DEFAULT_IPG2 …
#define DEFAULT_JAMSIZE …
#if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
static void sbus_hme_write32(void __iomem *reg, u32 val)
{
sbus_writel(val, reg);
}
static u32 sbus_hme_read32(void __iomem *reg)
{
return sbus_readl(reg);
}
static void sbus_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr)
{
rxd->rx_addr = (__force hme32)addr;
dma_wmb();
rxd->rx_flags = (__force hme32)flags;
}
static void sbus_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr)
{
txd->tx_addr = (__force hme32)addr;
dma_wmb();
txd->tx_flags = (__force hme32)flags;
}
static u32 sbus_hme_read_desc32(hme32 *p)
{
return (__force u32)*p;
}
static void pci_hme_write32(void __iomem *reg, u32 val)
{
writel(val, reg);
}
static u32 pci_hme_read32(void __iomem *reg)
{
return readl(reg);
}
static void pci_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr)
{
rxd->rx_addr = (__force hme32)cpu_to_le32(addr);
dma_wmb();
rxd->rx_flags = (__force hme32)cpu_to_le32(flags);
}
static void pci_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr)
{
txd->tx_addr = (__force hme32)cpu_to_le32(addr);
dma_wmb();
txd->tx_flags = (__force hme32)cpu_to_le32(flags);
}
static u32 pci_hme_read_desc32(hme32 *p)
{
return le32_to_cpup((__le32 *)p);
}
#define hme_write32 …
#define hme_read32 …
#define hme_write_rxd …
#define hme_write_txd …
#define hme_read_desc32 …
#else
#ifdef CONFIG_SBUS
#define hme_write32 …
#define hme_read32 …
#define hme_write_rxd …
#define hme_write_txd …
#define hme_read_desc32 …
#else
#define hme_write32(__hp, __reg, __val) …
#define hme_read32(__hp, __reg) …
#define hme_write_rxd(__hp, __rxd, __flags, __addr) …
#define hme_write_txd(__hp, __txd, __flags, __addr) …
static inline u32 hme_read_desc32(struct happy_meal *hp, hme32 *p)
{ … }
#endif
#endif
static void BB_PUT_BIT(struct happy_meal *hp, void __iomem *tregs, int bit)
{ … }
#if 0
static u32 BB_GET_BIT(struct happy_meal *hp, void __iomem *tregs, int internal)
{
u32 ret;
hme_write32(hp, tregs + TCVR_BBCLOCK, 0);
hme_write32(hp, tregs + TCVR_BBCLOCK, 1);
ret = hme_read32(hp, tregs + TCVR_CFG);
if (internal)
ret &= TCV_CFG_MDIO0;
else
ret &= TCV_CFG_MDIO1;
return ret;
}
#endif
static u32 BB_GET_BIT2(struct happy_meal *hp, void __iomem *tregs, int internal)
{ … }
#define TCVR_FAILURE …
static int happy_meal_bb_read(struct happy_meal *hp,
void __iomem *tregs, int reg)
{ … }
static void happy_meal_bb_write(struct happy_meal *hp,
void __iomem *tregs, int reg,
unsigned short value)
{ … }
#define TCVR_READ_TRIES …
static int happy_meal_tcvr_read(struct happy_meal *hp,
void __iomem *tregs, int reg)
{ … }
#define TCVR_WRITE_TRIES …
static void happy_meal_tcvr_write(struct happy_meal *hp,
void __iomem *tregs, int reg,
unsigned short value)
{ … }
static int try_next_permutation(struct happy_meal *hp, void __iomem *tregs)
{ … }
static void display_link_mode(struct happy_meal *hp, void __iomem *tregs)
{ … }
static void display_forced_link_mode(struct happy_meal *hp, void __iomem *tregs)
{ … }
static int set_happy_link_modes(struct happy_meal *hp, void __iomem *tregs)
{ … }
static int is_lucent_phy(struct happy_meal *hp)
{ … }
static void
happy_meal_begin_auto_negotiation(struct happy_meal *hp,
void __iomem *tregs,
const struct ethtool_link_ksettings *ep)
{ … }
static void happy_meal_timer(struct timer_list *t)
{ … }
#define TX_RESET_TRIES …
#define RX_RESET_TRIES …
static void happy_meal_tx_reset(struct happy_meal *hp, void __iomem *bregs)
{ … }
static void happy_meal_rx_reset(struct happy_meal *hp, void __iomem *bregs)
{ … }
#define STOP_TRIES …
static void happy_meal_stop(struct happy_meal *hp, void __iomem *gregs)
{ … }
static void happy_meal_get_counters(struct happy_meal *hp, void __iomem *bregs)
{ … }
#define TCVR_RESET_TRIES …
#define TCVR_UNISOLATE_TRIES …
static int happy_meal_tcvr_reset(struct happy_meal *hp, void __iomem *tregs)
{ … }
static void happy_meal_transceiver_check(struct happy_meal *hp, void __iomem *tregs)
{ … }
static void happy_meal_clean_rings(struct happy_meal *hp)
{ … }
static void happy_meal_init_rings(struct happy_meal *hp)
{ … }
static int happy_meal_init(struct happy_meal *hp)
{ … }
static void happy_meal_set_initial_advertisement(struct happy_meal *hp)
{ … }
static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status)
{ … }
static void happy_meal_tx(struct happy_meal *hp)
{ … }
static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
{ … }
static irqreturn_t happy_meal_interrupt(int irq, void *dev_id)
{ … }
static int happy_meal_open(struct net_device *dev)
{ … }
static int happy_meal_close(struct net_device *dev)
{ … }
static void happy_meal_tx_timeout(struct net_device *dev, unsigned int txqueue)
{ … }
static void unmap_partial_tx_skb(struct happy_meal *hp, u32 first_mapping,
u32 first_len, u32 first_entry, u32 entry)
{ … }
static netdev_tx_t happy_meal_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{ … }
static struct net_device_stats *happy_meal_get_stats(struct net_device *dev)
{ … }
static void happy_meal_set_multicast(struct net_device *dev)
{ … }
static int hme_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd)
{ … }
static int hme_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *cmd)
{ … }
static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{ … }
static u32 hme_get_link(struct net_device *dev)
{ … }
static const struct ethtool_ops hme_ethtool_ops = …;
#ifdef CONFIG_SBUS
static struct quattro *quattro_sbus_find(struct platform_device *child)
{
struct device *parent = child->dev.parent;
struct platform_device *op;
struct quattro *qp;
op = to_platform_device(parent);
qp = platform_get_drvdata(op);
if (qp)
return qp;
qp = kzalloc(sizeof(*qp), GFP_KERNEL);
if (!qp)
return NULL;
qp->quattro_dev = child;
qp->next = qfe_sbus_list;
qfe_sbus_list = qp;
platform_set_drvdata(op, qp);
return qp;
}
#endif
#ifdef CONFIG_PCI
static struct quattro *quattro_pci_find(struct pci_dev *pdev)
{ … }
#endif
static const struct net_device_ops hme_netdev_ops = …;
#ifdef CONFIG_PCI
static int is_quattro_p(struct pci_dev *pdev)
{ … }
static int find_eth_addr_in_vpd(void __iomem *rom_base, int len, int index, unsigned char *dev_addr)
{ … }
static void __maybe_unused get_hme_mac_nonsparc(struct pci_dev *pdev,
unsigned char *dev_addr)
{ … }
#endif
static void happy_meal_addr_init(struct happy_meal *hp,
struct device_node *dp, int qfe_slot)
{ … }
static int happy_meal_common_probe(struct happy_meal *hp,
struct device_node *dp)
{ … }
#ifdef CONFIG_SBUS
static int happy_meal_sbus_probe_one(struct platform_device *op, int is_qfe)
{
struct device_node *dp = op->dev.of_node, *sbus_dp;
struct quattro *qp = NULL;
struct happy_meal *hp;
struct net_device *dev;
int qfe_slot = -1;
int err;
sbus_dp = op->dev.parent->of_node;
if (!of_node_name_eq(sbus_dp, "sbus") && !of_node_name_eq(sbus_dp, "sbi"))
return -ENODEV;
if (is_qfe) {
qp = quattro_sbus_find(op);
if (qp == NULL)
return -ENODEV;
for (qfe_slot = 0; qfe_slot < 4; qfe_slot++)
if (qp->happy_meals[qfe_slot] == NULL)
break;
if (qfe_slot == 4)
return -ENODEV;
}
dev = devm_alloc_etherdev(&op->dev, sizeof(struct happy_meal));
if (!dev)
return -ENOMEM;
SET_NETDEV_DEV(dev, &op->dev);
hp = netdev_priv(dev);
hp->dev = dev;
hp->happy_dev = op;
hp->dma_dev = &op->dev;
happy_meal_addr_init(hp, dp, qfe_slot);
spin_lock_init(&hp->happy_lock);
if (qp != NULL) {
hp->qfe_parent = qp;
hp->qfe_ent = qfe_slot;
qp->happy_meals[qfe_slot] = dev;
}
hp->gregs = devm_platform_ioremap_resource(op, 0);
if (IS_ERR(hp->gregs)) {
dev_err(&op->dev, "Cannot map global registers.\n");
err = PTR_ERR(hp->gregs);
goto err_out_clear_quattro;
}
hp->etxregs = devm_platform_ioremap_resource(op, 1);
if (IS_ERR(hp->etxregs)) {
dev_err(&op->dev, "Cannot map MAC TX registers.\n");
err = PTR_ERR(hp->etxregs);
goto err_out_clear_quattro;
}
hp->erxregs = devm_platform_ioremap_resource(op, 2);
if (IS_ERR(hp->erxregs)) {
dev_err(&op->dev, "Cannot map MAC RX registers.\n");
err = PTR_ERR(hp->erxregs);
goto err_out_clear_quattro;
}
hp->bigmacregs = devm_platform_ioremap_resource(op, 3);
if (IS_ERR(hp->bigmacregs)) {
dev_err(&op->dev, "Cannot map BIGMAC registers.\n");
err = PTR_ERR(hp->bigmacregs);
goto err_out_clear_quattro;
}
hp->tcvregs = devm_platform_ioremap_resource(op, 4);
if (IS_ERR(hp->tcvregs)) {
dev_err(&op->dev, "Cannot map TCVR registers.\n");
err = PTR_ERR(hp->tcvregs);
goto err_out_clear_quattro;
}
hp->hm_revision = 0xa0;
if (qp != NULL)
hp->happy_flags |= HFLAG_QUATTRO;
hp->irq = op->archdata.irqs[0];
hp->happy_bursts = of_getintprop_default(sbus_dp,
"burst-sizes", 0x00);
#ifdef CONFIG_PCI
hp->read_desc32 = sbus_hme_read_desc32;
hp->write_txd = sbus_hme_write_txd;
hp->write_rxd = sbus_hme_write_rxd;
hp->read32 = sbus_hme_read32;
hp->write32 = sbus_hme_write32;
#endif
err = happy_meal_common_probe(hp, dp);
if (err)
goto err_out_clear_quattro;
platform_set_drvdata(op, hp);
if (qfe_slot != -1)
netdev_info(dev,
"Quattro HME slot %d (SBUS) 10/100baseT Ethernet %pM\n",
qfe_slot, dev->dev_addr);
else
netdev_info(dev, "HAPPY MEAL (SBUS) 10/100baseT Ethernet %pM\n",
dev->dev_addr);
return 0;
err_out_clear_quattro:
if (qp)
qp->happy_meals[qfe_slot] = NULL;
return err;
}
#endif
#ifdef CONFIG_PCI
static int happy_meal_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{ … }
static const struct pci_device_id happymeal_pci_ids[] = …;
MODULE_DEVICE_TABLE(pci, happymeal_pci_ids);
static struct pci_driver hme_pci_driver = …;
static int __init happy_meal_pci_init(void)
{ … }
static void happy_meal_pci_exit(void)
{ … }
#endif
#ifdef CONFIG_SBUS
static const struct of_device_id hme_sbus_match[];
static int hme_sbus_probe(struct platform_device *op)
{
const struct of_device_id *match;
struct device_node *dp = op->dev.of_node;
const char *model = of_get_property(dp, "model", NULL);
int is_qfe;
match = of_match_device(hme_sbus_match, &op->dev);
if (!match)
return -EINVAL;
is_qfe = (match->data != NULL);
if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
is_qfe = 1;
return happy_meal_sbus_probe_one(op, is_qfe);
}
static const struct of_device_id hme_sbus_match[] = {
{
.name = "SUNW,hme",
},
{
.name = "SUNW,qfe",
.data = (void *) 1,
},
{
.name = "qfe",
.data = (void *) 1,
},
{},
};
MODULE_DEVICE_TABLE(of, hme_sbus_match);
static struct platform_driver hme_sbus_driver = {
.driver = {
.name = "hme",
.of_match_table = hme_sbus_match,
},
.probe = hme_sbus_probe,
};
static int __init happy_meal_sbus_init(void)
{
return platform_driver_register(&hme_sbus_driver);
}
static void happy_meal_sbus_exit(void)
{
platform_driver_unregister(&hme_sbus_driver);
while (qfe_sbus_list) {
struct quattro *qfe = qfe_sbus_list;
struct quattro *next = qfe->next;
kfree(qfe);
qfe_sbus_list = next;
}
}
#endif
static int __init happy_meal_probe(void)
{ … }
static void __exit happy_meal_exit(void)
{ … }
module_init(…) …;
module_exit(happy_meal_exit);