Commit fab895b3 authored by Ching-Te Ku's avatar Ching-Te Ku Committed by Kalle Valo

wifi: rtw89: coex: Rename BTC firmware cycle report by feature version

Because there are new report format in the upcoming patches, to make the
logic more readable, rename the related structure by their version number.
And to support the several version at the same time, add union definition
to include all the versions.
Signed-off-by: default avatarChing-Te Ku <ku920601@realtek.com>
Signed-off-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20230103140238.15601-3-pkshih@realtek.com
parent f643d086
...@@ -932,8 +932,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, ...@@ -932,8 +932,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
struct rtw89_btc_bt_info *bt = &btc->cx.bt; struct rtw89_btc_bt_info *bt = &btc->cx.bt;
struct rtw89_btc_fbtc_rpt_ctrl *prpt; struct rtw89_btc_fbtc_rpt_ctrl *prpt;
struct rtw89_btc_fbtc_rpt_ctrl_v1 *prpt_v1; struct rtw89_btc_fbtc_rpt_ctrl_v1 *prpt_v1;
struct rtw89_btc_fbtc_cysta *pcysta = NULL; union rtw89_btc_fbtc_cysta_info *pcysta = NULL;
struct rtw89_btc_fbtc_cysta_v1 *pcysta_v1 = NULL;
struct rtw89_btc_prpt *btc_prpt = NULL; struct rtw89_btc_prpt *btc_prpt = NULL;
void *rpt_content = NULL, *pfinfo = NULL; void *rpt_content = NULL, *pfinfo = NULL;
u8 rpt_type = 0; u8 rpt_type = 0;
...@@ -993,14 +992,17 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, ...@@ -993,14 +992,17 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
break; break;
case BTC_RPT_TYPE_CYSTA: case BTC_RPT_TYPE_CYSTA:
pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo; pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
if (chip->chip_id == RTL8852A) { pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo; if (ver->fcxcysta == 2) {
pcysta = &pfwinfo->rpt_fbtc_cysta.finfo; pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v2;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo); pcysta->v2 = pfwinfo->rpt_fbtc_cysta.finfo.v2;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v2);
} else if (ver->fcxcysta == 3) {
pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v3;
pcysta->v3 = pfwinfo->rpt_fbtc_cysta.finfo.v3;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v3);
} else { } else {
pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo_v1; goto err;
pcysta_v1 = &pfwinfo->rpt_fbtc_cysta.finfo_v1;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo_v1);
} }
pcinfo->req_fver = ver->fcxcysta; pcinfo->req_fver = ver->fcxcysta;
break; break;
...@@ -1186,14 +1188,14 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, ...@@ -1186,14 +1188,14 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
sizeof(dm->slot_now))); sizeof(dm->slot_now)));
break; break;
case BTC_RPT_TYPE_CYSTA: case BTC_RPT_TYPE_CYSTA:
if (chip->chip_id == RTL8852A) { if (ver->fcxcysta == 2) {
if (le16_to_cpu(pcysta->cycles) < BTC_CYSTA_CHK_PERIOD) if (le16_to_cpu(pcysta->v2.cycles) < BTC_CYSTA_CHK_PERIOD)
break; break;
/* Check Leak-AP */ /* Check Leak-AP */
if (le32_to_cpu(pcysta->slot_cnt[CXST_LK]) != 0 && if (le32_to_cpu(pcysta->v2.slot_cnt[CXST_LK]) != 0 &&
le32_to_cpu(pcysta->leakrx_cnt) != 0 && dm->tdma_now.rxflctrl) { le32_to_cpu(pcysta->v2.leakrx_cnt) != 0 && dm->tdma_now.rxflctrl) {
if (le32_to_cpu(pcysta->slot_cnt[CXST_LK]) < if (le32_to_cpu(pcysta->v2.slot_cnt[CXST_LK]) <
BTC_LEAK_AP_TH * le32_to_cpu(pcysta->leakrx_cnt)) BTC_LEAK_AP_TH * le32_to_cpu(pcysta->v2.leakrx_cnt))
dm->leak_ap = 1; dm->leak_ap = 1;
} }
...@@ -1204,24 +1206,24 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, ...@@ -1204,24 +1206,24 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
else else
wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur); wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur);
if (le16_to_cpu(pcysta->tavg_cycle[CXT_WL]) > wl_slot_set) { if (le16_to_cpu(pcysta->v2.tavg_cycle[CXT_WL]) > wl_slot_set) {
diff_t = le16_to_cpu(pcysta->tavg_cycle[CXT_WL]) - wl_slot_set; diff_t = le16_to_cpu(pcysta->v2.tavg_cycle[CXT_WL]) - wl_slot_set;
_chk_btc_err(rtwdev, _chk_btc_err(rtwdev,
BTC_DCNT_WL_SLOT_DRIFT, diff_t); BTC_DCNT_WL_SLOT_DRIFT, diff_t);
} }
_chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE,
le32_to_cpu(pcysta->slot_cnt[CXST_W1])); le32_to_cpu(pcysta->v2.slot_cnt[CXST_W1]));
_chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE,
le32_to_cpu(pcysta->slot_cnt[CXST_B1])); le32_to_cpu(pcysta->v2.slot_cnt[CXST_B1]));
_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE,
le16_to_cpu(pcysta->cycles)); le16_to_cpu(pcysta->v2.cycles));
} else { } else if (ver->fcxcysta == 3) {
if (le16_to_cpu(pcysta_v1->cycles) < BTC_CYSTA_CHK_PERIOD) if (le16_to_cpu(pcysta->v3.cycles) < BTC_CYSTA_CHK_PERIOD)
break; break;
cnt_leak_slot = le32_to_cpu(pcysta_v1->slot_cnt[CXST_LK]); cnt_leak_slot = le32_to_cpu(pcysta->v3.slot_cnt[CXST_LK]);
cnt_rx_imr = le32_to_cpu(pcysta_v1->leak_slot.cnt_rximr); cnt_rx_imr = le32_to_cpu(pcysta->v3.leak_slot.cnt_rximr);
/* Check Leak-AP */ /* Check Leak-AP */
if (cnt_leak_slot != 0 && cnt_rx_imr != 0 && if (cnt_leak_slot != 0 && cnt_rx_imr != 0 &&
...@@ -1233,7 +1235,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, ...@@ -1233,7 +1235,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
/* Check diff time between real WL slot and W1 slot */ /* Check diff time between real WL slot and W1 slot */
if (dm->tdma_now.type == CXTDMA_OFF) { if (dm->tdma_now.type == CXTDMA_OFF) {
wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur); wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur);
wl_slot_real = le16_to_cpu(pcysta_v1->cycle_time.tavg[CXT_WL]); wl_slot_real = le16_to_cpu(pcysta->v3.cycle_time.tavg[CXT_WL]);
if (wl_slot_real > wl_slot_set) { if (wl_slot_real > wl_slot_set) {
diff_t = wl_slot_real - wl_slot_set; diff_t = wl_slot_real - wl_slot_set;
_chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t); _chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t);
...@@ -1244,8 +1246,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, ...@@ -1244,8 +1246,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
if (dm->tdma_now.type == CXTDMA_OFF && if (dm->tdma_now.type == CXTDMA_OFF &&
dm->tdma_now.ext_ctrl == CXECTL_EXT && dm->tdma_now.ext_ctrl == CXECTL_EXT &&
btc->bt_req_len != 0) { btc->bt_req_len != 0) {
bt_slot_real = le16_to_cpu(pcysta_v1->cycle_time.tavg[CXT_BT]); bt_slot_real = le16_to_cpu(pcysta->v3.cycle_time.tavg[CXT_BT]);
if (btc->bt_req_len > bt_slot_real) { if (btc->bt_req_len > bt_slot_real) {
diff_t = btc->bt_req_len - bt_slot_real; diff_t = btc->bt_req_len - bt_slot_real;
_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t); _chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t);
...@@ -1253,11 +1254,13 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, ...@@ -1253,11 +1254,13 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
} }
_chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE,
le32_to_cpu(pcysta_v1->slot_cnt[CXST_W1])); le32_to_cpu(pcysta->v3.slot_cnt[CXST_W1]));
_chk_btc_err(rtwdev, BTC_DCNT_B1_FREEZE, _chk_btc_err(rtwdev, BTC_DCNT_B1_FREEZE,
le32_to_cpu(pcysta_v1->slot_cnt[CXST_B1])); le32_to_cpu(pcysta->v3.slot_cnt[CXST_B1]));
_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE,
(u32)le16_to_cpu(pcysta_v1->cycles)); le16_to_cpu(pcysta->v3.cycles));
} else {
goto err;
} }
break; break;
case BTC_RPT_TYPE_BT_VER: case BTC_RPT_TYPE_BT_VER:
...@@ -6160,21 +6163,23 @@ static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m) ...@@ -6160,21 +6163,23 @@ static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m)
static void _show_error(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_error(struct rtw89_dev *rtwdev, struct seq_file *m)
{ {
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc *btc = &rtwdev->btc;
const struct rtw89_btc_ver *ver = btc->ver;
struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
struct rtw89_btc_fbtc_cysta *pcysta; union rtw89_btc_fbtc_cysta_info *pcysta;
struct rtw89_btc_fbtc_cysta_v1 *pcysta_v1;
u32 except_cnt, exception_map; u32 except_cnt, exception_map;
if (chip->chip_id == RTL8852A) { pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
pcysta = &pfwinfo->rpt_fbtc_cysta.finfo; if (ver->fcxcysta == 2) {
except_cnt = le32_to_cpu(pcysta->except_cnt); pcysta->v2 = pfwinfo->rpt_fbtc_cysta.finfo.v2;
exception_map = le32_to_cpu(pcysta->exception); except_cnt = le32_to_cpu(pcysta->v2.except_cnt);
exception_map = le32_to_cpu(pcysta->v2.exception);
} else if (ver->fcxcysta == 3) {
pcysta->v3 = pfwinfo->rpt_fbtc_cysta.finfo.v3;
except_cnt = le32_to_cpu(pcysta->v3.except_cnt);
exception_map = le32_to_cpu(pcysta->v3.except_map);
} else { } else {
pcysta_v1 = &pfwinfo->rpt_fbtc_cysta.finfo_v1; return;
except_cnt = le32_to_cpu(pcysta_v1->except_cnt);
exception_map = le32_to_cpu(pcysta_v1->except_map);
} }
if (pfwinfo->event[BTF_EVNT_BUF_OVERFLOW] == 0 && except_cnt == 0 && if (pfwinfo->event[BTF_EVNT_BUF_OVERFLOW] == 0 && except_cnt == 0 &&
...@@ -6305,14 +6310,14 @@ static void _show_fbtc_slots(struct rtw89_dev *rtwdev, struct seq_file *m) ...@@ -6305,14 +6310,14 @@ static void _show_fbtc_slots(struct rtw89_dev *rtwdev, struct seq_file *m)
} }
} }
static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_fbtc_cysta_v2(struct rtw89_dev *rtwdev, struct seq_file *m)
{ {
struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_dm *dm = &btc->dm;
struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc; struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
struct rtw89_btc_fbtc_cysta *pcysta_le32 = NULL; struct rtw89_btc_fbtc_cysta_v2 *pcysta_le32 = NULL;
union rtw89_btc_fbtc_rxflct r; union rtw89_btc_fbtc_rxflct r;
u8 i, cnt = 0, slot_pair; u8 i, cnt = 0, slot_pair;
u16 cycle, c_begin, c_end, store_index; u16 cycle, c_begin, c_end, store_index;
...@@ -6321,7 +6326,7 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) ...@@ -6321,7 +6326,7 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m)
if (!pcinfo->valid) if (!pcinfo->valid)
return; return;
pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo; pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo.v2;
seq_printf(m, seq_printf(m,
" %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]", " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
"[cycle_cnt]", "[cycle_cnt]",
...@@ -6433,14 +6438,14 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) ...@@ -6433,14 +6438,14 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m)
} }
} }
static void _show_fbtc_cysta_v1(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_fbtc_cysta_v3(struct rtw89_dev *rtwdev, struct seq_file *m)
{ {
struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc; struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_dm *dm = &btc->dm;
struct rtw89_btc_fbtc_a2dp_trx_stat *a2dp_trx; struct rtw89_btc_fbtc_a2dp_trx_stat *a2dp_trx;
struct rtw89_btc_fbtc_cysta_v1 *pcysta; struct rtw89_btc_fbtc_cysta_v3 *pcysta;
struct rtw89_btc_rpt_cmn_info *pcinfo; struct rtw89_btc_rpt_cmn_info *pcinfo;
u8 i, cnt = 0, slot_pair, divide_cnt; u8 i, cnt = 0, slot_pair, divide_cnt;
u16 cycle, c_begin, c_end, store_index; u16 cycle, c_begin, c_end, store_index;
...@@ -6449,7 +6454,7 @@ static void _show_fbtc_cysta_v1(struct rtw89_dev *rtwdev, struct seq_file *m) ...@@ -6449,7 +6454,7 @@ static void _show_fbtc_cysta_v1(struct rtw89_dev *rtwdev, struct seq_file *m)
if (!pcinfo->valid) if (!pcinfo->valid)
return; return;
pcysta = &pfwinfo->rpt_fbtc_cysta.finfo_v1; pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v3;
seq_printf(m, seq_printf(m,
" %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]", " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
"[cycle_cnt]", "[cycle_cnt]",
...@@ -6708,8 +6713,8 @@ static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m) ...@@ -6708,8 +6713,8 @@ static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m)
static void _show_fw_dm_msg(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_fw_dm_msg(struct rtw89_dev *rtwdev, struct seq_file *m)
{ {
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc *btc = &rtwdev->btc;
const struct rtw89_btc_ver *ver = btc->ver;
if (!(btc->dm.coex_info_map & BTC_COEX_INFO_DM)) if (!(btc->dm.coex_info_map & BTC_COEX_INFO_DM))
return; return;
...@@ -6718,10 +6723,10 @@ static void _show_fw_dm_msg(struct rtw89_dev *rtwdev, struct seq_file *m) ...@@ -6718,10 +6723,10 @@ static void _show_fw_dm_msg(struct rtw89_dev *rtwdev, struct seq_file *m)
_show_fbtc_tdma(rtwdev, m); _show_fbtc_tdma(rtwdev, m);
_show_fbtc_slots(rtwdev, m); _show_fbtc_slots(rtwdev, m);
if (chip->chip_id == RTL8852A) if (ver->fcxcysta == 2)
_show_fbtc_cysta(rtwdev, m); _show_fbtc_cysta_v2(rtwdev, m);
else else if (ver->fcxcysta == 3)
_show_fbtc_cysta_v1(rtwdev, m); _show_fbtc_cysta_v3(rtwdev, m);
_show_fbtc_nullsta(rtwdev, m); _show_fbtc_nullsta(rtwdev, m);
_show_fbtc_step(rtwdev, m); _show_fbtc_step(rtwdev, m);
......
...@@ -1681,7 +1681,7 @@ struct rtw89_btc_fbtc_steps_v1 { ...@@ -1681,7 +1681,7 @@ struct rtw89_btc_fbtc_steps_v1 {
struct rtw89_btc_fbtc_step step[FCXMAX_STEP]; struct rtw89_btc_fbtc_step step[FCXMAX_STEP];
} __packed; } __packed;
struct rtw89_btc_fbtc_cysta { /* statistics for cycles */ struct rtw89_btc_fbtc_cysta_v2 { /* statistics for cycles */
u8 fver; /* btc_ver::fcxcysta */ u8 fver; /* btc_ver::fcxcysta */
u8 rsvd; u8 rsvd;
__le16 cycles; /* total cycle number */ __le16 cycles; /* total cycle number */
...@@ -1743,7 +1743,7 @@ struct rtw89_btc_fbtc_cycle_leak_info { ...@@ -1743,7 +1743,7 @@ struct rtw89_btc_fbtc_cycle_leak_info {
__le16 tmax; /* max leak-slot time */ __le16 tmax; /* max leak-slot time */
} __packed; } __packed;
struct rtw89_btc_fbtc_cysta_v1 { /* statistics for cycles */ struct rtw89_btc_fbtc_cysta_v3 { /* statistics for cycles */
u8 fver; u8 fver;
u8 rsvd; u8 rsvd;
__le16 cycles; /* total cycle number */ __le16 cycles; /* total cycle number */
...@@ -1761,6 +1761,11 @@ struct rtw89_btc_fbtc_cysta_v1 { /* statistics for cycles */ ...@@ -1761,6 +1761,11 @@ struct rtw89_btc_fbtc_cysta_v1 { /* statistics for cycles */
__le32 except_map; __le32 except_map;
} __packed; } __packed;
union rtw89_btc_fbtc_cysta_info {
struct rtw89_btc_fbtc_cysta_v2 v2;
struct rtw89_btc_fbtc_cysta_v3 v3;
};
struct rtw89_btc_fbtc_cynullsta { /* cycle null statistics */ struct rtw89_btc_fbtc_cynullsta { /* cycle null statistics */
u8 fver; /* btc_ver::fcxnullsta */ u8 fver; /* btc_ver::fcxnullsta */
u8 rsvd; u8 rsvd;
...@@ -1961,10 +1966,7 @@ struct rtw89_btc_rpt_fbtc_slots { ...@@ -1961,10 +1966,7 @@ struct rtw89_btc_rpt_fbtc_slots {
struct rtw89_btc_rpt_fbtc_cysta { struct rtw89_btc_rpt_fbtc_cysta {
struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */ struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
union { union rtw89_btc_fbtc_cysta_info finfo;
struct rtw89_btc_fbtc_cysta finfo; /* info from fw for 52A*/
struct rtw89_btc_fbtc_cysta_v1 finfo_v1; /* info from fw for 52C*/
};
}; };
struct rtw89_btc_rpt_fbtc_step { struct rtw89_btc_rpt_fbtc_step {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment