* [Intel-wired-lan] [PATCH iwl-next v3 0/3] ice: split ice_aq_wait_for_event() func into two
@ 2023-08-07 15:58 Przemek Kitszel
2023-08-07 15:58 ` [Intel-wired-lan] [PATCH iwl-next v3 1/3] ice: ice_aq_check_events: fix off-by-one check when filling buffer Przemek Kitszel
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Przemek Kitszel @ 2023-08-07 15:58 UTC (permalink / raw)
To: intel-wired-lan; +Cc: netdev, Tony Nguyen, Simon Horman, Przemek Kitszel
Mitigate race between registering on wait list and receiving
AQ Response from FW.
The first patch fixes bound check to be more inclusive;
the second one refactors code to make the third one smaller,
which is an actual fix for the race.
Thanks Simon Horman for pushing into split, it's easier to follow now.
v3: split into 3 commits
Przemek Kitszel (3):
ice: ice_aq_check_events: fix off-by-one check when filling buffer
ice: embed &ice_rq_event_info event into struct ice_aq_task
ice: split ice_aq_wait_for_event() func into two
drivers/net/ethernet/intel/ice/ice.h | 21 +++-
.../net/ethernet/intel/ice/ice_fw_update.c | 45 ++++----
drivers/net/ethernet/intel/ice/ice_main.c | 100 +++++++++---------
3 files changed, 94 insertions(+), 72 deletions(-)
base-commit: 1efaa6ca8af14114dafb99924bc922daa135f870
--
2.40.1
_______________________________________________
Intel-wired-lan mailing list
Intel-wired-lan@osuosl.org
https://lists.osuosl.org/mailman/listinfo/intel-wired-lan
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Intel-wired-lan] [PATCH iwl-next v3 1/3] ice: ice_aq_check_events: fix off-by-one check when filling buffer
2023-08-07 15:58 [Intel-wired-lan] [PATCH iwl-next v3 0/3] ice: split ice_aq_wait_for_event() func into two Przemek Kitszel
@ 2023-08-07 15:58 ` Przemek Kitszel
2023-08-08 18:06 ` Tony Nguyen
2023-08-07 15:58 ` [Intel-wired-lan] [PATCH iwl-next v3 2/3] ice: embed &ice_rq_event_info event into struct ice_aq_task Przemek Kitszel
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: Przemek Kitszel @ 2023-08-07 15:58 UTC (permalink / raw)
To: intel-wired-lan; +Cc: netdev, Tony Nguyen, Simon Horman, Przemek Kitszel
Allow task's event buffer to be filled also in the case that it's size
is exactly the size of the message.
Fixes: d69ea414c9b4 ("ice: implement device flash update via devlink")
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
drivers/net/ethernet/intel/ice/ice_main.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index a73895483e6c..f2ad2153589a 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -1357,7 +1357,9 @@ int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout,
static void ice_aq_check_events(struct ice_pf *pf, u16 opcode,
struct ice_rq_event_info *event)
{
+ struct ice_rq_event_info *task_ev;
struct ice_aq_task *task;
+
bool found = false;
spin_lock_bh(&pf->aq_wait_lock);
@@ -1365,15 +1367,15 @@ static void ice_aq_check_events(struct ice_pf *pf, u16 opcode,
if (task->state || task->opcode != opcode)
continue;
- memcpy(&task->event->desc, &event->desc, sizeof(event->desc));
- task->event->msg_len = event->msg_len;
+ task_ev = task->event;
+ memcpy(&task_ev->desc, &event->desc, sizeof(event->desc));
+ task_ev->msg_len = event->msg_len;
/* Only copy the data buffer if a destination was set */
- if (task->event->msg_buf &&
- task->event->buf_len > event->buf_len) {
- memcpy(task->event->msg_buf, event->msg_buf,
+ if (task_ev->msg_buf && task_ev->buf_len >= event->buf_len) {
+ memcpy(task_ev->msg_buf, event->msg_buf,
event->buf_len);
- task->event->buf_len = event->buf_len;
+ task_ev->buf_len = event->buf_len;
}
task->state = ICE_AQ_TASK_COMPLETE;
--
2.40.1
_______________________________________________
Intel-wired-lan mailing list
Intel-wired-lan@osuosl.org
https://lists.osuosl.org/mailman/listinfo/intel-wired-lan
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Intel-wired-lan] [PATCH iwl-next v3 2/3] ice: embed &ice_rq_event_info event into struct ice_aq_task
2023-08-07 15:58 [Intel-wired-lan] [PATCH iwl-next v3 0/3] ice: split ice_aq_wait_for_event() func into two Przemek Kitszel
2023-08-07 15:58 ` [Intel-wired-lan] [PATCH iwl-next v3 1/3] ice: ice_aq_check_events: fix off-by-one check when filling buffer Przemek Kitszel
@ 2023-08-07 15:58 ` Przemek Kitszel
2023-08-08 18:06 ` Tony Nguyen
2023-08-07 15:58 ` [Intel-wired-lan] [PATCH iwl-next v3 3/3] ice: split ice_aq_wait_for_event() func into two Przemek Kitszel
2023-08-07 16:45 ` [Intel-wired-lan] [PATCH iwl-next v3 0/3] " Keller, Jacob E
3 siblings, 1 reply; 8+ messages in thread
From: Przemek Kitszel @ 2023-08-07 15:58 UTC (permalink / raw)
To: intel-wired-lan; +Cc: netdev, Tony Nguyen, Simon Horman, Przemek Kitszel
Expose struct ice_aq_task to callers,
what takes burden of memory ownership out from AQ-wait family of functions,
and reduces need for heap-based allocations.
Embed struct ice_rq_event_info event into struct ice_aq_task
(instead of it being a ptr). to remove some more code from the callers.
Subsequent commit will improve more based on this one.
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
add/remove: 0/0 grow/shrink: 3/1 up/down: 266/-68 (198)
---
drivers/net/ethernet/intel/ice/ice.h | 20 ++++++++-
.../net/ethernet/intel/ice/ice_fw_update.c | 42 +++++++++----------
drivers/net/ethernet/intel/ice/ice_main.c | 29 ++-----------
3 files changed, 42 insertions(+), 49 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 34be1cb1e28f..6346283c5d14 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -931,8 +931,24 @@ void ice_fdir_release_flows(struct ice_hw *hw);
void ice_fdir_replay_flows(struct ice_hw *hw);
void ice_fdir_replay_fltrs(struct ice_pf *pf);
int ice_fdir_create_dflt_rules(struct ice_pf *pf);
-int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout,
- struct ice_rq_event_info *event);
+
+enum ice_aq_task_state {
+ ICE_AQ_TASK_WAITING,
+ ICE_AQ_TASK_COMPLETE,
+ ICE_AQ_TASK_CANCELED,
+};
+
+struct ice_aq_task {
+ struct hlist_node entry;
+ struct ice_rq_event_info event;
+ enum ice_aq_task_state state;
+ u16 opcode;
+};
+
+
+int ice_aq_wait_for_event(struct ice_pf *pf, struct ice_aq_task *task,
+ u16 opcode, unsigned long timeout);
+
int ice_open(struct net_device *netdev);
int ice_open_internal(struct net_device *netdev);
int ice_stop(struct net_device *netdev);
diff --git a/drivers/net/ethernet/intel/ice/ice_fw_update.c b/drivers/net/ethernet/intel/ice/ice_fw_update.c
index 3dc5662d62a6..819b70823e9c 100644
--- a/drivers/net/ethernet/intel/ice/ice_fw_update.c
+++ b/drivers/net/ethernet/intel/ice/ice_fw_update.c
@@ -293,13 +293,12 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
{
u16 completion_module, completion_retval;
struct device *dev = ice_pf_to_dev(pf);
- struct ice_rq_event_info event;
+ struct ice_aq_task task = {};
struct ice_hw *hw = &pf->hw;
+ struct ice_aq_desc *desc;
u32 completion_offset;
int err;
- memset(&event, 0, sizeof(event));
-
dev_dbg(dev, "Writing block of %u bytes for module 0x%02x at offset %u\n",
block_size, module, offset);
@@ -319,7 +318,7 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
* is conservative and is intended to prevent failure to update when
* firmware is slow to respond.
*/
- err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_write, 15 * HZ, &event);
+ err = ice_aq_wait_for_event(pf, &task, ice_aqc_opc_nvm_write, 15 * HZ);
if (err) {
dev_err(dev, "Timed out while trying to flash module 0x%02x with block of size %u at offset %u, err %d\n",
module, block_size, offset, err);
@@ -327,11 +326,12 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
return -EIO;
}
- completion_module = le16_to_cpu(event.desc.params.nvm.module_typeid);
- completion_retval = le16_to_cpu(event.desc.retval);
+ desc = &task.event.desc;
+ completion_module = le16_to_cpu(desc->params.nvm.module_typeid);
+ completion_retval = le16_to_cpu(desc->retval);
- completion_offset = le16_to_cpu(event.desc.params.nvm.offset_low);
- completion_offset |= event.desc.params.nvm.offset_high << 16;
+ completion_offset = le16_to_cpu(desc->params.nvm.offset_low);
+ completion_offset |= desc->params.nvm.offset_high << 16;
if (completion_module != module) {
dev_err(dev, "Unexpected module_typeid in write completion: got 0x%x, expected 0x%x\n",
@@ -363,8 +363,8 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
*/
if (reset_level && last_cmd && module == ICE_SR_1ST_NVM_BANK_PTR) {
if (hw->dev_caps.common_cap.pcie_reset_avoidance) {
- *reset_level = (event.desc.params.nvm.cmd_flags &
- ICE_AQC_NVM_RESET_LVL_M);
+ *reset_level = desc->params.nvm.cmd_flags &
+ ICE_AQC_NVM_RESET_LVL_M;
dev_dbg(dev, "Firmware reported required reset level as %u\n",
*reset_level);
} else {
@@ -479,15 +479,14 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component,
{
u16 completion_module, completion_retval;
struct device *dev = ice_pf_to_dev(pf);
- struct ice_rq_event_info event;
+ struct ice_aq_task task = {};
struct ice_hw *hw = &pf->hw;
+ struct ice_aq_desc *desc;
struct devlink *devlink;
int err;
dev_dbg(dev, "Beginning erase of flash component '%s', module 0x%02x\n", component, module);
- memset(&event, 0, sizeof(event));
-
devlink = priv_to_devlink(pf);
devlink_flash_update_timeout_notify(devlink, "Erasing", component, ICE_FW_ERASE_TIMEOUT);
@@ -502,7 +501,7 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component,
goto out_notify_devlink;
}
- err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_erase, ICE_FW_ERASE_TIMEOUT * HZ, &event);
+ err = ice_aq_wait_for_event(pf, &task, ice_aqc_opc_nvm_erase, ICE_FW_ERASE_TIMEOUT * HZ);
if (err) {
dev_err(dev, "Timed out waiting for firmware to respond with erase completion for %s (module 0x%02x), err %d\n",
component, module, err);
@@ -510,8 +509,9 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component,
goto out_notify_devlink;
}
- completion_module = le16_to_cpu(event.desc.params.nvm.module_typeid);
- completion_retval = le16_to_cpu(event.desc.retval);
+ desc = &task.event.desc;
+ completion_module = le16_to_cpu(desc->params.nvm.module_typeid);
+ completion_retval = le16_to_cpu(desc->retval);
if (completion_module != module) {
dev_err(dev, "Unexpected module_typeid in erase completion for %s: got 0x%x, expected 0x%x\n",
@@ -560,14 +560,12 @@ ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags,
u8 *emp_reset_available, struct netlink_ext_ack *extack)
{
struct device *dev = ice_pf_to_dev(pf);
- struct ice_rq_event_info event;
+ struct ice_aq_task task = {};
struct ice_hw *hw = &pf->hw;
u16 completion_retval;
u8 response_flags;
int err;
- memset(&event, 0, sizeof(event));
-
err = ice_nvm_write_activate(hw, activate_flags, &response_flags);
if (err) {
dev_err(dev, "Failed to switch active flash banks, err %d aq_err %s\n",
@@ -592,8 +590,8 @@ ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags,
}
}
- err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_write_activate, 30 * HZ,
- &event);
+ err = ice_aq_wait_for_event(pf, &task, ice_aqc_opc_nvm_write_activate,
+ 30 * HZ);
if (err) {
dev_err(dev, "Timed out waiting for firmware to switch active flash banks, err %d\n",
err);
@@ -601,7 +599,7 @@ ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags,
return err;
}
- completion_retval = le16_to_cpu(event.desc.retval);
+ completion_retval = le16_to_cpu(task.event.desc.retval);
if (completion_retval) {
dev_err(dev, "Firmware failed to switch active flash banks aq_err %s\n",
ice_aq_str((enum ice_aq_err)completion_retval));
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index f2ad2153589a..36772215b8c6 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -1250,26 +1250,12 @@ ice_handle_link_event(struct ice_pf *pf, struct ice_rq_event_info *event)
return status;
}
-enum ice_aq_task_state {
- ICE_AQ_TASK_WAITING = 0,
- ICE_AQ_TASK_COMPLETE,
- ICE_AQ_TASK_CANCELED,
-};
-
-struct ice_aq_task {
- struct hlist_node entry;
-
- u16 opcode;
- struct ice_rq_event_info *event;
- enum ice_aq_task_state state;
-};
-
/**
* ice_aq_wait_for_event - Wait for an AdminQ event from firmware
* @pf: pointer to the PF private structure
+ * @task: ptr to task structure
* @opcode: the opcode to wait for
* @timeout: how long to wait, in jiffies
- * @event: storage for the event info
*
* Waits for a specific AdminQ completion event on the ARQ for a given PF. The
* current thread will be put to sleep until the specified event occurs or
@@ -1281,22 +1267,16 @@ struct ice_aq_task {
*
* Returns: zero on success, or a negative error code on failure.
*/
-int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout,
- struct ice_rq_event_info *event)
+int ice_aq_wait_for_event(struct ice_pf *pf, struct ice_aq_task *task,
+ u16 opcode, unsigned long timeout)
{
struct device *dev = ice_pf_to_dev(pf);
- struct ice_aq_task *task;
unsigned long start;
long ret;
int err;
- task = kzalloc(sizeof(*task), GFP_KERNEL);
- if (!task)
- return -ENOMEM;
-
INIT_HLIST_NODE(&task->entry);
task->opcode = opcode;
- task->event = event;
task->state = ICE_AQ_TASK_WAITING;
spin_lock_bh(&pf->aq_wait_lock);
@@ -1331,7 +1311,6 @@ int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout,
spin_lock_bh(&pf->aq_wait_lock);
hlist_del(&task->entry);
spin_unlock_bh(&pf->aq_wait_lock);
- kfree(task);
return err;
}
@@ -1367,7 +1346,7 @@ static void ice_aq_check_events(struct ice_pf *pf, u16 opcode,
if (task->state || task->opcode != opcode)
continue;
- task_ev = task->event;
+ task_ev = &task->event;
memcpy(&task_ev->desc, &event->desc, sizeof(event->desc));
task_ev->msg_len = event->msg_len;
--
2.40.1
_______________________________________________
Intel-wired-lan mailing list
Intel-wired-lan@osuosl.org
https://lists.osuosl.org/mailman/listinfo/intel-wired-lan
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Intel-wired-lan] [PATCH iwl-next v3 3/3] ice: split ice_aq_wait_for_event() func into two
2023-08-07 15:58 [Intel-wired-lan] [PATCH iwl-next v3 0/3] ice: split ice_aq_wait_for_event() func into two Przemek Kitszel
2023-08-07 15:58 ` [Intel-wired-lan] [PATCH iwl-next v3 1/3] ice: ice_aq_check_events: fix off-by-one check when filling buffer Przemek Kitszel
2023-08-07 15:58 ` [Intel-wired-lan] [PATCH iwl-next v3 2/3] ice: embed &ice_rq_event_info event into struct ice_aq_task Przemek Kitszel
@ 2023-08-07 15:58 ` Przemek Kitszel
2023-08-07 16:45 ` [Intel-wired-lan] [PATCH iwl-next v3 0/3] " Keller, Jacob E
3 siblings, 0 replies; 8+ messages in thread
From: Przemek Kitszel @ 2023-08-07 15:58 UTC (permalink / raw)
To: intel-wired-lan; +Cc: netdev, Tony Nguyen, Simon Horman, Przemek Kitszel
Mitigate race between registering on wait list and receiving
AQ Response from FW.
ice_aq_prep_for_event() should be called before sending AQ command,
ice_aq_wait_for_event() should be called after sending AQ command,
to wait for AQ Response.
Please note, that this was found by reading the code,
an actual race has not yet materialized.
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
add/remove: 2/0 grow/shrink: 1/3 up/down: 131/-61 (70)
---
drivers/net/ethernet/intel/ice/ice.h | 7 +-
.../net/ethernet/intel/ice/ice_fw_update.c | 13 ++--
drivers/net/ethernet/intel/ice/ice_main.c | 67 ++++++++++++-------
3 files changed, 57 insertions(+), 30 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 6346283c5d14..3ac645afbc8d 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -933,6 +933,7 @@ void ice_fdir_replay_fltrs(struct ice_pf *pf);
int ice_fdir_create_dflt_rules(struct ice_pf *pf);
enum ice_aq_task_state {
+ ICE_AQ_TASK_NOT_PREPARED,
ICE_AQ_TASK_WAITING,
ICE_AQ_TASK_COMPLETE,
ICE_AQ_TASK_CANCELED,
@@ -945,10 +946,10 @@ struct ice_aq_task {
u16 opcode;
};
-
+void ice_aq_prep_for_event(struct ice_pf *pf, struct ice_aq_task *task,
+ u16 opcode);
int ice_aq_wait_for_event(struct ice_pf *pf, struct ice_aq_task *task,
- u16 opcode, unsigned long timeout);
-
+ unsigned long timeout);
int ice_open(struct net_device *netdev);
int ice_open_internal(struct net_device *netdev);
int ice_stop(struct net_device *netdev);
diff --git a/drivers/net/ethernet/intel/ice/ice_fw_update.c b/drivers/net/ethernet/intel/ice/ice_fw_update.c
index 819b70823e9c..319a2d6fe26c 100644
--- a/drivers/net/ethernet/intel/ice/ice_fw_update.c
+++ b/drivers/net/ethernet/intel/ice/ice_fw_update.c
@@ -302,6 +302,8 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
dev_dbg(dev, "Writing block of %u bytes for module 0x%02x at offset %u\n",
block_size, module, offset);
+ ice_aq_prep_for_event(pf, &task, ice_aqc_opc_nvm_write);
+
err = ice_aq_update_nvm(hw, module, offset, block_size, block,
last_cmd, 0, NULL);
if (err) {
@@ -318,7 +320,7 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
* is conservative and is intended to prevent failure to update when
* firmware is slow to respond.
*/
- err = ice_aq_wait_for_event(pf, &task, ice_aqc_opc_nvm_write, 15 * HZ);
+ err = ice_aq_wait_for_event(pf, &task, 15 * HZ);
if (err) {
dev_err(dev, "Timed out while trying to flash module 0x%02x with block of size %u at offset %u, err %d\n",
module, block_size, offset, err);
@@ -491,6 +493,8 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component,
devlink_flash_update_timeout_notify(devlink, "Erasing", component, ICE_FW_ERASE_TIMEOUT);
+ ice_aq_prep_for_event(pf, &task, ice_aqc_opc_nvm_erase);
+
err = ice_aq_erase_nvm(hw, module, NULL);
if (err) {
dev_err(dev, "Failed to erase %s (module 0x%02x), err %d aq_err %s\n",
@@ -501,7 +505,7 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component,
goto out_notify_devlink;
}
- err = ice_aq_wait_for_event(pf, &task, ice_aqc_opc_nvm_erase, ICE_FW_ERASE_TIMEOUT * HZ);
+ err = ice_aq_wait_for_event(pf, &task, ICE_FW_ERASE_TIMEOUT * HZ);
if (err) {
dev_err(dev, "Timed out waiting for firmware to respond with erase completion for %s (module 0x%02x), err %d\n",
component, module, err);
@@ -566,6 +570,8 @@ ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags,
u8 response_flags;
int err;
+ ice_aq_prep_for_event(pf, &task, ice_aqc_opc_nvm_write_activate);
+
err = ice_nvm_write_activate(hw, activate_flags, &response_flags);
if (err) {
dev_err(dev, "Failed to switch active flash banks, err %d aq_err %s\n",
@@ -590,8 +596,7 @@ ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags,
}
}
- err = ice_aq_wait_for_event(pf, &task, ice_aqc_opc_nvm_write_activate,
- 30 * HZ);
+ err = ice_aq_wait_for_event(pf, &task, 30 * HZ);
if (err) {
dev_err(dev, "Timed out waiting for firmware to switch active flash banks, err %d\n",
err);
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 36772215b8c6..edbbadd20845 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -1251,30 +1251,24 @@ ice_handle_link_event(struct ice_pf *pf, struct ice_rq_event_info *event)
}
/**
- * ice_aq_wait_for_event - Wait for an AdminQ event from firmware
+ * ice_aq_prep_for_event - Prepare to wait for an AdminQ event from firmware
* @pf: pointer to the PF private structure
- * @task: ptr to task structure
+ * @task: intermediate helper storage and identifier for waiting
* @opcode: the opcode to wait for
- * @timeout: how long to wait, in jiffies
*
- * Waits for a specific AdminQ completion event on the ARQ for a given PF. The
- * current thread will be put to sleep until the specified event occurs or
- * until the given timeout is reached.
+ * Prepares to wait for a specific AdminQ completion event on the ARQ for
+ * a given PF. Actual wait would be done by a call to ice_aq_wait_for_event().
*
- * To obtain only the descriptor contents, pass an event without an allocated
- * msg_buf. If the complete data buffer is desired, allocate the
- * event->msg_buf with enough space ahead of time.
+ * Calls are separated to allow caller registering for event before sending
+ * the command, which mitigates a race between registering and FW responding.
*
- * Returns: zero on success, or a negative error code on failure.
+ * To obtain only the descriptor contents, pass an task->event with null
+ * msg_buf. If the complete data buffer is desired, allocate the
+ * task->event.msg_buf with enough space ahead of time.
*/
-int ice_aq_wait_for_event(struct ice_pf *pf, struct ice_aq_task *task,
- u16 opcode, unsigned long timeout)
+void ice_aq_prep_for_event(struct ice_pf *pf, struct ice_aq_task *task,
+ u16 opcode)
{
- struct device *dev = ice_pf_to_dev(pf);
- unsigned long start;
- long ret;
- int err;
-
INIT_HLIST_NODE(&task->entry);
task->opcode = opcode;
task->state = ICE_AQ_TASK_WAITING;
@@ -1282,12 +1276,37 @@ int ice_aq_wait_for_event(struct ice_pf *pf, struct ice_aq_task *task,
spin_lock_bh(&pf->aq_wait_lock);
hlist_add_head(&task->entry, &pf->aq_wait_list);
spin_unlock_bh(&pf->aq_wait_lock);
+}
- start = jiffies;
+/**
+ * ice_aq_wait_for_event - Wait for an AdminQ event from firmware
+ * @pf: pointer to the PF private structure
+ * @task: ptr prepared by ice_aq_prep_for_event()
+ * @timeout: how long to wait, in jiffies
+ *
+ * Waits for a specific AdminQ completion event on the ARQ for a given PF. The
+ * current thread will be put to sleep until the specified event occurs or
+ * until the given timeout is reached.
+ *
+ * Returns: zero on success, or a negative error code on failure.
+ */
+int ice_aq_wait_for_event(struct ice_pf *pf, struct ice_aq_task *task,
+ unsigned long timeout)
+{
+ enum ice_aq_task_state *state = &task->state;
+ struct device *dev = ice_pf_to_dev(pf);
+ unsigned long start = jiffies;
+ long ret;
+ int err;
- ret = wait_event_interruptible_timeout(pf->aq_wait_queue, task->state,
+ ret = wait_event_interruptible_timeout(pf->aq_wait_queue,
+ *state != ICE_AQ_TASK_WAITING,
timeout);
- switch (task->state) {
+ switch (*state) {
+ case ICE_AQ_TASK_NOT_PREPARED:
+ WARN(1, "call to %s without ice_aq_prep_for_event()", __func__);
+ err = -EINVAL;
+ break;
case ICE_AQ_TASK_WAITING:
err = ret < 0 ? ret : -ETIMEDOUT;
break;
@@ -1298,7 +1317,7 @@ int ice_aq_wait_for_event(struct ice_pf *pf, struct ice_aq_task *task,
err = ret < 0 ? ret : 0;
break;
default:
- WARN(1, "Unexpected AdminQ wait task state %u", task->state);
+ WARN(1, "Unexpected AdminQ wait task state %u", *state);
err = -EINVAL;
break;
}
@@ -1306,7 +1325,7 @@ int ice_aq_wait_for_event(struct ice_pf *pf, struct ice_aq_task *task,
dev_dbg(dev, "Waited %u msecs (max %u msecs) for firmware response to op 0x%04x\n",
jiffies_to_msecs(jiffies - start),
jiffies_to_msecs(timeout),
- opcode);
+ task->opcode);
spin_lock_bh(&pf->aq_wait_lock);
hlist_del(&task->entry);
@@ -1343,7 +1362,9 @@ static void ice_aq_check_events(struct ice_pf *pf, u16 opcode,
spin_lock_bh(&pf->aq_wait_lock);
hlist_for_each_entry(task, &pf->aq_wait_list, entry) {
- if (task->state || task->opcode != opcode)
+ if (task->state != ICE_AQ_TASK_WAITING)
+ continue;
+ if (task->opcode != opcode)
continue;
task_ev = &task->event;
--
2.40.1
_______________________________________________
Intel-wired-lan mailing list
Intel-wired-lan@osuosl.org
https://lists.osuosl.org/mailman/listinfo/intel-wired-lan
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v3 0/3] ice: split ice_aq_wait_for_event() func into two
2023-08-07 15:58 [Intel-wired-lan] [PATCH iwl-next v3 0/3] ice: split ice_aq_wait_for_event() func into two Przemek Kitszel
` (2 preceding siblings ...)
2023-08-07 15:58 ` [Intel-wired-lan] [PATCH iwl-next v3 3/3] ice: split ice_aq_wait_for_event() func into two Przemek Kitszel
@ 2023-08-07 16:45 ` Keller, Jacob E
3 siblings, 0 replies; 8+ messages in thread
From: Keller, Jacob E @ 2023-08-07 16:45 UTC (permalink / raw)
To: Kitszel, Przemyslaw, intel-wired-lan@lists.osuosl.org
Cc: netdev@vger.kernel.org, Nguyen, Anthony L, Simon Horman
> -----Original Message-----
> From: Kitszel, Przemyslaw <przemyslaw.kitszel@intel.com>
> Sent: Monday, August 7, 2023 8:59 AM
> To: intel-wired-lan@lists.osuosl.org
> Cc: netdev@vger.kernel.org; Keller, Jacob E <jacob.e.keller@intel.com>; Nguyen,
> Anthony L <anthony.l.nguyen@intel.com>; Simon Horman <horms@kernel.org>;
> Kitszel, Przemyslaw <przemyslaw.kitszel@intel.com>
> Subject: [PATCH iwl-next v3 0/3] ice: split ice_aq_wait_for_event() func into two
>
> Mitigate race between registering on wait list and receiving
> AQ Response from FW.
>
> The first patch fixes bound check to be more inclusive;
> the second one refactors code to make the third one smaller,
> which is an actual fix for the race.
>
> Thanks Simon Horman for pushing into split, it's easier to follow now.
>
> v3: split into 3 commits
>
> Przemek Kitszel (3):
> ice: ice_aq_check_events: fix off-by-one check when filling buffer
> ice: embed &ice_rq_event_info event into struct ice_aq_task
> ice: split ice_aq_wait_for_event() func into two
>
> drivers/net/ethernet/intel/ice/ice.h | 21 +++-
> .../net/ethernet/intel/ice/ice_fw_update.c | 45 ++++----
> drivers/net/ethernet/intel/ice/ice_main.c | 100 +++++++++---------
> 3 files changed, 94 insertions(+), 72 deletions(-)
>
>
> base-commit: 1efaa6ca8af14114dafb99924bc922daa135f870
> --
> 2.40.1
This series looks good to me.
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Thanks,
Jake
_______________________________________________
Intel-wired-lan mailing list
Intel-wired-lan@osuosl.org
https://lists.osuosl.org/mailman/listinfo/intel-wired-lan
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v3 1/3] ice: ice_aq_check_events: fix off-by-one check when filling buffer
2023-08-07 15:58 ` [Intel-wired-lan] [PATCH iwl-next v3 1/3] ice: ice_aq_check_events: fix off-by-one check when filling buffer Przemek Kitszel
@ 2023-08-08 18:06 ` Tony Nguyen
2023-08-08 21:14 ` Przemek Kitszel
0 siblings, 1 reply; 8+ messages in thread
From: Tony Nguyen @ 2023-08-08 18:06 UTC (permalink / raw)
To: Przemek Kitszel, intel-wired-lan; +Cc: netdev, Simon Horman
On 8/7/2023 8:58 AM, Przemek Kitszel wrote:
> Allow task's event buffer to be filled also in the case that it's size
> is exactly the size of the message.
>
> Fixes: d69ea414c9b4 ("ice: implement device flash update via devlink")
> Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
> ---
> drivers/net/ethernet/intel/ice/ice_main.c | 14 ++++++++------
> 1 file changed, 8 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
> index a73895483e6c..f2ad2153589a 100644
> --- a/drivers/net/ethernet/intel/ice/ice_main.c
> +++ b/drivers/net/ethernet/intel/ice/ice_main.c
> @@ -1357,7 +1357,9 @@ int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout,
> static void ice_aq_check_events(struct ice_pf *pf, u16 opcode,
> struct ice_rq_event_info *event)
> {
> + struct ice_rq_event_info *task_ev;
> struct ice_aq_task *task;
> +
Accidental newline?
> bool found = false;
>
> spin_lock_bh(&pf->aq_wait_lock);
> @@ -1365,15 +1367,15 @@ static void ice_aq_check_events(struct ice_pf *pf, u16 opcode,
> if (task->state || task->opcode != opcode)
> continue;
>
> - memcpy(&task->event->desc, &event->desc, sizeof(event->desc));
> - task->event->msg_len = event->msg_len;
> + task_ev = task->event;
> + memcpy(&task_ev->desc, &event->desc, sizeof(event->desc));
> + task_ev->msg_len = event->msg_len;
>
> /* Only copy the data buffer if a destination was set */
> - if (task->event->msg_buf &&
> - task->event->buf_len > event->buf_len) {
> - memcpy(task->event->msg_buf, event->msg_buf,
> + if (task_ev->msg_buf && task_ev->buf_len >= event->buf_len) {
> + memcpy(task_ev->msg_buf, event->msg_buf,
> event->buf_len);
> - task->event->buf_len = event->buf_len;
> + task_ev->buf_len = event->buf_len;
> }
>
> task->state = ICE_AQ_TASK_COMPLETE;
_______________________________________________
Intel-wired-lan mailing list
Intel-wired-lan@osuosl.org
https://lists.osuosl.org/mailman/listinfo/intel-wired-lan
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v3 2/3] ice: embed &ice_rq_event_info event into struct ice_aq_task
2023-08-07 15:58 ` [Intel-wired-lan] [PATCH iwl-next v3 2/3] ice: embed &ice_rq_event_info event into struct ice_aq_task Przemek Kitszel
@ 2023-08-08 18:06 ` Tony Nguyen
0 siblings, 0 replies; 8+ messages in thread
From: Tony Nguyen @ 2023-08-08 18:06 UTC (permalink / raw)
To: Przemek Kitszel, intel-wired-lan; +Cc: netdev, Simon Horman
On 8/7/2023 8:58 AM, Przemek Kitszel wrote:
> Expose struct ice_aq_task to callers,
> what takes burden of memory ownership out from AQ-wait family of functions,
> and reduces need for heap-based allocations.
>
> Embed struct ice_rq_event_info event into struct ice_aq_task
> (instead of it being a ptr). to remove some more code from the callers.
>
> Subsequent commit will improve more based on this one.
>
> Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
>
> ---
> add/remove: 0/0 grow/shrink: 3/1 up/down: 266/-68 (198)
> ---
> drivers/net/ethernet/intel/ice/ice.h | 20 ++++++++-
> .../net/ethernet/intel/ice/ice_fw_update.c | 42 +++++++++----------
> drivers/net/ethernet/intel/ice/ice_main.c | 29 ++-----------
> 3 files changed, 42 insertions(+), 49 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
> index 34be1cb1e28f..6346283c5d14 100644
> --- a/drivers/net/ethernet/intel/ice/ice.h
> +++ b/drivers/net/ethernet/intel/ice/ice.h
> @@ -931,8 +931,24 @@ void ice_fdir_release_flows(struct ice_hw *hw);
> void ice_fdir_replay_flows(struct ice_hw *hw);
> void ice_fdir_replay_fltrs(struct ice_pf *pf);
> int ice_fdir_create_dflt_rules(struct ice_pf *pf);
> -int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout,
> - struct ice_rq_event_info *event);
> +
> +enum ice_aq_task_state {
> + ICE_AQ_TASK_WAITING,
> + ICE_AQ_TASK_COMPLETE,
> + ICE_AQ_TASK_CANCELED,
> +};
> +
> +struct ice_aq_task {
> + struct hlist_node entry;
> + struct ice_rq_event_info event;
> + enum ice_aq_task_state state;
> + u16 opcode;
> +};
> +
> +
CHECK: Please don't use multiple blank lines
> +int ice_aq_wait_for_event(struct ice_pf *pf, struct ice_aq_task *task,
> + u16 opcode, unsigned long timeout);
> +
> int ice_open(struct net_device *netdev);
> int ice_open_internal(struct net_device *netdev);
> int ice_stop(struct net_device *netdev);
_______________________________________________
Intel-wired-lan mailing list
Intel-wired-lan@osuosl.org
https://lists.osuosl.org/mailman/listinfo/intel-wired-lan
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v3 1/3] ice: ice_aq_check_events: fix off-by-one check when filling buffer
2023-08-08 18:06 ` Tony Nguyen
@ 2023-08-08 21:14 ` Przemek Kitszel
0 siblings, 0 replies; 8+ messages in thread
From: Przemek Kitszel @ 2023-08-08 21:14 UTC (permalink / raw)
To: Tony Nguyen, intel-wired-lan; +Cc: netdev, Simon Horman
On 8/8/23 20:06, Tony Nguyen wrote:
>
>
> On 8/7/2023 8:58 AM, Przemek Kitszel wrote:
>> Allow task's event buffer to be filled also in the case that it's size
>> is exactly the size of the message.
>>
>> Fixes: d69ea414c9b4 ("ice: implement device flash update via devlink")
>> Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
>> ---
>> drivers/net/ethernet/intel/ice/ice_main.c | 14 ++++++++------
>> 1 file changed, 8 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/intel/ice/ice_main.c
>> b/drivers/net/ethernet/intel/ice/ice_main.c
>> index a73895483e6c..f2ad2153589a 100644
>> --- a/drivers/net/ethernet/intel/ice/ice_main.c
>> +++ b/drivers/net/ethernet/intel/ice/ice_main.c
>> @@ -1357,7 +1357,9 @@ int ice_aq_wait_for_event(struct ice_pf *pf, u16
>> opcode, unsigned long timeout,
>> static void ice_aq_check_events(struct ice_pf *pf, u16 opcode,
>> struct ice_rq_event_info *event)
>> {
>> + struct ice_rq_event_info *task_ev;
>> struct ice_aq_task *task;
>> +
>
> Accidental newline?
Ouch, sorry :( and thank for catching it!
>
>> bool found = false;
>> spin_lock_bh(&pf->aq_wait_lock);
>> @@ -1365,15 +1367,15 @@ static void ice_aq_check_events(struct ice_pf
>> *pf, u16 opcode,
>> if (task->state || task->opcode != opcode)
>> continue;
>> - memcpy(&task->event->desc, &event->desc, sizeof(event->desc));
>> - task->event->msg_len = event->msg_len;
>> + task_ev = task->event;
>> + memcpy(&task_ev->desc, &event->desc, sizeof(event->desc));
>> + task_ev->msg_len = event->msg_len;
>> /* Only copy the data buffer if a destination was set */
>> - if (task->event->msg_buf &&
>> - task->event->buf_len > event->buf_len) {
>> - memcpy(task->event->msg_buf, event->msg_buf,
>> + if (task_ev->msg_buf && task_ev->buf_len >= event->buf_len) {
>> + memcpy(task_ev->msg_buf, event->msg_buf,
>> event->buf_len);
>> - task->event->buf_len = event->buf_len;
>> + task_ev->buf_len = event->buf_len;
>> }
>> task->state = ICE_AQ_TASK_COMPLETE;
_______________________________________________
Intel-wired-lan mailing list
Intel-wired-lan@osuosl.org
https://lists.osuosl.org/mailman/listinfo/intel-wired-lan
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2023-08-08 21:14 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-08-07 15:58 [Intel-wired-lan] [PATCH iwl-next v3 0/3] ice: split ice_aq_wait_for_event() func into two Przemek Kitszel
2023-08-07 15:58 ` [Intel-wired-lan] [PATCH iwl-next v3 1/3] ice: ice_aq_check_events: fix off-by-one check when filling buffer Przemek Kitszel
2023-08-08 18:06 ` Tony Nguyen
2023-08-08 21:14 ` Przemek Kitszel
2023-08-07 15:58 ` [Intel-wired-lan] [PATCH iwl-next v3 2/3] ice: embed &ice_rq_event_info event into struct ice_aq_task Przemek Kitszel
2023-08-08 18:06 ` Tony Nguyen
2023-08-07 15:58 ` [Intel-wired-lan] [PATCH iwl-next v3 3/3] ice: split ice_aq_wait_for_event() func into two Przemek Kitszel
2023-08-07 16:45 ` [Intel-wired-lan] [PATCH iwl-next v3 0/3] " Keller, Jacob E
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox