Commit c2c1d9de authored by Xiang Chen's avatar Xiang Chen Committed by Martin K. Petersen

scsi: hisi_sas: update PHY linkrate after a controller reset

After the controller is reset, we currently may not honour the PHY max
linkrate set via sysfs, in that after a reset we always revert to max
linkrate of 12Gbps, ignoring the value set via sysfs.

This patch modifies to policy to set the programmed PHY linkrate,
honouring the max linkrate programmed via sysfs.
Signed-off-by: default avatarXiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: default avatarJohn Garry <john.garry@huawei.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 6f7c32d6
...@@ -463,4 +463,5 @@ extern void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba); ...@@ -463,4 +463,5 @@ extern void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba);
extern bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy, extern bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
enum hisi_sas_phy_event event); enum hisi_sas_phy_event event);
extern void hisi_sas_release_tasks(struct hisi_hba *hisi_hba); extern void hisi_sas_release_tasks(struct hisi_hba *hisi_hba);
extern u8 hisi_sas_get_prog_phy_linkrate_mask(enum sas_linkrate max);
#endif #endif
...@@ -135,6 +135,22 @@ int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag) ...@@ -135,6 +135,22 @@ int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag)
} }
EXPORT_SYMBOL_GPL(hisi_sas_get_ncq_tag); EXPORT_SYMBOL_GPL(hisi_sas_get_ncq_tag);
/*
* This function assumes linkrate mask fits in 8 bits, which it
* does for all HW versions supported.
*/
u8 hisi_sas_get_prog_phy_linkrate_mask(enum sas_linkrate max)
{
u16 rate = 0;
int i;
max -= SAS_LINK_RATE_1_5_GBPS;
for (i = 0; i <= max; i++)
rate |= 1 << (i * 2);
return rate;
}
EXPORT_SYMBOL_GPL(hisi_sas_get_prog_phy_linkrate_mask);
static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device) static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
{ {
return device->port->ha->lldd_ha; return device->port->ha->lldd_ha;
......
...@@ -1216,7 +1216,22 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) ...@@ -1216,7 +1216,22 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
} }
for (i = 0; i < hisi_hba->n_phy; i++) { for (i = 0; i < hisi_hba->n_phy; i++) {
hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855); struct hisi_sas_phy *phy = &hisi_hba->phy[i];
struct asd_sas_phy *sas_phy = &phy->sas_phy;
u32 prog_phy_link_rate = 0x800;
if (!sas_phy->phy || (sas_phy->phy->maximum_linkrate <
SAS_LINK_RATE_1_5_GBPS)) {
prog_phy_link_rate = 0x855;
} else {
enum sas_linkrate max = sas_phy->phy->maximum_linkrate;
prog_phy_link_rate =
hisi_sas_get_prog_phy_linkrate_mask(max) |
0x800;
}
hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE,
prog_phy_link_rate);
hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, sas_phy_ctrl); hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, sas_phy_ctrl);
hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d); hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
hisi_sas_phy_write32(hisi_hba, i, SL_CONTROL, 0x0); hisi_sas_phy_write32(hisi_hba, i, SL_CONTROL, 0x0);
...@@ -1585,13 +1600,10 @@ static enum sas_linkrate phy_get_max_linkrate_v2_hw(void) ...@@ -1585,13 +1600,10 @@ static enum sas_linkrate phy_get_max_linkrate_v2_hw(void)
static void phy_set_linkrate_v2_hw(struct hisi_hba *hisi_hba, int phy_no, static void phy_set_linkrate_v2_hw(struct hisi_hba *hisi_hba, int phy_no,
struct sas_phy_linkrates *r) struct sas_phy_linkrates *r)
{ {
u32 prog_phy_link_rate =
hisi_sas_phy_read32(hisi_hba, phy_no, PROG_PHY_LINK_RATE);
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
struct asd_sas_phy *sas_phy = &phy->sas_phy; struct asd_sas_phy *sas_phy = &phy->sas_phy;
int i;
enum sas_linkrate min, max; enum sas_linkrate min, max;
u32 rate_mask = 0; u32 prog_phy_link_rate = 0x800;
if (r->maximum_linkrate == SAS_LINK_RATE_UNKNOWN) { if (r->maximum_linkrate == SAS_LINK_RATE_UNKNOWN) {
max = sas_phy->phy->maximum_linkrate; max = sas_phy->phy->maximum_linkrate;
...@@ -1604,14 +1616,7 @@ static void phy_set_linkrate_v2_hw(struct hisi_hba *hisi_hba, int phy_no, ...@@ -1604,14 +1616,7 @@ static void phy_set_linkrate_v2_hw(struct hisi_hba *hisi_hba, int phy_no,
sas_phy->phy->maximum_linkrate = max; sas_phy->phy->maximum_linkrate = max;
sas_phy->phy->minimum_linkrate = min; sas_phy->phy->minimum_linkrate = min;
prog_phy_link_rate |= hisi_sas_get_prog_phy_linkrate_mask(max);
max -= SAS_LINK_RATE_1_5_GBPS;
for (i = 0; i <= max; i++)
rate_mask |= 1 << (i * 2);
prog_phy_link_rate &= ~0xff;
prog_phy_link_rate |= rate_mask;
disable_phy_v2_hw(hisi_hba, phy_no); disable_phy_v2_hw(hisi_hba, phy_no);
msleep(100); msleep(100);
......
...@@ -429,7 +429,22 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) ...@@ -429,7 +429,22 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1); hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
for (i = 0; i < hisi_hba->n_phy; i++) { for (i = 0; i < hisi_hba->n_phy; i++) {
hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855); struct hisi_sas_phy *phy = &hisi_hba->phy[i];
struct asd_sas_phy *sas_phy = &phy->sas_phy;
u32 prog_phy_link_rate = 0x800;
if (!sas_phy->phy || (sas_phy->phy->maximum_linkrate <
SAS_LINK_RATE_1_5_GBPS)) {
prog_phy_link_rate = 0x855;
} else {
enum sas_linkrate max = sas_phy->phy->maximum_linkrate;
prog_phy_link_rate =
hisi_sas_get_prog_phy_linkrate_mask(max) |
0x800;
}
hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE,
prog_phy_link_rate);
hisi_sas_phy_write32(hisi_hba, i, SAS_RX_TRAIN_TIMER, 0x13e80); hisi_sas_phy_write32(hisi_hba, i, SAS_RX_TRAIN_TIMER, 0x13e80);
hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff); hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff);
hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff); hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
...@@ -1869,13 +1884,10 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba) ...@@ -1869,13 +1884,10 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
static void phy_set_linkrate_v3_hw(struct hisi_hba *hisi_hba, int phy_no, static void phy_set_linkrate_v3_hw(struct hisi_hba *hisi_hba, int phy_no,
struct sas_phy_linkrates *r) struct sas_phy_linkrates *r)
{ {
u32 prog_phy_link_rate =
hisi_sas_phy_read32(hisi_hba, phy_no, PROG_PHY_LINK_RATE);
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
struct asd_sas_phy *sas_phy = &phy->sas_phy; struct asd_sas_phy *sas_phy = &phy->sas_phy;
int i;
enum sas_linkrate min, max; enum sas_linkrate min, max;
u32 rate_mask = 0; u32 prog_phy_link_rate = 0x800;
if (r->maximum_linkrate == SAS_LINK_RATE_UNKNOWN) { if (r->maximum_linkrate == SAS_LINK_RATE_UNKNOWN) {
max = sas_phy->phy->maximum_linkrate; max = sas_phy->phy->maximum_linkrate;
...@@ -1888,14 +1900,7 @@ static void phy_set_linkrate_v3_hw(struct hisi_hba *hisi_hba, int phy_no, ...@@ -1888,14 +1900,7 @@ static void phy_set_linkrate_v3_hw(struct hisi_hba *hisi_hba, int phy_no,
sas_phy->phy->maximum_linkrate = max; sas_phy->phy->maximum_linkrate = max;
sas_phy->phy->minimum_linkrate = min; sas_phy->phy->minimum_linkrate = min;
prog_phy_link_rate |= hisi_sas_get_prog_phy_linkrate_mask(max);
max -= SAS_LINK_RATE_1_5_GBPS;
for (i = 0; i <= max; i++)
rate_mask |= 1 << (i * 2);
prog_phy_link_rate &= ~0xff;
prog_phy_link_rate |= rate_mask;
disable_phy_v3_hw(hisi_hba, phy_no); disable_phy_v3_hw(hisi_hba, phy_no);
msleep(100); msleep(100);
......
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