/*
Broadcom Everest network driver.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/crc32.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/crc32c.h>
#include "bnx2x.h"
#include "bnx2x_cmn.h"
#include "bnx2x_sp.h"
#define BNX2X_MAX_EMUL_MULTI 16
/**** Exe Queue interfaces ****/
/**
* bnx2x_exe_queue_init - init the Exe Queue object
*
* @o: pointer to the object
* @exe_len: length
* @owner: pointer to the owner
* @validate: validate function pointer
* @optimize: optimize function pointer
* @exec: execute function pointer
* @get: get function pointer
*/
static inline void bnx2x_exe_queue_init(struct bnx2x *bp,
struct bnx2x_exe_queue_obj *o,
int exe_len,
union bnx2x_qable_obj *owner,
exe_q_validate validate,
exe_q_remove remove,
exe_q_optimize optimize,
exe_q_execute exec,
exe_q_get get)
{
memset(o, 0, sizeof(*o));
INIT_LIST_HEAD(&o->exe_queue);
INIT_LIST_HEAD(&o->pending_comp);
spin_lock_init(&o->lock);
o->exe_chunk_len = exe_len;
o->owner = owner;
/* Owner specific callbacks */
o->validate = validate;
o->remove = remove;
o->optimize = optimize;
o->execute = exec;
o->get = get;
DP(BNX2X_MSG_SP, "Setup the execution queue with the chunk length of %d\n",
exe_len);
}
static inline void bnx2x_exe_queue_free_elem(struct bnx2x *bp,
struct bnx2x_exeq_elem *elem)
{
DP(BNX2X_MSG_SP, "Deleting an exe_queue element\n");
kfree(elem);
}
static inline int bnx2x_exe_queue_length(struct bnx2x_exe_queue_obj *o)
{
struct bnx2x_exeq_elem *elem;
int cnt = 0;
spin_lock_bh(&o->lock);
list_for_each_entry(elem, &o->exe_queue, link)
cnt++;
spin_unlock_bh(&o->lock);
return cnt;
}
/**
* bnx2x_exe_queue_add - add a new element to the execution queue
*
* @bp: driver handle
* @o: queue
* @cmd: new command to add
* @restore: true - do not optimize the command
*
* If the element is optimized or is illegal, frees it.
*/
static inline int bnx2x_exe_queue_add(struct bnx2x *bp,
struct bnx2x_exe_queue_obj *o,
struct bnx2x_exeq_elem *elem,
bool restore)
{
int rc;
spin_lock_bh(&o->lock);
if (!restore) {
/* Try to cancel this element queue */
rc = o->optimize(bp, o->owner, elem);
if (rc)
goto free_and_exit;
/* Check if this request is ok */
rc = o->validate(bp, o->owner, elem);
if (rc) {
DP(BNX2X_MSG_SP, "Preamble failed: %d\n", rc);
goto free_and_exit;
}
}
/* If so, add it to the execution queue */
list_add_tail(&elem->link, &o->exe_queue);
spin_unlock_bh(&o->lock);
return 0;
free_and_exit:
bnx2x_exe_queue_free_elem(bp, elem);
spin_unlock_bh(&o->lock);
return rc;
}
static inline void __bnx2x_exe_queue_reset_pending(
struct bnx2x *bp,
struct bnx2x_exe_queue_obj *o)
{
struct bnx2x_exeq_elem *elem;
while (!list_empty(&o->pending_comp)) {
elem = list_first_entry(&o->pending_comp,
struct bnx2x_exeq_elem, link);
list_del(&elem->link);
bnx2x_exe_queue_free_elem(bp, elem);
}
}
/**
* bnx2x_exe_queue_step - execute one execution chunk atomically
*
* @bp: driver handle
* @o: queue
* @ramrod_flags: flags
*
* (Should be called while holding the exe_queue->lock).
*/
static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
struct bnx2x_exe_queue_obj *o,
unsigned long *ramrod_flags)
{
struct bnx2x_exeq_elem *elem, spacer;
int cur_len = 0, rc;
memset(&spacer, 0, sizeof(spacer));
/* Next step should not be performed until the current is finished,
* unless a DRV_CLEAR_ONLY bit is set. In this case we just want to
* properly clear object internals without sending any command to the FW
* which also implies there won't be any completion to clear the
* 'pending' list.
*/
if (!list_empty(&o->pending_comp)) {
if (test_bit(RAMROD_DRV_CLR_ONLY, ramrod_flags)) {
DP(BNX2X_MSG_SP, "RAMROD_DRV_CLR_ONLY requested: resetting a pending_comp list\n");
__bnx2x_exe_queue_reset_pending(bp, o);
} else {
return 1;
}
}
/* Run through the pending commands list and create a next
* execution chunk.
*/
while (!list_empty(&o->exe_queue)) {
elem = list_first_entry(&o->exe_queue, struct bnx2x_exeq_elem,
link);
WARN_ON(!elem->cmd_len);
if (cur_len + elem->cmd_len <= o->exe_chunk_len) {
cur_len += elem->cmd_len;
/* Prevent from both lists being empty when moving an
* element. This will allow the call of
* bnx2x_exe_queue_empty() without locking.
*/
list_add_tail(&spacer.link, &o->pending_comp);
mb();
list_move_tail(&elem->link, &o->pending_comp);
list_del(&spacer.link);
} else
break;
}
/* Sanity check */
if (!cur_len)
return 0;
rc = o->execute(bp, o->owner, &o->pending_comp, ramrod_flags);
if (rc < 0)
/* In case of an error return the commands back to the queue
* and reset the pending_comp.
*/
list_splice_init(&o->pending_comp, &o->exe_queue);
else if (!rc)
/* If zero is returned, means there are no outstanding pending
* completions and we may dismiss the pending list.
*/
__bnx2x_exe_queue_reset_pending(bp, o);
return rc;
}
static inline bool bnx2x_exe_queue_empty(struct bnx2x_exe_queue_obj *o)
{
bool empty = list_empty(&o->exe_queue);
/* Don't reorder!!! */
mb();
return empty && list_empty(&o->pending_comp);
}
static inline struct bnx2x_exeq_elem *bnx2x_exe_queue_alloc_elem(
struct bnx2x *bp)
{
DP(BNX2X_MSG_SP, "Allocating a new exe_queue element\n");
return kzalloc(sizeof(struct bnx2x_exeq_elem), GFP_ATOMIC);
}
/************************ raw_obj functions ***********************************/
static bool bnx2x_raw_check_pending(struct bnx2x_raw_obj *o)
{
return !!test_bit(o->state, o->pstate);
}
static void bnx2x_raw_clear_pending(struct bnx2x_raw_obj *o)
{
smp_mb__before_clear_bit();
clear_bit(o->state, o->pstate);
smp_mb__after_clear_bit();
}
static void bnx2x_raw_set_pending(struct bnx2x_raw_obj *o)
{
smp_mb__before_clear_bit();
set_bit(o->state, o->pstate);
smp_mb__after_clear_bit();
}
/**
* bnx2x_state_wait - wait until the given bit(state) is cleared
*
* @bp: device handle
* @state: state which is to be cleared
* @state_p: state buffer
*
*/
static inline int bnx2x_state_wait(struct bnx2x *bp, int state,
unsigned long *pstate)
{
/* can take a while if any port is running */
int cnt = 5000;
if (CHIP_REV_IS_EMUL(bp))
cnt *= 20;
DP(BNX2X_MSG_SP, "waiting for state to become %d\n", state);
might_sleep();
while (cnt--) {
if (!test_bit(state, pstate)) {
#ifdef BNX2X_STOP_ON_ERROR
DP(BNX2X_MSG_SP, "exit (cnt %d)\n", 5000 - cnt);
#endif
return 0;
}
usleep_range(1000, 2000);
if (bp->panic)
return -EIO;
}
/* timeout! */
BNX2X_ERR("timeout waiting for state %d\n", state);
#ifdef BNX2X_STOP_ON_ERROR
bnx2x_panic();
#endif
return -EBUSY;
}
static int bnx2x_raw_wait(struct bnx2x *bp, struct bnx2x_raw_obj *raw)
{
return bnx2x_state_wait(bp, raw->state, raw->pstate);
}
/***************** Classification verbs: Set/Del MAC/VLAN/VLAN-MAC ************/
/* credit handling callbacks */
static bool bnx2x_get_cam_offset_mac(struct bnx2x_vlan_mac_obj *o, int *offset)
{
struct bnx2x_credit_pool_obj *mp = o->macs_pool;
WARN_ON(!mp);
return mp->get_entry(mp, offset);
}
static bool bnx2x_get_credit_mac(struct bnx2x_vlan_mac_obj *o)
{
struct bnx2x_credit_pool_obj *mp = o->macs_pool;
WARN_ON(!mp);
return mp->get(mp, 1);
}
static bool bnx2x_get_cam_offset_vlan(struct bnx2x_vlan_mac_obj *o, int *offset)
{
struct bnx2x_credit_pool_obj *vp = o->vlans_pool;
WARN_ON(!vp);
return vp->get_entry(vp, offset);
}
static bool bnx2x_get_credit_vlan(struct bnx2x_vlan_mac_obj *o)
{
struct bnx2x_credit_pool_obj *vp = o->vlans_pool;
WARN_ON(!vp);
return vp->get(vp, 1);
}
static bool bnx2x_get_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o)
{
struct bnx2x_credit_pool_obj *mp = o->macs_pool;
struct bnx2x_credit_pool_
bnx2x_sp.rar_EVEREST
版权申诉
99 浏览量
2022-09-21
19:08:22
上传
评论
收藏 40KB RAR 举报
周楷雯
- 粉丝: 80
- 资源: 1万+
最新资源
- 毕业设计基于python矩阵分解的推荐算法研究源码+详细文档+全部数据资料 高分项目.zip
- 基于网络的入侵检测系统源码+数据集+详细文档(高分毕业设计).zip
- 微信小程序源码 旅行故事分享 - 面包旅行App界面设计与文本展示资源下载
- 微信小程序源码 创意互动游戏 - 你画我猜App下载
- 摸底考试_学生版20230305.py
- 课程设计基于FPGA数字钟课程设计源码+课设报告(95分以上).zip
- 基于Java的企业家申报系统设计源码
- Cesium案例,集成各种模型,推演,各种Cesium效果
- 基于Python的Struts2全漏洞扫描利用工具设计源码
- python朴素贝叶斯(Naive Bayes)算法,机器算法
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈