// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
/*
* Copyright (c) 2003-2012 Broadcom Corporation
* All Rights Reserved
*/
#include <linux/phy.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/smp.h>
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/jiffies.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <asm/mipsregs.h>
/*
* fmn.h - For FMN credit configuration and registering fmn_handler.
* FMN is communication mechanism that allows processing agents within
* XLR/XLS to communicate each other.
*/
#include <asm/netlogic/xlr/fmn.h>
#include "platform_net.h"
#include "xlr_net.h"
/*
* The readl/writel implementation byteswaps on XLR/XLS, so
* we need to use __raw_ IO to read the NAE registers
* because they are in the big-endian MMIO area on the SoC.
*/
static inline void xlr_nae_wreg(u32 __iomem *base, unsigned int reg, u32 val)
{
__raw_writel(val, base + reg);
}
static inline u32 xlr_nae_rdreg(u32 __iomem *base, unsigned int reg)
{
return __raw_readl(base + reg);
}
static inline void xlr_reg_update(u32 *base_addr, u32 off, u32 val, u32 mask)
{
u32 tmp;
tmp = xlr_nae_rdreg(base_addr, off);
xlr_nae_wreg(base_addr, off, (tmp & ~mask) | (val & mask));
}
#define MAC_SKB_BACK_PTR_SIZE SMP_CACHE_BYTES
static int send_to_rfr_fifo(struct xlr_net_priv *priv, void *addr)
{
struct nlm_fmn_msg msg;
int ret = 0, num_try = 0, stnid;
unsigned long paddr, mflags;
paddr = virt_to_bus(addr);
msg.msg0 = (u64)paddr & 0xffffffffe0ULL;
msg.msg1 = 0;
msg.msg2 = 0;
msg.msg3 = 0;
stnid = priv->nd->rfr_station;
do {
mflags = nlm_cop2_enable_irqsave();
ret = nlm_fmn_send(1, 0, stnid, &msg);
nlm_cop2_disable_irqrestore(mflags);
if (ret == 0)
return 0;
} while (++num_try < 10000);
netdev_err(priv->ndev, "Send to RFR failed in RX path\n");
return ret;
}
static inline unsigned char *xlr_alloc_skb(void)
{
struct sk_buff *skb;
int buf_len = sizeof(struct sk_buff *);
unsigned char *skb_data;
/* skb->data is cache aligned */
skb = alloc_skb(XLR_RX_BUF_SIZE, GFP_ATOMIC);
if (!skb)
return NULL;
skb_data = skb->data;
skb_reserve(skb, MAC_SKB_BACK_PTR_SIZE);
memcpy(skb_data, &skb, buf_len);
return skb->data;
}
static void xlr_net_fmn_handler(int bkt, int src_stnid, int size, int code,
struct nlm_fmn_msg *msg, void *arg)
{
struct sk_buff *skb;
void *skb_data = NULL;
struct net_device *ndev;
struct xlr_net_priv *priv;
u32 port, length;
unsigned char *addr;
struct xlr_adapter *adapter = arg;
length = (msg->msg0 >> 40) & 0x3fff;
if (length == 0) {
addr = bus_to_virt(msg->msg0 & 0xffffffffffULL);
addr = addr - MAC_SKB_BACK_PTR_SIZE;
skb = (struct sk_buff *)(*(unsigned long *)addr);
dev_kfree_skb_any((struct sk_buff *)addr);
} else {
addr = (unsigned