pm80xx: set PHY profiles for ATTO 12Gb SAS controllers
PHY profiles are not saved in NVRAM on ATTO 12Gb SAS controllers. Therefore, in order for the controller to function in a wide range of configurations, the PHY profiles must be statically set. This patch provides the necessary functionality to do so. Signed-off-by: Benjamin Rood <brood@attotech.com> Reviewed-by: Jack Wang <jinpu.wang@profitbricks.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Родитель
10efa460fe
Коммит
c5614df7ff
|
@ -732,6 +732,131 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct pm8001_mpi3_phy_pg_trx_config {
|
||||
u32 LaneLosCfg;
|
||||
u32 LanePgaCfg1;
|
||||
u32 LanePisoCfg1;
|
||||
u32 LanePisoCfg2;
|
||||
u32 LanePisoCfg3;
|
||||
u32 LanePisoCfg4;
|
||||
u32 LanePisoCfg5;
|
||||
u32 LanePisoCfg6;
|
||||
u32 LaneBctCtrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* pm8001_get_internal_phy_settings : Retrieves the internal PHY settings
|
||||
* @pm8001_ha : our adapter
|
||||
* @phycfg : PHY config page to populate
|
||||
*/
|
||||
static
|
||||
void pm8001_get_internal_phy_settings(struct pm8001_hba_info *pm8001_ha,
|
||||
struct pm8001_mpi3_phy_pg_trx_config *phycfg)
|
||||
{
|
||||
phycfg->LaneLosCfg = 0x00000132;
|
||||
phycfg->LanePgaCfg1 = 0x00203949;
|
||||
phycfg->LanePisoCfg1 = 0x000000FF;
|
||||
phycfg->LanePisoCfg2 = 0xFF000001;
|
||||
phycfg->LanePisoCfg3 = 0xE7011300;
|
||||
phycfg->LanePisoCfg4 = 0x631C40C0;
|
||||
phycfg->LanePisoCfg5 = 0xF8102036;
|
||||
phycfg->LanePisoCfg6 = 0xF74A1000;
|
||||
phycfg->LaneBctCtrl = 0x00FB33F8;
|
||||
}
|
||||
|
||||
/**
|
||||
* pm8001_get_external_phy_settings : Retrieves the external PHY settings
|
||||
* @pm8001_ha : our adapter
|
||||
* @phycfg : PHY config page to populate
|
||||
*/
|
||||
static
|
||||
void pm8001_get_external_phy_settings(struct pm8001_hba_info *pm8001_ha,
|
||||
struct pm8001_mpi3_phy_pg_trx_config *phycfg)
|
||||
{
|
||||
phycfg->LaneLosCfg = 0x00000132;
|
||||
phycfg->LanePgaCfg1 = 0x00203949;
|
||||
phycfg->LanePisoCfg1 = 0x000000FF;
|
||||
phycfg->LanePisoCfg2 = 0xFF000001;
|
||||
phycfg->LanePisoCfg3 = 0xE7011300;
|
||||
phycfg->LanePisoCfg4 = 0x63349140;
|
||||
phycfg->LanePisoCfg5 = 0xF8102036;
|
||||
phycfg->LanePisoCfg6 = 0xF80D9300;
|
||||
phycfg->LaneBctCtrl = 0x00FB33F8;
|
||||
}
|
||||
|
||||
/**
|
||||
* pm8001_get_phy_mask : Retrieves the mask that denotes if a PHY is int/ext
|
||||
* @pm8001_ha : our adapter
|
||||
* @phymask : The PHY mask
|
||||
*/
|
||||
static
|
||||
void pm8001_get_phy_mask(struct pm8001_hba_info *pm8001_ha, int *phymask)
|
||||
{
|
||||
switch (pm8001_ha->pdev->subsystem_device) {
|
||||
case 0x0070: /* H1280 - 8 external 0 internal */
|
||||
case 0x0072: /* H12F0 - 16 external 0 internal */
|
||||
*phymask = 0x0000;
|
||||
break;
|
||||
|
||||
case 0x0071: /* H1208 - 0 external 8 internal */
|
||||
case 0x0073: /* H120F - 0 external 16 internal */
|
||||
*phymask = 0xFFFF;
|
||||
break;
|
||||
|
||||
case 0x0080: /* H1244 - 4 external 4 internal */
|
||||
*phymask = 0x00F0;
|
||||
break;
|
||||
|
||||
case 0x0081: /* H1248 - 4 external 8 internal */
|
||||
*phymask = 0x0FF0;
|
||||
break;
|
||||
|
||||
case 0x0082: /* H1288 - 8 external 8 internal */
|
||||
*phymask = 0xFF00;
|
||||
break;
|
||||
|
||||
default:
|
||||
PM8001_INIT_DBG(pm8001_ha,
|
||||
pm8001_printk("Unknown subsystem device=0x%.04x",
|
||||
pm8001_ha->pdev->subsystem_device));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pm8001_set_phy_settings_ven_117c_12Gb : Configure ATTO 12Gb PHY settings
|
||||
* @pm8001_ha : our adapter
|
||||
*/
|
||||
static
|
||||
int pm8001_set_phy_settings_ven_117c_12G(struct pm8001_hba_info *pm8001_ha)
|
||||
{
|
||||
struct pm8001_mpi3_phy_pg_trx_config phycfg_int;
|
||||
struct pm8001_mpi3_phy_pg_trx_config phycfg_ext;
|
||||
int phymask = 0;
|
||||
int i = 0;
|
||||
|
||||
memset(&phycfg_int, 0, sizeof(phycfg_int));
|
||||
memset(&phycfg_ext, 0, sizeof(phycfg_ext));
|
||||
|
||||
pm8001_get_internal_phy_settings(pm8001_ha, &phycfg_int);
|
||||
pm8001_get_external_phy_settings(pm8001_ha, &phycfg_ext);
|
||||
pm8001_get_phy_mask(pm8001_ha, &phymask);
|
||||
|
||||
for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
|
||||
if (phymask & (1 << i)) {/* Internal PHY */
|
||||
pm8001_set_phy_profile_single(pm8001_ha, i,
|
||||
sizeof(phycfg_int) / sizeof(u32),
|
||||
(u32 *)&phycfg_int);
|
||||
|
||||
} else { /* External PHY */
|
||||
pm8001_set_phy_profile_single(pm8001_ha, i,
|
||||
sizeof(phycfg_ext) / sizeof(u32),
|
||||
(u32 *)&phycfg_ext);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pm8001_configure_phy_settings : Configures PHY settings based on vendor ID.
|
||||
* @pm8001_ha : our hba.
|
||||
|
@ -740,6 +865,11 @@ static int pm8001_configure_phy_settings(struct pm8001_hba_info *pm8001_ha)
|
|||
{
|
||||
switch (pm8001_ha->pdev->subsystem_vendor) {
|
||||
case PCI_VENDOR_ID_ATTO:
|
||||
if (pm8001_ha->pdev->device == 0x0042) /* 6Gb */
|
||||
return 0;
|
||||
else
|
||||
return pm8001_set_phy_settings_ven_117c_12G(pm8001_ha);
|
||||
|
||||
case PCI_VENDOR_ID_ADAPTEC2:
|
||||
case 0:
|
||||
return 0;
|
||||
|
|
|
@ -710,6 +710,8 @@ int pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha);
|
|||
int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
|
||||
void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
|
||||
u32 length, u8 *buf);
|
||||
void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha,
|
||||
u32 phy, u32 length, u32 *buf);
|
||||
int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
|
||||
ssize_t pm80xx_get_fatal_dump(struct device *cdev,
|
||||
struct device_attribute *attr, char *buf);
|
||||
|
|
|
@ -4576,6 +4576,38 @@ void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
|
|||
}
|
||||
PM8001_INIT_DBG(pm8001_ha, pm8001_printk("phy settings completed\n"));
|
||||
}
|
||||
|
||||
void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha,
|
||||
u32 phy, u32 length, u32 *buf)
|
||||
{
|
||||
u32 tag, opc;
|
||||
int rc, i;
|
||||
struct set_phy_profile_req payload;
|
||||
struct inbound_queue_table *circularQ;
|
||||
|
||||
memset(&payload, 0, sizeof(payload));
|
||||
|
||||
rc = pm8001_tag_alloc(pm8001_ha, &tag);
|
||||
if (rc)
|
||||
PM8001_INIT_DBG(pm8001_ha, pm8001_printk("Invalid tag"));
|
||||
|
||||
circularQ = &pm8001_ha->inbnd_q_tbl[0];
|
||||
opc = OPC_INB_SET_PHY_PROFILE;
|
||||
|
||||
payload.tag = cpu_to_le32(tag);
|
||||
payload.ppc_phyid = (((SAS_PHY_ANALOG_SETTINGS_PAGE & 0xF) << 8)
|
||||
| (phy & 0xFF));
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
payload.reserved[i] = cpu_to_le32(*(buf + i));
|
||||
|
||||
rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
|
||||
if (rc)
|
||||
pm8001_tag_free(pm8001_ha, tag);
|
||||
|
||||
PM8001_INIT_DBG(pm8001_ha,
|
||||
pm8001_printk("PHY %d settings applied", phy));
|
||||
}
|
||||
const struct pm8001_dispatch pm8001_80xx_dispatch = {
|
||||
.name = "pmc80xx",
|
||||
.chip_init = pm80xx_chip_init,
|
||||
|
|
Загрузка…
Ссылка в новой задаче