|
@@ -3363,6 +3363,50 @@ static int __subn_get_opa_cong_setting(struct opa_smp *smp, u32 am,
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Apply congestion control information stored in the ppd to the
|
|
|
+ * active structure.
|
|
|
+ */
|
|
|
+static void apply_cc_state(struct hfi1_pportdata *ppd)
|
|
|
+{
|
|
|
+ struct cc_state *old_cc_state, *new_cc_state;
|
|
|
+
|
|
|
+ new_cc_state = kzalloc(sizeof(*new_cc_state), GFP_KERNEL);
|
|
|
+ if (!new_cc_state)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Hold the lock for updating *and* to prevent ppd information
|
|
|
+ * from changing during the update.
|
|
|
+ */
|
|
|
+ spin_lock(&ppd->cc_state_lock);
|
|
|
+
|
|
|
+ old_cc_state = get_cc_state(ppd);
|
|
|
+ if (!old_cc_state) {
|
|
|
+ /* never active, or shutting down */
|
|
|
+ spin_unlock(&ppd->cc_state_lock);
|
|
|
+ kfree(new_cc_state);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ *new_cc_state = *old_cc_state;
|
|
|
+
|
|
|
+ new_cc_state->cct.ccti_limit = ppd->total_cct_entry - 1;
|
|
|
+ memcpy(new_cc_state->cct.entries, ppd->ccti_entries,
|
|
|
+ ppd->total_cct_entry * sizeof(struct ib_cc_table_entry));
|
|
|
+
|
|
|
+ new_cc_state->cong_setting.port_control = IB_CC_CCS_PC_SL_BASED;
|
|
|
+ new_cc_state->cong_setting.control_map = ppd->cc_sl_control_map;
|
|
|
+ memcpy(new_cc_state->cong_setting.entries, ppd->congestion_entries,
|
|
|
+ OPA_MAX_SLS * sizeof(struct opa_congestion_setting_entry));
|
|
|
+
|
|
|
+ rcu_assign_pointer(ppd->cc_state, new_cc_state);
|
|
|
+
|
|
|
+ spin_unlock(&ppd->cc_state_lock);
|
|
|
+
|
|
|
+ call_rcu(&old_cc_state->rcu, cc_state_reclaim);
|
|
|
+}
|
|
|
+
|
|
|
static int __subn_set_opa_cong_setting(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
u32 *resp_len)
|
|
@@ -3374,6 +3418,11 @@ static int __subn_set_opa_cong_setting(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct opa_congestion_setting_entry_shadow *entries;
|
|
|
int i;
|
|
|
|
|
|
+ /*
|
|
|
+ * Save details from packet into the ppd. Hold the cc_state_lock so
|
|
|
+ * our information is consistent with anyone trying to apply the state.
|
|
|
+ */
|
|
|
+ spin_lock(&ppd->cc_state_lock);
|
|
|
ppd->cc_sl_control_map = be32_to_cpu(p->control_map);
|
|
|
|
|
|
entries = ppd->congestion_entries;
|
|
@@ -3384,6 +3433,10 @@ static int __subn_set_opa_cong_setting(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
p->entries[i].trigger_threshold;
|
|
|
entries[i].ccti_min = p->entries[i].ccti_min;
|
|
|
}
|
|
|
+ spin_unlock(&ppd->cc_state_lock);
|
|
|
+
|
|
|
+ /* now apply the information */
|
|
|
+ apply_cc_state(ppd);
|
|
|
|
|
|
return __subn_get_opa_cong_setting(smp, am, data, ibdev, port,
|
|
|
resp_len);
|
|
@@ -3526,7 +3579,6 @@ static int __subn_set_opa_cc_table(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
int i, j;
|
|
|
u32 sentry, eentry;
|
|
|
u16 ccti_limit;
|
|
|
- struct cc_state *old_cc_state, *new_cc_state;
|
|
|
|
|
|
/* sanity check n_blocks, start_block */
|
|
|
if (n_blocks == 0 ||
|
|
@@ -3546,45 +3598,20 @@ static int __subn_set_opa_cc_table(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
|
|
|
|
- new_cc_state = kzalloc(sizeof(*new_cc_state), GFP_KERNEL);
|
|
|
- if (!new_cc_state)
|
|
|
- goto getit;
|
|
|
-
|
|
|
+ /*
|
|
|
+ * Save details from packet into the ppd. Hold the cc_state_lock so
|
|
|
+ * our information is consistent with anyone trying to apply the state.
|
|
|
+ */
|
|
|
spin_lock(&ppd->cc_state_lock);
|
|
|
-
|
|
|
- old_cc_state = get_cc_state(ppd);
|
|
|
-
|
|
|
- if (!old_cc_state) {
|
|
|
- spin_unlock(&ppd->cc_state_lock);
|
|
|
- kfree(new_cc_state);
|
|
|
- return reply((struct ib_mad_hdr *)smp);
|
|
|
- }
|
|
|
-
|
|
|
- *new_cc_state = *old_cc_state;
|
|
|
-
|
|
|
- new_cc_state->cct.ccti_limit = ccti_limit;
|
|
|
-
|
|
|
- entries = ppd->ccti_entries;
|
|
|
ppd->total_cct_entry = ccti_limit + 1;
|
|
|
-
|
|
|
+ entries = ppd->ccti_entries;
|
|
|
for (j = 0, i = sentry; i < eentry; j++, i++)
|
|
|
entries[i].entry = be16_to_cpu(p->ccti_entries[j].entry);
|
|
|
-
|
|
|
- memcpy(new_cc_state->cct.entries, entries,
|
|
|
- eentry * sizeof(struct ib_cc_table_entry));
|
|
|
-
|
|
|
- new_cc_state->cong_setting.port_control = IB_CC_CCS_PC_SL_BASED;
|
|
|
- new_cc_state->cong_setting.control_map = ppd->cc_sl_control_map;
|
|
|
- memcpy(new_cc_state->cong_setting.entries, ppd->congestion_entries,
|
|
|
- OPA_MAX_SLS * sizeof(struct opa_congestion_setting_entry));
|
|
|
-
|
|
|
- rcu_assign_pointer(ppd->cc_state, new_cc_state);
|
|
|
-
|
|
|
spin_unlock(&ppd->cc_state_lock);
|
|
|
|
|
|
- call_rcu(&old_cc_state->rcu, cc_state_reclaim);
|
|
|
+ /* now apply the information */
|
|
|
+ apply_cc_state(ppd);
|
|
|
|
|
|
-getit:
|
|
|
return __subn_get_opa_cc_table(smp, am, data, ibdev, port, resp_len);
|
|
|
}
|
|
|
|