/*
* Copyright (C) 2015 Cavium, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*/
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/phy.h>
#include <linux/of.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include "nic_reg.h"
#include "nic.h"
#include "thunder_bgx.h"
#define DRV_NAME "thunder-BGX"
#define DRV_VERSION "1.0"
struct lmac {
struct bgx *bgx;
int dmac;
u8 mac[ETH_ALEN];
bool link_up;
int lmacid; /* ID within BGX */
int lmacid_bd; /* ID on board */
struct net_device netdev;
struct phy_device *phydev;
unsigned int last_duplex;
unsigned int last_link;
unsigned int last_speed;
bool is_sgmii;
struct delayed_work dwork;
struct workqueue_struct *check_link;
};
struct bgx {
u8 bgx_id;
u8 qlm_mode;
struct lmac lmac[MAX_LMAC_PER_BGX];
int lmac_count;
int lmac_type;
int lane_to_sds;
int use_training;
void __iomem *reg_base;
struct pci_dev *pdev;
};
static struct bgx *bgx_vnic[MAX_BGX_THUNDER];
static int lmac_count; /* Total no of LMACs in system */
static int bgx_xaui_check_link(struct lmac *lmac);
/* Supported devices */
static const struct pci_device_id bgx_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_BGX) },
{ 0, } /* end of table */
};
MODULE_AUTHOR("Cavium Inc");
MODULE_DESCRIPTION("Cavium Thunder BGX/MAC Driver");
MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
MODULE_DEVICE_TABLE(pci, bgx_id_table);
/* The Cavium ThunderX network controller can *only* be found in SoCs
* containing the ThunderX ARM64 CPU implementation. All accesses to the device
* registers on this platform are implicitly strongly ordered with respect
* to memory accesses. So writeq_relaxed() and readq_relaxed() are safe to use
* with no memory barriers in this driver. The readq()/writeq() functions add
* explicit ordering operation which in this case are redundant, and only
* add overhead.
*/
/* Register read/write APIs */
static u64 bgx_reg_read(struct bgx *bgx, u8 lmac, u64 offset)
{
void __iomem *addr = bgx->reg_base + ((u32)lmac << 20) + offset;
return readq_relaxed(addr);
}
static void bgx_reg_write(struct bgx *bgx, u8 lmac, u64 offset, u64 val)
{
void __iomem *addr = bgx->reg_base + ((u32)lmac << 20) + offset;
writeq_relaxed(val, addr);
}
static void bgx_reg_modify(struct bgx *bgx, u8 lmac, u64 offset, u64 val)
{
void __iomem *addr = bgx->reg_base + ((u32)lmac << 20) + offset;
writeq_relaxed(val | readq_relaxed(addr), addr);
}
static int bgx_poll_reg(struct bgx *bgx, u8 lmac, u64 reg, u64 mask, bool zero)
{
int timeout = 100;
u64 reg_val;
while (timeout) {
reg_val = bgx_reg_read(bgx, lmac