/*
* FUJITSU Extended Socket Network Device driver
* Copyright (c) 2015 FUJITSU LIMITED
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, see <http://www.gnu.org/licenses/>.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
*/
#include "fjes_hw.h"
#include "fjes.h"
static void fjes_hw_update_zone_task(struct work_struct *);
static void fjes_hw_epstop_task(struct work_struct *);
/* supported MTU list */
const u32 fjes_support_mtu[] = {
FJES_MTU_DEFINE(8 * 1024),
FJES_MTU_DEFINE(16 * 1024),
FJES_MTU_DEFINE(32 * 1024),
FJES_MTU_DEFINE(64 * 1024),
0
};
u32 fjes_hw_rd32(struct fjes_hw *hw, u32 reg)
{
u8 *base = hw->base;
u32 value = 0;
value = readl(&base[reg]);
return value;
}
static u8 *fjes_hw_iomap(struct fjes_hw *hw)
{
u8 *base;
if (!request_mem_region(hw->hw_res.start, hw->hw_res.size,
fjes_driver_name)) {
pr_err("request_mem_region failed\n");
return NULL;
}
base = (u8 *)ioremap_nocache(hw->hw_res.start, hw->hw_res.size);
return base;
}
static void fjes_hw_iounmap(struct fjes_hw *hw)
{
iounmap(hw->base);
release_mem_region(hw->hw_res.start, hw->hw_res.size);
}
int fjes_hw_reset(struct fjes_hw *hw)
{
union REG_DCTL dctl;
int timeout;
dctl.reg = 0;
dctl.bits.reset = 1;
wr32(XSCT_DCTL, dctl.reg);
timeout = FJES_DEVICE_RESET_TIMEOUT * 1000;
dctl.reg = rd32(XSCT_DCTL);
while ((dctl.bits.reset == 1) && (timeout > 0)) {
msleep(1000);
dctl.reg = rd32(XSCT_DCTL);
timeout -= 1000;
}
return timeout > 0 ? 0 : -EIO;
}
static int fjes_hw_get_max_epid(struct fjes_hw *hw)
{
union REG_MAX_EP info;
info.reg = rd32(XSCT_MAX_EP);
return info.bits.maxep;
}
static int fjes_hw_get_my_epid(struct fjes_hw *hw)
{
union REG_OWNER_EPID info;
info.reg = rd32(XSCT_OWNER_EPID);
return info.bits.epid;
}
static int fjes_hw_alloc_shared_status_region(struct fjes_hw *hw)
{
size_t size;
size = sizeof(struct fjes_device_shared_info) +
(sizeof(u8) * hw->max_epid);
hw->hw_info.share = kzalloc(size, GFP_KERNEL);
if (!hw->hw_info.share)
return -ENOMEM;
hw->hw_info.share->epnum = hw->max_epid;
return 0;
}
static void fjes_hw_free_shared_status_region(struct fjes_hw *hw)
{
kfree(hw->hw_info.share);
hw->hw_info.share = NULL;
}
static int fjes_hw_alloc_epbuf(struct epbuf_handler *epbh)
{
void *