Skip to content
Permalink
Browse files
lpfc: Add support for the CM framework
This patch completes the enablement of the cm framework feature in the
adapter.

The patch performs the following:
- Detects the presence of the congestion management framework feature

When the cm framework is present:
- Issues the SET_FEATURE command to enable the feature
- Registers the cm statistics buffer with the adapter
- Reads the cm enablement buffer to determine the cm framework state
  for cm management.

When cm management is enabled:
- Monitors all FPIN and congestion signalling events, incrementing
  counters.
- Regularly syncs with the adapter to communicate congestion events and
  to receive an rx request limit.
- Monitors requests for rx data and ensures that no more than the
  adapter prescribed limit is issued on the link. If the limit is
  exceeded, scsi and/or nvme traffic is temporarily suspended.
- Maintains the minute, hourly, daily statistics buffer.
- Monitors for congestion enablement change events, causing a reread of
  the enablement buffer and acting on any change in enablement.

And
- Adds teardown logic, including buffer deregistration, on adapter
  detachment or reset.

Co-developed-by: Justin Tee <justin.tee@broadcom.com>
Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
  • Loading branch information
jsmart-gh authored and intel-lab-lkp committed Aug 13, 2021
1 parent d1a0dd2 commit 1a8e9dd2b3e469dbf4383dce6f60aa9cea9bd669
Show file tree
Hide file tree
Showing 12 changed files with 910 additions and 34 deletions.
@@ -550,6 +550,14 @@ struct lpfc_cgn_info {
#define LPFC_CGN_INFO_SZ (sizeof(struct lpfc_cgn_info) - \
sizeof(uint32_t))

struct lpfc_cgn_stat {
atomic64_t total_bytes;
atomic64_t rcv_bytes;
atomic64_t rx_latency;
#define LPFC_CGN_NOT_SENT 0xFFFFFFFFFFFFFFFFLL
atomic_t rx_io_cnt;
};

struct lpfc_cgn_acqe_stat {
atomic64_t alarm;
atomic64_t warn;
@@ -1021,7 +1029,10 @@ struct lpfc_hba {
* capability
*/
#define HBA_FLOGI_ISSUED 0x100000 /* FLOGI was issued */
#define HBA_CGN_RSVD1 0x200000 /* Reserved CGN flag */
#define HBA_CGN_DAY_WRAP 0x400000 /* HBA Congestion info day wraps */
#define HBA_DEFER_FLOGI 0x800000 /* Defer FLOGI till read_sparm cmpl */
#define HBA_SETUP 0x1000000 /* Signifies HBA setup is completed */
#define HBA_NEEDS_CFG_PORT 0x2000000 /* SLI3 - needs a CONFIG_PORT mbox */
#define HBA_HBEAT_INP 0x4000000 /* mbox HBEAT is in progress */
#define HBA_HBEAT_TMO 0x8000000 /* HBEAT initiated after timeout */
@@ -1272,6 +1283,7 @@ struct lpfc_hba {
uint32_t total_iocbq_bufs;
struct list_head active_rrq_list;
spinlock_t hbalock;
struct work_struct unblock_request_work; /* SCSI layer unblock IOs */

/* dma_mem_pools */
struct dma_pool *lpfc_sg_dma_buf_pool;
@@ -1496,12 +1508,25 @@ struct lpfc_hba {
uint64_t ktime_seg10_max;
#endif
/* CMF objects */
u32 cmf_active_mode;
#define LPFC_CFG_OFF 0

struct lpfc_cgn_stat __percpu *cmf_stat;
uint32_t cmf_interval_rate; /* timer interval limit in ms */
uint32_t cmf_timer_cnt;
#define LPFC_CMF_INTERVAL 90
uint64_t cmf_link_byte_count;
uint64_t cmf_max_line_rate;
uint64_t cmf_max_bytes_per_interval;
uint64_t cmf_last_sync_bw;
#define LPFC_CMF_BLK_SIZE 512
struct hrtimer cmf_timer;
atomic_t cmf_bw_wait;
atomic_t cmf_busy;
atomic_t cmf_stop_io; /* To block request and stop IO's */
uint32_t cmf_active_mode;
uint32_t cmf_info_per_interval;
#define LPFC_MAX_CMF_INFO 32
struct timespec64 cmf_latency; /* Interval congestion timestamp */
uint32_t cmf_last_ts; /* Interval congestion time (ms) */
uint32_t cmf_active_info;

/* Signal / FPIN handling for Congestion Mgmt */
u8 cgn_reg_fpin; /* Negotiated value from RDF */
@@ -1521,6 +1546,8 @@ struct lpfc_hba {
u32 cgn_sig_freq;
u32 cgn_acqe_cnt;

uint64_t rx_block_cnt;

/* Congestion parameters from flash */
struct lpfc_cgn_param cgn_p;

@@ -7476,6 +7476,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_enable_dpp_init(phba, lpfc_enable_dpp);
lpfc_enable_mi_init(phba, lpfc_enable_mi);

phba->cgn_p.cgn_param_mode = LPFC_CFG_OFF;
phba->cmf_active_mode = LPFC_CFG_OFF;
if (lpfc_fabric_cgn_frequency > EDC_CG_SIGFREQ_CNT_MAX ||
lpfc_fabric_cgn_frequency < EDC_CG_SIGFREQ_CNT_MIN)
@@ -59,6 +59,7 @@ int lpfc_sli4_mbox_rsrc_extent(struct lpfc_hba *, struct lpfcMboxq *,
uint16_t, uint16_t, bool);
int lpfc_get_sli4_parameters(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_reg_congestion_buf(struct lpfc_hba *phba);
int lpfc_unreg_congestion_buf(struct lpfc_hba *phba);
struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
void lpfc_cleanup_rcv_buffers(struct lpfc_vport *);
void lpfc_rcv_seq_check_edtov(struct lpfc_vport *);
@@ -75,11 +76,17 @@ int lpfc_init_iocb_list(struct lpfc_hba *phba, int cnt);
void lpfc_free_iocb_list(struct lpfc_hba *phba);
int lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
struct lpfc_queue *drq, int count, int idx);
uint32_t lpfc_calc_cmf_latency(struct lpfc_hba *phba);
void lpfc_cmf_signal_init(struct lpfc_hba *phba);
void lpfc_cmf_start(struct lpfc_hba *phba);
void lpfc_cmf_stop(struct lpfc_hba *phba);
void lpfc_init_congestion_stat(struct lpfc_hba *phba);
void lpfc_init_congestion_buf(struct lpfc_hba *phba);
int lpfc_sli4_cgn_params_read(struct lpfc_hba *phba);
int lpfc_config_cgn_signal(struct lpfc_hba *phba);
int lpfc_issue_cmf_sync_wqe(struct lpfc_hba *phba, u32 ms, u64 total);
void lpfc_unblock_requests(struct lpfc_hba *phba);
void lpfc_block_requests(struct lpfc_hba *phba);

void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -471,6 +478,9 @@ void lpfc_free_fast_evt(struct lpfc_hba *, struct lpfc_fast_path_event *);
void lpfc_create_static_vport(struct lpfc_hba *);
void lpfc_stop_hba_timers(struct lpfc_hba *);
void lpfc_stop_port(struct lpfc_hba *);
int lpfc_update_cmf_cmd(struct lpfc_hba *phba, uint32_t sz);
int lpfc_update_cmf_cmpl(struct lpfc_hba *phba, uint64_t val, uint32_t sz,
struct Scsi_Host *shost);
void __lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *);
void lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *);
void lpfc_parse_fcoe_conf(struct lpfc_hba *, uint8_t *, uint32_t);
@@ -3333,9 +3333,11 @@ lpfc_cmpl_els_disc_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_printf_vlog(vport, KERN_INFO,
LOG_ELS | LOG_CGN_MGMT,
"4677 Fabric RDF Notification Grant "
"Data: 0x%08x\n",
"Data: 0x%08x Reg: %x %x\n",
be32_to_cpu(
prdf->reg_d1.desc_tags[i]));
prdf->reg_d1.desc_tags[i]),
phba->cgn_reg_signal,
phba->cgn_reg_fpin);
}

out:
@@ -3702,9 +3704,11 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
prdf->reg_d1.desc_tags[3] = cpu_to_be32(ELS_DTAG_CONGESTION);

lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT,
"6444 Xmit RDF to remote NPORT x%x\n",
ndlp->nlp_DID);
"6444 Xmit RDF to remote NPORT x%x Reg: %x %x\n",
ndlp->nlp_DID, phba->cgn_reg_signal,
phba->cgn_reg_fpin);

phba->cgn_fpin_frequency = LPFC_FPIN_INIT_FREQ;
elsiocb->iocb_cmpl = lpfc_cmpl_els_disc_cmd;
elsiocb->context1 = lpfc_nlp_get(ndlp);
if (!elsiocb->context1) {
@@ -3778,6 +3782,8 @@ lpfc_least_capable_settings(struct lpfc_hba *phba,
{
u32 rsp_sig_cap = 0, drv_sig_cap = 0;
u32 rsp_sig_freq_cyc = 0, rsp_sig_freq_scale = 0;
struct lpfc_cgn_info *cp;
u16 sig_freq;

/* Get rsp signal and frequency capabilities. */
rsp_sig_cap = be32_to_cpu(pcgd->xmt_signal_capability);
@@ -3832,6 +3838,24 @@ lpfc_least_capable_settings(struct lpfc_hba *phba,
phba->cgn_reg_fpin &= ~LPFC_CGN_FPIN_WARN;
}
}

if (!phba->cgn_i)
return;

/* Update signal frequency in congestion info buffer */
cp = (struct lpfc_cgn_info *)phba->cgn_i->virt;

/* Frequency (in ms) Signal Warning/Signal Congestion Notifications
* are received by the HBA
*/
sig_freq = phba->cgn_sig_freq;

if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ONLY)
cp->cgn_warn_freq = cpu_to_le16(sig_freq);
if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) {
cp->cgn_alarm_freq = cpu_to_le16(sig_freq);
cp->cgn_warn_freq = cpu_to_le16(sig_freq);
}
return;

out_no_support:
@@ -9508,11 +9532,13 @@ lpfc_els_rcv_fpin_peer_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv)
static int
lpfc_els_rcv_fpin_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv)
{
struct lpfc_cgn_info *cp;
struct fc_fn_congn_desc *cgn = (struct fc_fn_congn_desc *)tlv;
const char *cgn_evt_str;
u32 cgn_evt;
const char *cgn_sev_str;
u32 cgn_sev;
uint16_t value;
bool nm_log = false;
int rc = 1;

@@ -9540,9 +9566,48 @@ lpfc_els_rcv_fpin_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv)
switch (cgn_sev) {
case FPIN_CONGN_SEVERITY_ERROR:
/* Take action here for an Alarm event */
if (phba->cmf_active_mode != LPFC_CFG_OFF) {
if (phba->cgn_reg_fpin & LPFC_CGN_FPIN_ALARM) {
/* Track of alarm cnt for cgn_info */
atomic_inc(&phba->cgn_fabric_alarm_cnt);
/* Track of alarm cnt for SYNC_WQE */
atomic_inc(&phba->cgn_sync_alarm_cnt);
}
goto cleanup;
}
break;
case FPIN_CONGN_SEVERITY_WARNING:
/* Take action here for a Warning event */
if (phba->cmf_active_mode != LPFC_CFG_OFF) {
if (phba->cgn_reg_fpin & LPFC_CGN_FPIN_WARN) {
/* Track of warning cnt for cgn_info */
atomic_inc(&phba->cgn_fabric_warn_cnt);
/* Track of warning cnt for SYNC_WQE */
atomic_inc(&phba->cgn_sync_warn_cnt);
}
cleanup:
/* Save frequency in ms */
phba->cgn_fpin_frequency =
be32_to_cpu(cgn->event_period);
value = phba->cgn_fpin_frequency;
if (phba->cgn_i) {
cp = (struct lpfc_cgn_info *)
phba->cgn_i->virt;
if (phba->cgn_reg_fpin &
LPFC_CGN_FPIN_ALARM)
cp->cgn_alarm_freq =
cpu_to_le16(value);
if (phba->cgn_reg_fpin &
LPFC_CGN_FPIN_WARN)
cp->cgn_warn_freq =
cpu_to_le16(value);
}

/* Don't deliver to upper layer since
* driver took action on this tlv.
*/
rc = 0;
}
break;
}
break;
@@ -3647,6 +3647,10 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
phba->wait_4_mlo_maint_flg);
}
lpfc_mbx_process_link_up(phba, la);

if (phba->cmf_active_mode != LPFC_CFG_OFF)
lpfc_cmf_signal_init(phba);

} else if (attn_type == LPFC_ATT_LINK_DOWN ||
attn_type == LPFC_ATT_UNEXP_WWPN) {
phba->fc_stat.LinkDown++;

0 comments on commit 1a8e9dd

Please sign in to comment.