761 lines
26 KiB
C
Executable File

/*++
Copyright (c) 2021 Motor-comm Corporation.
Confidential and Proprietary. All rights reserved.
This is Motor-comm Corporation NIC driver relevant files. Please don't copy, modify,
distribute without commercial permission.
--*/
#include "fuxi-gmac.h"
#include "fuxi-gmac-reg.h"
#ifdef HAVE_FXGMAC_DEBUG_FS
#include <linux/debugfs.h>
#endif
#include <linux/module.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/fcntl.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/inet.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <linux/udp.h>
#define TEST_MAC_HEAD 14
#define TEST_TCP_HEAD_LEN_OFFSET 12
#define TEST_TCP_OFFLOAD_LEN_OFFSET 48
#define TEST_TCP_FIX_HEAD_LEN 24
#define TEST_TCP_MSS_OFFSET 56
#define DF_MAX_NIC_NUM 16
#ifdef HAVE_FXGMAC_DEBUG_FS
/**
* fxgmac_dbg_netdev_ops_read - read for netdev_ops datum
* @filp: the opened file
* @buffer: where to write the data for the user to read
* @count: the size of the user's buffer
* @ppos: file position offset
**/
static ssize_t fxgmac_dbg_netdev_ops_read(struct file *filp,
char __user *buffer,
size_t count, loff_t *ppos)
{
struct fxgmac_pdata *pdata = filp->private_data;
char *buf;
int len;
/* don't allow partial reads */
if (*ppos != 0)
return 0;
buf = kasprintf(GFP_KERNEL, "%s: %s\n",
pdata->netdev->name,
pdata->expansion.fxgmac_dbg_netdev_ops_buf);
if (!buf)
return -ENOMEM;
if (count < strlen(buf)) {
kfree(buf);
return -ENOSPC;
}
len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
kfree(buf);
return len;
}
/**
* fxgmac_dbg_netdev_ops_write - write into netdev_ops datum
* @filp: the opened file
* @buffer: where to find the user's data
* @count: the length of the user's data
* @ppos: file position offset
**/
static ssize_t fxgmac_dbg_netdev_ops_write(struct file *filp,
const char __user *buffer,
size_t count, loff_t *ppos)
{
struct fxgmac_pdata *pdata = filp->private_data;
int len;
/* don't allow partial writes */
if (*ppos != 0)
return 0;
if (count >= sizeof(pdata->expansion.fxgmac_dbg_netdev_ops_buf))
return -ENOSPC;
len = simple_write_to_buffer(pdata->expansion.fxgmac_dbg_netdev_ops_buf,
sizeof(pdata->expansion.fxgmac_dbg_netdev_ops_buf)-1,
ppos,
buffer,
count);
if (len < 0)
return len;
pdata->expansion.fxgmac_dbg_netdev_ops_buf[len] = '\0';
if (strncmp(pdata->expansion.fxgmac_dbg_netdev_ops_buf, "tx_timeout", 10) == 0) {
DPRINTK("tx_timeout called\n");
} else {
FXGMAC_PR("Unknown command: %s\n", pdata->expansion.fxgmac_dbg_netdev_ops_buf);
FXGMAC_PR("Available commands:\n");
FXGMAC_PR(" tx_timeout\n");
}
return count;
}
#endif
static void fxgmac_dbg_tx_pkt(struct fxgmac_pdata *pdata, u8 *pcmd_data)
{
unsigned int pktLen = 0;
struct sk_buff *skb;
pfxgmac_test_packet pPkt;
u8 * pTx_data = NULL;
u8 * pSkb_data = NULL;
u32 offload_len = 0;
u8 ipHeadLen, tcpHeadLen, headTotalLen;
static u32 lastGsoSize = 806;//initial default value
//int i = 0;
/* get fxgmac_test_packet */
pPkt = (pfxgmac_test_packet)(pcmd_data + sizeof(struct ext_ioctl_data));
pktLen = pPkt->length;
/* get pkt data */
pTx_data = (u8 *)pPkt + sizeof(fxgmac_test_packet);
#if 0 //for debug
DPRINTK("Send packet len is %d, data:\n", pktLen);
#if 1
for(i = 0; i < 70 ; i++)
{
DPRINTK("%2x ", pTx_data[i]);
}
#endif
#endif
/* alloc sk_buff */
skb = alloc_skb(pktLen, GFP_ATOMIC);
if (!skb){
DPRINTK("alloc skb fail\n");
return;
}
/* copy data to skb */
pSkb_data = skb_put(skb, pktLen);
memset(pSkb_data, 0, pktLen);
memcpy(pSkb_data, pTx_data, pktLen);
/* set skb parameters */
skb->dev = pdata->netdev;
skb->pkt_type = PACKET_OUTGOING;
skb->protocol = ntohs(ETH_P_IP);
skb->no_fcs = 1;
skb->ip_summed = CHECKSUM_PARTIAL;
if(skb->len > 1514){
/* TSO packet */
/* set tso test flag */
pdata->expansion.fxgmac_test_tso_flag = true;
/* get protocol head length */
ipHeadLen = (pSkb_data[TEST_MAC_HEAD] & 0xF) * 4;
tcpHeadLen = (pSkb_data[TEST_MAC_HEAD + ipHeadLen + TEST_TCP_HEAD_LEN_OFFSET] >> 4 & 0xF) * 4;
headTotalLen = TEST_MAC_HEAD + ipHeadLen + tcpHeadLen;
offload_len = (pSkb_data[TEST_TCP_OFFLOAD_LEN_OFFSET] << 8 |
pSkb_data[TEST_TCP_OFFLOAD_LEN_OFFSET + 1]) & 0xFFFF;
/* set tso skb parameters */
//skb->ip_summed = CHECKSUM_PARTIAL;
skb->transport_header = ipHeadLen + TEST_MAC_HEAD;
skb->network_header = TEST_MAC_HEAD;
skb->inner_network_header = TEST_MAC_HEAD;
skb->mac_len = TEST_MAC_HEAD;
/* set skb_shinfo parameters */
if(tcpHeadLen > TEST_TCP_FIX_HEAD_LEN){
skb_shinfo(skb)->gso_size = (pSkb_data[TEST_TCP_MSS_OFFSET] << 8 |
pSkb_data[TEST_TCP_MSS_OFFSET + 1]) & 0xFFFF;
}else{
skb_shinfo(skb)->gso_size = 0;
}
if(skb_shinfo(skb)->gso_size != 0){
lastGsoSize = skb_shinfo(skb)->gso_size;
}else{
skb_shinfo(skb)->gso_size = lastGsoSize;
}
//DPRINTK("offload_len is %d, skb_shinfo(skb)->gso_size is %d", offload_len, skb_shinfo(skb)->gso_size);
/* get segment size */
if(offload_len % skb_shinfo(skb)->gso_size == 0){
skb_shinfo(skb)->gso_segs = offload_len / skb_shinfo(skb)->gso_size;
pdata->expansion.fxgmac_test_last_tso_len = skb_shinfo(skb)->gso_size + headTotalLen;
}else{
skb_shinfo(skb)->gso_segs = offload_len / skb_shinfo(skb)->gso_size + 1;
pdata->expansion.fxgmac_test_last_tso_len = offload_len % skb_shinfo(skb)->gso_size + headTotalLen;
}
pdata->expansion.fxgmac_test_tso_seg_num = skb_shinfo(skb)->gso_segs;
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4 ;
skb_shinfo(skb)->frag_list = NULL;
skb->csum_start = skb_headroom(skb) + TEST_MAC_HEAD + ipHeadLen;
skb->csum_offset = skb->len - TEST_MAC_HEAD - ipHeadLen;
pdata->expansion.fxgmac_test_packet_len = skb_shinfo(skb)->gso_size + headTotalLen;
}else{
/* set non-TSO packet parameters */
pdata->expansion.fxgmac_test_packet_len = skb->len;
}
/* send data */
if(dev_queue_xmit(skb) != NET_XMIT_SUCCESS){
DPRINTK("xmit data fail \n");
}
}
static void fxgmac_dbg_rx_pkt(struct fxgmac_pdata *pdata, u8 *pcmd_data)
{
unsigned int totalLen = 0;
struct sk_buff *rx_skb;
struct ext_ioctl_data *pcmd;
fxgmac_test_packet pkt;
void* addr = 0;
u8 *rx_data = (u8*)kzalloc(FXGMAC_MAX_DBG_RX_DATA, GFP_KERNEL);
if (!rx_data)
return;
//int i;
/* initial dest data region */
pcmd = (struct ext_ioctl_data *)pcmd_data;
addr = pcmd->cmd_buf.buf;
while(pdata->expansion.fxgmac_test_skb_arr_in_index != pdata->expansion.fxgmac_test_skb_arr_out_index){
/* get received skb data */
rx_skb = pdata->expansion.fxgmac_test_skb_array[pdata->expansion.fxgmac_test_skb_arr_out_index];
if(rx_skb->len + sizeof(fxgmac_test_packet) + totalLen < 64000){
pkt.length = rx_skb->len;
pkt.type = 0x80;
pkt.buf[0].offset = totalLen + sizeof(fxgmac_test_packet);
pkt.buf[0].length = rx_skb->len;
/* get data from skb */
//DPRINTK("FXG:rx_skb->len=%d", rx_skb->len);
memcpy(rx_data, rx_skb->data, rx_skb->len);
/* update next pointer */
if((pdata->expansion.fxgmac_test_skb_arr_out_index + 1) % FXGMAC_MAX_DBG_TEST_PKT == pdata->expansion.fxgmac_test_skb_arr_in_index)
{
pkt.next = NULL;
}
else
{
pkt.next = (pfxgmac_test_packet)(addr + totalLen + sizeof(fxgmac_test_packet) + pkt.length);
}
/* copy data to user space */
if(copy_to_user((void *)(addr + totalLen), (void*)(&pkt), sizeof(fxgmac_test_packet)))
{
DPRINTK("cppy pkt data to user fail...");
}
//FXGMAC_PR("FXG:rx_skb->len=%d", rx_skb->len);
if(copy_to_user((void *)(addr + totalLen + sizeof(fxgmac_test_packet)), (void*)rx_data, rx_skb->len))
{
DPRINTK("cppy data to user fail...");
}
/* update total length */
totalLen += (sizeof(fxgmac_test_packet) + rx_skb->len);
/* free skb */
kfree_skb(rx_skb);
pdata->expansion.fxgmac_test_skb_array[pdata->expansion.fxgmac_test_skb_arr_out_index] = NULL;
/* update gCurSkbOutIndex */
pdata->expansion.fxgmac_test_skb_arr_out_index = (pdata->expansion.fxgmac_test_skb_arr_out_index + 1) % FXGMAC_MAX_DBG_TEST_PKT;
}else{
DPRINTK("receive data more receive buffer... \n");
break;
}
}
if (rx_data)
kfree(rx_data);
#if 0
pPkt = (pfxgmac_test_packet)buf;
DPRINTK("FXG: pPkt->Length is %d", pPkt->length);
DPRINTK("FXG: pPkt->Length is %d", pPkt->length);
DPRINTK("pPkt: %p, buf is %lx",pPkt, pcmd->cmd_buf.buf);
for(i = 0; i < 30; i++){
DPRINTK("%x",*(((u8*)pPkt + sizeof(fxgmac_test_packet)) + i));
}
#endif
}
// Based on the current application scenario,we only use CMD_DATA for data.
// if you use other struct, you should recalculate in_total_size
long fxgmac_dbg_netdev_ops_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
bool ret = true;
int regval = 0;
struct fxgmac_pdata *pdata = file->private_data;
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
FXGMAC_PDATA_OF_PLATFORM *ex = &pdata->expansion;
CMD_DATA ex_data;
struct ext_ioctl_data pcmd;
u8* data = NULL;
u8* buf = NULL;
int in_total_size, in_data_size, out_total_size;
int ioctl_cmd_size = sizeof(struct ext_ioctl_data);
u8 mac[ETH_ALEN] = {0};
struct sk_buff *tmpskb;
if (!arg) {
DPRINTK("[%s] command arg is %lx !\n", __func__, arg);
goto err;
}
/* check device type */
if (_IOC_TYPE(cmd) != IOC_MAGIC) {
DPRINTK("[%s] command type [%c] error!\n", __func__, _IOC_TYPE(cmd));
goto err;
}
/* check command number*/
if (_IOC_NR(cmd) > IOC_MAXNR) {
DPRINTK("[%s] command numer [%d] exceeded!\n", __func__, _IOC_NR(cmd));
goto err;
}
//buf = (u8*)kzalloc(FXGMAC_MAX_DBG_BUF_LEN, GFP_KERNEL);
if(copy_from_user(&pcmd, (void*)arg, ioctl_cmd_size)) {
DPRINTK("copy data from user fail... \n");
goto err;
}
in_total_size = pcmd.cmd_buf.size_in;
in_data_size = in_total_size - ioctl_cmd_size;
out_total_size = pcmd.cmd_buf.size_out;
buf = (u8*)kzalloc(in_total_size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
if(copy_from_user(buf, (void*)arg, in_total_size)) {
DPRINTK("copy data from user fail... \n");
goto err;
}
data = buf + ioctl_cmd_size;
if(arg != 0) {
switch(pcmd.cmd_type) {
/* ioctl diag begin */
case FUXI_DFS_IOCTL_DIAG_BEGIN:
DPRINTK("Debugfs received diag begin command.\n");
if (netif_running(pdata->netdev)){
fxgmac_restart_dev(pdata);
}
/* release last loopback test abnormal exit buffer */
while(ex->fxgmac_test_skb_arr_in_index !=
ex->fxgmac_test_skb_arr_out_index)
{
tmpskb = ex->fxgmac_test_skb_array[ex->fxgmac_test_skb_arr_out_index];
if(tmpskb)
{
kfree_skb(tmpskb);
ex->fxgmac_test_skb_array[ex->fxgmac_test_skb_arr_out_index] = NULL;
}
ex->fxgmac_test_skb_arr_out_index = (ex->fxgmac_test_skb_arr_out_index + 1) % FXGMAC_MAX_DBG_TEST_PKT;
}
/* init loopback test parameters */
ex->fxgmac_test_skb_arr_in_index = 0;
ex->fxgmac_test_skb_arr_out_index = 0;
ex->fxgmac_test_tso_flag = false;
ex->fxgmac_test_tso_seg_num = 0;
ex->fxgmac_test_last_tso_len = 0;
ex->fxgmac_test_packet_len = 0;
break;
/* ioctl diag end */
case FUXI_DFS_IOCTL_DIAG_END:
DPRINTK("Debugfs received diag end command.\n");
if (netif_running(pdata->netdev)){
fxgmac_restart_dev(pdata);
}
break;
/* ioctl diag tx pkt */
case FUXI_DFS_IOCTL_DIAG_TX_PKT:
fxgmac_dbg_tx_pkt(pdata, buf);
break;
/* ioctl diag rx pkt */
case FUXI_DFS_IOCTL_DIAG_RX_PKT:
fxgmac_dbg_rx_pkt(pdata, buf);
break;
/* ioctl device reset */
case FUXI_DFS_IOCTL_DEVICE_RESET:
DPRINTK("Debugfs received device reset command.\n");
if (netif_running(pdata->netdev)){
fxgmac_restart_dev(pdata);
}
break;
case FXGMAC_EFUSE_LED_TEST:
DPRINTK("Debugfs received device led test command.\n");
memcpy(&pdata->led, data, sizeof(struct led_setting));
fxgmac_restart_dev(pdata);
break;
case FXGMAC_EFUSE_UPDATE_LED_CFG:
DPRINTK("Debugfs received device led update command.\n");
memcpy(&pdata->ledconfig, data, sizeof(struct led_setting));
ret = hw_ops->write_led_config(pdata);
hw_ops->read_led_config(pdata);
hw_ops->led_under_active(pdata);
break;
case FXGMAC_EFUSE_WRITE_LED:
memcpy(&ex_data, data, sizeof(CMD_DATA));
DPRINTK("FXGMAC_EFUSE_WRITE_LED, val = 0x%x\n", ex_data.val0);
ret = hw_ops->write_led(pdata, ex_data.val0);
break;
case FXGMAC_EFUSE_WRITE_OOB:
DPRINTK("FXGMAC_EFUSE_WRITE_OOB.\n");
ret = hw_ops->write_oob(pdata);
break;
case FXGMAC_EFUSE_READ_REGIONABC:
memcpy(&ex_data, data, sizeof(CMD_DATA));
ret = hw_ops->read_efuse_data(pdata, ex_data.val0, &ex_data.val1);
DPRINTK("FXGMAC_EFUSE_READ_REGIONABC, address = 0x%x, val = 0x%x\n",
ex_data.val0,
ex_data.val1);
if (ret) {
memcpy(data, &ex_data, sizeof(CMD_DATA));
out_total_size = ioctl_cmd_size + sizeof(CMD_DATA);
if (copy_to_user((void*)arg, (void*)buf, out_total_size))
goto err;
}
break;
case FXGMAC_EFUSE_WRITE_PATCH_REG:
memcpy(&ex_data, data, sizeof(CMD_DATA));
DPRINTK("FXGMAC_EFUSE_WRITE_PATCH_REG, address = 0x%x, val = 0x%x\n",
ex_data.val0,
ex_data.val1);
ret = hw_ops->write_patch_to_efuse(pdata, ex_data.val0, ex_data.val1);
break;
case FXGMAC_EFUSE_READ_PATCH_REG:
memcpy(&ex_data, data, sizeof(CMD_DATA));
ret = hw_ops->read_patch_from_efuse(pdata, ex_data.val0, &ex_data.val1);
DPRINTK("FXGMAC_EFUSE_READ_PATCH_REG, address = 0x%x, val = 0x%x\n",
ex_data.val0, ex_data.val1);
if (ret) {
memcpy(data, &ex_data, sizeof(CMD_DATA));
out_total_size = ioctl_cmd_size + sizeof(CMD_DATA);
if (copy_to_user((void*)arg, (void*)buf, out_total_size))
goto err;
}
break;
case FXGMAC_EFUSE_WRITE_PATCH_PER_INDEX:
memcpy(&ex_data, data, sizeof(CMD_DATA));
ret = hw_ops->write_patch_to_efuse_per_index(pdata, ex_data.val0,
ex_data.val1,
ex_data.val2);
DPRINTK("FXGMAC_EFUSE_WRITE_PATCH_PER_INDEX, index = %d, address = 0x%x, val = 0x%x\n",
ex_data.val0, ex_data.val1, ex_data.val2);
break;
case FXGMAC_EFUSE_READ_PATCH_PER_INDEX:
memcpy(&ex_data, data, sizeof(CMD_DATA));
ret = hw_ops->read_patch_from_efuse_per_index(pdata,ex_data.val0,
&ex_data.val1,
&ex_data.val2);
DPRINTK("FXGMAC_EFUSE_READ_PATCH_PER_INDEX, address = 0x%x, val = 0x%x\n",
ex_data.val1, ex_data.val2);
if (ret) {
memcpy(data, &ex_data, sizeof(CMD_DATA));
out_total_size = ioctl_cmd_size + sizeof(CMD_DATA);
if (copy_to_user((void*)arg, (void*)buf, out_total_size))
goto err;
}
break;
case FXGMAC_EFUSE_LOAD:
DPRINTK("FXGMAC_EFUSE_LOAD.\n");
ret = hw_ops->efuse_load(pdata);
break;
case FXGMAC_GET_MAC_DATA:
ret = hw_ops->read_mac_subsys_from_efuse(pdata, mac, NULL, NULL);
if (ret) {
memcpy(data, mac, ETH_ALEN);
out_total_size = ioctl_cmd_size + ETH_ALEN;
if (copy_to_user((void*)arg, (void*)buf, out_total_size))
goto err;
}
break;
case FXGMAC_SET_MAC_DATA:
if (in_data_size != ETH_ALEN)
goto err;
memcpy(mac, data, ETH_ALEN);
ret = hw_ops->write_mac_subsys_to_efuse(pdata, mac, NULL, NULL);
if (ret) {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,17,0))
eth_hw_addr_set(pdata->netdev, mac);
#else
memcpy(pdata->netdev->dev_addr, mac, ETH_ALEN);
#endif
memcpy(pdata->mac_addr, mac, ETH_ALEN);
hw_ops->set_mac_address(pdata, mac);
hw_ops->set_mac_hash(pdata);
}
break;
case FXGMAC_GET_SUBSYS_ID:
memcpy(&ex_data, data, sizeof(CMD_DATA));
ret = hw_ops->read_mac_subsys_from_efuse(pdata,
NULL,
&ex_data.val0,
NULL);
if (ret) {
ex_data.val1 = 0xFFFF; // invalid value
memcpy(data, &ex_data, sizeof(CMD_DATA));
out_total_size = ioctl_cmd_size + sizeof(CMD_DATA);
if (copy_to_user((void*)arg, (void*)buf, out_total_size))
goto err;
}
break;
case FXGMAC_SET_SUBSYS_ID:
memcpy(&ex_data, data, sizeof(CMD_DATA));
ret = hw_ops->write_mac_subsys_to_efuse(pdata,
NULL,
&ex_data.val0,
NULL);
break;
case FXGMAC_GET_GMAC_REG:
memcpy(&ex_data, data, sizeof(CMD_DATA));
ex_data.val1 = hw_ops->get_gmac_register(pdata,
(u8*)(pdata->mac_regs + ex_data.val0));
memcpy(data, &ex_data, sizeof(CMD_DATA));
out_total_size = ioctl_cmd_size + sizeof(CMD_DATA);
if (copy_to_user((void*)arg, (void*)buf, out_total_size))
goto err;
break;
case FXGMAC_SET_GMAC_REG:
memcpy(&ex_data, data, sizeof(CMD_DATA));
regval = hw_ops->set_gmac_register(pdata,
(u8*)(pdata->mac_regs + ex_data.val0),
ex_data.val1);
ret = (regval == 0 ? true : false);
break;
case FXGMAC_GET_PHY_REG:
memcpy(&ex_data, data, sizeof(CMD_DATA));
regval = hw_ops->read_ephy_reg(pdata, ex_data.val0, &ex_data.val1);
if (regval != -1) {
memcpy(data, &ex_data, sizeof(CMD_DATA));
out_total_size = ioctl_cmd_size + sizeof(CMD_DATA);
if (copy_to_user((void*)arg, (void*)buf, out_total_size))
goto err;
}
ret = (regval == -1 ? false : true);
break;
case FXGMAC_SET_PHY_REG:
memcpy(&ex_data, data, sizeof(CMD_DATA));
regval = hw_ops->write_ephy_reg(pdata, ex_data.val0, ex_data.val1);
ret = (regval == 0 ? true : false);
break;
case FXGMAC_GET_PCIE_LOCATION:
ex_data.val0 = pdata->pdev->bus->number;
ex_data.val1 = PCI_SLOT(pdata->pdev->devfn);
ex_data.val2 = PCI_FUNC(pdata->pdev->devfn);
memcpy(data, &ex_data, sizeof(CMD_DATA));
out_total_size = ioctl_cmd_size + sizeof(CMD_DATA);
if (copy_to_user((void*)arg, (void*)buf, out_total_size))
goto err;
break;
case FXGMAC_GET_GSO_SIZE:
ex_data.val0 = pdata->netdev->gso_max_size;
memcpy(data, &ex_data, sizeof(CMD_DATA));
out_total_size = ioctl_cmd_size + sizeof(CMD_DATA);
if (copy_to_user((void*)arg, (void*)buf, out_total_size))
goto err;
break;
case FXGMAC_SET_GSO_SIZE:
memcpy(&ex_data, data, sizeof(CMD_DATA));
pdata->netdev->gso_max_size = ex_data.val0;
break;
case FXGMAC_SET_RX_MODERATION:
memcpy(&ex_data, data, sizeof(CMD_DATA));
regval = readreg(pdata->pAdapter, pdata->base_mem + INT_MOD);
regval = FXGMAC_SET_REG_BITS(regval, INT_MOD_RX_POS, INT_MOD_RX_LEN, ex_data.val0);
writereg(pdata->pAdapter, regval, pdata->base_mem + INT_MOD);
break;
case FXGMAC_SET_TX_MODERATION:
memcpy(&ex_data, data, sizeof(CMD_DATA));
regval = readreg(pdata->pAdapter, pdata->base_mem + INT_MOD);
regval = FXGMAC_SET_REG_BITS(regval, INT_MOD_TX_POS, INT_MOD_TX_LEN, ex_data.val0);
writereg(pdata->pAdapter, regval, pdata->base_mem + INT_MOD);
break;
case FXGMAC_GET_TXRX_MODERATION:
regval = readreg(pdata->pAdapter, pdata->base_mem + INT_MOD);
ex_data.val0 = FXGMAC_GET_REG_BITS(regval, INT_MOD_RX_POS, INT_MOD_RX_LEN);
ex_data.val1 = FXGMAC_GET_REG_BITS(regval, INT_MOD_TX_POS, INT_MOD_TX_LEN);
memcpy(data, &ex_data, sizeof(CMD_DATA));
out_total_size = ioctl_cmd_size + sizeof(CMD_DATA);
if (copy_to_user((void*)arg, (void*)buf, out_total_size))
goto err;
break;
default:
DPRINTK("Debugfs received invalid command: %x.\n", pcmd.cmd_type);
ret = false;
break;
}
}
if (buf)
kfree(buf);
return ret ? FXGMAC_SUCCESS : FXGMAC_FAIL;
err:
if (buf)
kfree(buf);
return FXGMAC_FAIL;
}
#ifdef HAVE_FXGMAC_DEBUG_FS
static struct file_operations fxgmac_dbg_netdev_ops_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = fxgmac_dbg_netdev_ops_read,
.write = fxgmac_dbg_netdev_ops_write,
.unlocked_ioctl = fxgmac_dbg_netdev_ops_ioctl,
};
/**
* fxgmac_dbg_adapter_init - setup the debugfs directory for the adapter
* @adapter: the adapter that is starting up
**/
void fxgmac_dbg_adapter_init(struct fxgmac_pdata *pdata)
{
const char *name = pdata->drv_name;
struct dentry *pfile;
pdata->expansion.dbg_adapter = debugfs_create_dir(name, pdata->expansion.fxgmac_dbg_root);
if (pdata->expansion.dbg_adapter) {
pfile = debugfs_create_file("netdev_ops", 0600,
pdata->expansion.dbg_adapter, pdata,
&fxgmac_dbg_netdev_ops_fops);
if (!pfile)
DPRINTK("debugfs netdev_ops for %s failed\n", name);
} else {
DPRINTK("debugfs entry for %s failed\n", name);
}
}
/**
* fxgmac_dbg_adapter_exit - clear out the adapter's debugfs entries
* @adapter: board private structure
**/
void fxgmac_dbg_adapter_exit(struct fxgmac_pdata *pdata)
{
if (pdata->expansion.dbg_adapter)
debugfs_remove_recursive(pdata->expansion.dbg_adapter);
pdata->expansion.dbg_adapter = NULL;
}
/**
* fxgmac_dbg_init - start up debugfs for the driver
**/
void fxgmac_dbg_init(struct fxgmac_pdata *pdata)
{
unsigned int i;
char num[3];
const char debug_path[] = "/sys/kernel/debug/";
const char file_prefix[] = "fuxi_";
char file_path[50];
char file_name[8];
/* init file_path */
memset(file_path, '\0', sizeof(file_path));
memcpy(file_path, debug_path, sizeof(debug_path));
for(i = 0; i < DF_MAX_NIC_NUM; i++)
{
/* init num and filename */
memset(num, '\0', sizeof(num));
memset(file_name, '\0', sizeof(file_name));
/* int to string */
sprintf(num, "%d", i);
/* file name */
memcpy(file_name, file_prefix, sizeof(file_prefix));
memcpy(file_name + strlen(file_prefix), num, sizeof(num));
/* file path */
memcpy(file_path + sizeof(debug_path) - 1, file_name, sizeof(file_name));
//DPRINTK("FXG: file_path is %s", file_path);
/* whether file exist */
pdata->expansion.fxgmac_dbg_root = debugfs_lookup(file_name, NULL);
if (!pdata->expansion.fxgmac_dbg_root)
{
/* create file */
pdata->expansion.fxgmac_dbg_root = debugfs_create_dir(file_name, NULL);
if (IS_ERR(pdata->expansion.fxgmac_dbg_root))
DPRINTK("fxgmac init of debugfs failed\n");
break;
}
}
}
/**
* fxgmac_dbg_exit - clean out the driver's debugfs entries
**/
void fxgmac_dbg_exit(struct fxgmac_pdata *pdata)
{
if (pdata->expansion.fxgmac_dbg_root)
debugfs_remove_recursive(pdata->expansion.fxgmac_dbg_root);
}
#endif /* HAVE_XLGMAC_DEBUG_FS */