summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_atombios.c
diff options
context:
space:
mode:
authorAlex Deucher <alexander.deucher@amd.com>2013-03-28 14:47:34 -0400
committerAlex Deucher <alexander.deucher@amd.com>2013-06-27 19:16:42 -0400
commit779187f2c3e69b8c06488538e0fd9fd02163359e (patch)
treea803814043858c8d916571da3625d55fc5823b1b /drivers/gpu/drm/radeon/radeon_atombios.c
parentda289525b6010bd4617c94bdd95f4980b7a297ec (diff)
downloadblackbird-obmc-linux-779187f2c3e69b8c06488538e0fd9fd02163359e.tar.gz
blackbird-obmc-linux-779187f2c3e69b8c06488538e0fd9fd02163359e.zip
drm/radeon/atom: fix voltage table parsing
The arrays items are variable sized. Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_atombios.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c320
1 files changed, 170 insertions, 150 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index e36144630a7d..5d798c9176e7 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -3118,6 +3118,63 @@ union voltage_object_info {
struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3;
};
+union voltage_object {
+ struct _ATOM_VOLTAGE_OBJECT v1;
+ struct _ATOM_VOLTAGE_OBJECT_V2 v2;
+ union _ATOM_VOLTAGE_OBJECT_V3 v3;
+};
+
+static ATOM_VOLTAGE_OBJECT *atom_lookup_voltage_object_v1(ATOM_VOLTAGE_OBJECT_INFO *v1,
+ u8 voltage_type)
+{
+ u32 size = v1->sHeader.usStructureSize;
+ u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO, asVoltageObj[0]);
+ u8 *start = (u8 *)v1;
+
+ while (offset < size) {
+ ATOM_VOLTAGE_OBJECT *vo = (ATOM_VOLTAGE_OBJECT *)(start + offset);
+ if (vo->ucVoltageType == voltage_type)
+ return vo;
+ offset += offsetof(ATOM_VOLTAGE_OBJECT, asFormula.ucVIDAdjustEntries) +
+ vo->asFormula.ucNumOfVoltageEntries;
+ }
+ return NULL;
+}
+
+static ATOM_VOLTAGE_OBJECT_V2 *atom_lookup_voltage_object_v2(ATOM_VOLTAGE_OBJECT_INFO_V2 *v2,
+ u8 voltage_type)
+{
+ u32 size = v2->sHeader.usStructureSize;
+ u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V2, asVoltageObj[0]);
+ u8 *start = (u8*)v2;
+
+ while (offset < size) {
+ ATOM_VOLTAGE_OBJECT_V2 *vo = (ATOM_VOLTAGE_OBJECT_V2 *)(start + offset);
+ if (vo->ucVoltageType == voltage_type)
+ return vo;
+ offset += offsetof(ATOM_VOLTAGE_OBJECT_V2, asFormula.asVIDAdjustEntries) +
+ (vo->asFormula.ucNumOfVoltageEntries * sizeof(VOLTAGE_LUT_ENTRY));
+ }
+ return NULL;
+}
+
+static ATOM_VOLTAGE_OBJECT_V3 *atom_lookup_voltage_object_v3(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *v3,
+ u8 voltage_type, u8 voltage_mode)
+{
+ u32 size = v3->sHeader.usStructureSize;
+ u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);
+ u8 *start = (u8*)v3;
+
+ while (offset < size) {
+ ATOM_VOLTAGE_OBJECT_V3 *vo = (ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);
+ if ((vo->asGpioVoltageObj.sHeader.ucVoltageType == voltage_type) &&
+ (vo->asGpioVoltageObj.sHeader.ucVoltageMode == voltage_mode))
+ return vo;
+ offset += vo->asGpioVoltageObj.sHeader.usSize;
+ }
+ return NULL;
+}
+
bool
radeon_atom_is_voltage_gpio(struct radeon_device *rdev,
u8 voltage_type, u8 voltage_mode)
@@ -3125,8 +3182,8 @@ radeon_atom_is_voltage_gpio(struct radeon_device *rdev,
int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
u8 frev, crev;
u16 data_offset, size;
- int num_indices, i;
union voltage_object_info *voltage_info;
+ union voltage_object *voltage_object = NULL;
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
&frev, &crev, &data_offset)) {
@@ -3138,26 +3195,18 @@ radeon_atom_is_voltage_gpio(struct radeon_device *rdev,
case 2:
switch (crev) {
case 1:
- num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
- sizeof(ATOM_VOLTAGE_OBJECT);
-
- for (i = 0; i < num_indices; i++) {
- if ((voltage_info->v1.asVoltageObj[i].ucVoltageType == voltage_type) &&
- (voltage_info->v1.asVoltageObj[i].asControl.ucVoltageControlId ==
- VOLTAGE_CONTROLLED_BY_GPIO))
- return true;
- }
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
+ if (voltage_object &&
+ (voltage_object->v1.asControl.ucVoltageControlId == VOLTAGE_CONTROLLED_BY_GPIO))
+ return true;
break;
case 2:
- num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
- sizeof(ATOM_VOLTAGE_OBJECT_V2);
-
- for (i = 0; i < num_indices; i++) {
- if ((voltage_info->v2.asVoltageObj[i].ucVoltageType == voltage_type) &&
- (voltage_info->v2.asVoltageObj[i].asControl.ucVoltageControlId ==
- VOLTAGE_CONTROLLED_BY_GPIO))
- return true;
- }
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
+ if (voltage_object &&
+ (voltage_object->v2.asControl.ucVoltageControlId == VOLTAGE_CONTROLLED_BY_GPIO))
+ return true;
break;
default:
DRM_ERROR("unknown voltage object table\n");
@@ -3167,16 +3216,9 @@ radeon_atom_is_voltage_gpio(struct radeon_device *rdev,
case 3:
switch (crev) {
case 1:
- num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
- sizeof(ATOM_VOLTAGE_OBJECT_V3);
-
- for (i = 0; i < num_indices; i++) {
- if ((voltage_info->v3.asVoltageObj[i].asGpioVoltageObj.sHeader.ucVoltageType ==
- voltage_type) &&
- (voltage_info->v3.asVoltageObj[i].asGpioVoltageObj.sHeader.ucVoltageMode ==
- voltage_mode))
- return true;
- }
+ if (atom_lookup_voltage_object_v3(&voltage_info->v3,
+ voltage_type, voltage_mode))
+ return true;
break;
default:
DRM_ERROR("unknown voltage object table\n");
@@ -3198,8 +3240,8 @@ int radeon_atom_get_max_voltage(struct radeon_device *rdev,
int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
u8 frev, crev;
u16 data_offset, size;
- int num_indices, i;
union voltage_object_info *voltage_info;
+ union voltage_object *voltage_object = NULL;
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
&frev, &crev, &data_offset)) {
@@ -3208,42 +3250,36 @@ int radeon_atom_get_max_voltage(struct radeon_device *rdev,
switch (crev) {
case 1:
- num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
- sizeof(ATOM_VOLTAGE_OBJECT);
-
- for (i = 0; i < num_indices; i++) {
- if (voltage_info->v1.asVoltageObj[i].ucVoltageType == voltage_type) {
- ATOM_VOLTAGE_FORMULA *formula =
- &voltage_info->v1.asVoltageObj[i].asFormula;
- if (formula->ucFlag & 1)
- *max_voltage =
- le16_to_cpu(formula->usVoltageBaseLevel) +
- formula->ucNumOfVoltageEntries / 2 *
- le16_to_cpu(formula->usVoltageStep);
- else
- *max_voltage =
- le16_to_cpu(formula->usVoltageBaseLevel) +
- (formula->ucNumOfVoltageEntries - 1) *
- le16_to_cpu(formula->usVoltageStep);
- return 0;
- }
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
+ if (voltage_object) {
+ ATOM_VOLTAGE_FORMULA *formula =
+ &voltage_object->v1.asFormula;
+ if (formula->ucFlag & 1)
+ *max_voltage =
+ le16_to_cpu(formula->usVoltageBaseLevel) +
+ formula->ucNumOfVoltageEntries / 2 *
+ le16_to_cpu(formula->usVoltageStep);
+ else
+ *max_voltage =
+ le16_to_cpu(formula->usVoltageBaseLevel) +
+ (formula->ucNumOfVoltageEntries - 1) *
+ le16_to_cpu(formula->usVoltageStep);
+ return 0;
}
break;
case 2:
- num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
- sizeof(ATOM_VOLTAGE_OBJECT_V2);
-
- for (i = 0; i < num_indices; i++) {
- if (voltage_info->v2.asVoltageObj[i].ucVoltageType == voltage_type) {
- ATOM_VOLTAGE_FORMULA_V2 *formula =
- &voltage_info->v2.asVoltageObj[i].asFormula;
- if (formula->ucNumOfVoltageEntries) {
- *max_voltage =
- le16_to_cpu(formula->asVIDAdjustEntries[
- formula->ucNumOfVoltageEntries - 1
- ].usVoltageValue);
- return 0;
- }
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
+ if (voltage_object) {
+ ATOM_VOLTAGE_FORMULA_V2 *formula =
+ &voltage_object->v2.asFormula;
+ if (formula->ucNumOfVoltageEntries) {
+ *max_voltage =
+ le16_to_cpu(formula->asVIDAdjustEntries[
+ formula->ucNumOfVoltageEntries - 1
+ ].usVoltageValue);
+ return 0;
}
}
break;
@@ -3262,8 +3298,8 @@ int radeon_atom_get_min_voltage(struct radeon_device *rdev,
int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
u8 frev, crev;
u16 data_offset, size;
- int num_indices, i;
union voltage_object_info *voltage_info;
+ union voltage_object *voltage_object = NULL;
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
&frev, &crev, &data_offset)) {
@@ -3272,34 +3308,28 @@ int radeon_atom_get_min_voltage(struct radeon_device *rdev,
switch (crev) {
case 1:
- num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
- sizeof(ATOM_VOLTAGE_OBJECT);
-
- for (i = 0; i < num_indices; i++) {
- if (voltage_info->v1.asVoltageObj[i].ucVoltageType == voltage_type) {
- ATOM_VOLTAGE_FORMULA *formula =
- &voltage_info->v1.asVoltageObj[i].asFormula;
- *min_voltage =
- le16_to_cpu(formula->usVoltageBaseLevel);
- return 0;
- }
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
+ if (voltage_object) {
+ ATOM_VOLTAGE_FORMULA *formula =
+ &voltage_object->v1.asFormula;
+ *min_voltage =
+ le16_to_cpu(formula->usVoltageBaseLevel);
+ return 0;
}
break;
case 2:
- num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
- sizeof(ATOM_VOLTAGE_OBJECT_V2);
-
- for (i = 0; i < num_indices; i++) {
- if (voltage_info->v2.asVoltageObj[i].ucVoltageType == voltage_type) {
- ATOM_VOLTAGE_FORMULA_V2 *formula =
- &voltage_info->v2.asVoltageObj[i].asFormula;
- if (formula->ucNumOfVoltageEntries) {
- *min_voltage =
- le16_to_cpu(formula->asVIDAdjustEntries[
- 0
- ].usVoltageValue);
- return 0;
- }
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
+ if (voltage_object) {
+ ATOM_VOLTAGE_FORMULA_V2 *formula =
+ &voltage_object->v2.asFormula;
+ if (formula->ucNumOfVoltageEntries) {
+ *min_voltage =
+ le16_to_cpu(formula->asVIDAdjustEntries[
+ 0
+ ].usVoltageValue);
+ return 0;
}
}
break;
@@ -3318,8 +3348,8 @@ int radeon_atom_get_voltage_step(struct radeon_device *rdev,
int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
u8 frev, crev;
u16 data_offset, size;
- int num_indices, i;
union voltage_object_info *voltage_info;
+ union voltage_object *voltage_object = NULL;
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
&frev, &crev, &data_offset)) {
@@ -3328,21 +3358,18 @@ int radeon_atom_get_voltage_step(struct radeon_device *rdev,
switch (crev) {
case 1:
- num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
- sizeof(ATOM_VOLTAGE_OBJECT);
-
- for (i = 0; i < num_indices; i++) {
- if (voltage_info->v1.asVoltageObj[i].ucVoltageType == voltage_type) {
- ATOM_VOLTAGE_FORMULA *formula =
- &voltage_info->v1.asVoltageObj[i].asFormula;
- if (formula->ucFlag & 1)
- *voltage_step =
- (le16_to_cpu(formula->usVoltageStep) + 1) / 2;
- else
- *voltage_step =
- le16_to_cpu(formula->usVoltageStep);
- return 0;
- }
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
+ if (voltage_object) {
+ ATOM_VOLTAGE_FORMULA *formula =
+ &voltage_object->v1.asFormula;
+ if (formula->ucFlag & 1)
+ *voltage_step =
+ (le16_to_cpu(formula->usVoltageStep) + 1) / 2;
+ else
+ *voltage_step =
+ le16_to_cpu(formula->usVoltageStep);
+ return 0;
}
break;
case 2:
@@ -3389,8 +3416,9 @@ int radeon_atom_get_voltage_table(struct radeon_device *rdev,
int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
u8 frev, crev;
u16 data_offset, size;
- int num_indices, i, j, ret;
+ int i, ret;
union voltage_object_info *voltage_info;
+ union voltage_object *voltage_object = NULL;
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
&frev, &crev, &data_offset)) {
@@ -3405,29 +3433,26 @@ int radeon_atom_get_voltage_table(struct radeon_device *rdev,
DRM_ERROR("old table version %d, %d\n", frev, crev);
return -EINVAL;
case 2:
- num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
- sizeof(ATOM_VOLTAGE_OBJECT_V2);
-
- for (i = 0; i < num_indices; i++) {
- if (voltage_info->v2.asVoltageObj[i].ucVoltageType == voltage_type) {
- ATOM_VOLTAGE_FORMULA_V2 *formula =
- &voltage_info->v2.asVoltageObj[i].asFormula;
- if (formula->ucNumOfVoltageEntries > MAX_VOLTAGE_ENTRIES)
- return -EINVAL;
- for (j = 0; j < formula->ucNumOfVoltageEntries; j++) {
- voltage_table->entries[j].value =
- le16_to_cpu(formula->asVIDAdjustEntries[j].usVoltageValue);
- ret = radeon_atom_get_voltage_gpio_settings(rdev,
- voltage_table->entries[j].value,
- voltage_type,
- &voltage_table->entries[j].smio_low,
- &voltage_table->mask_low);
- if (ret)
- return ret;
- }
- voltage_table->count = formula->ucNumOfVoltageEntries;
- return 0;
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
+ if (voltage_object) {
+ ATOM_VOLTAGE_FORMULA_V2 *formula =
+ &voltage_object->v2.asFormula;
+ if (formula->ucNumOfVoltageEntries > MAX_VOLTAGE_ENTRIES)
+ return -EINVAL;
+ for (i = 0; i < formula->ucNumOfVoltageEntries; i++) {
+ voltage_table->entries[i].value =
+ le16_to_cpu(formula->asVIDAdjustEntries[i].usVoltageValue);
+ ret = radeon_atom_get_voltage_gpio_settings(rdev,
+ voltage_table->entries[i].value,
+ voltage_type,
+ &voltage_table->entries[i].smio_low,
+ &voltage_table->mask_low);
+ if (ret)
+ return ret;
}
+ voltage_table->count = formula->ucNumOfVoltageEntries;
+ return 0;
}
break;
default:
@@ -3438,29 +3463,24 @@ int radeon_atom_get_voltage_table(struct radeon_device *rdev,
case 3:
switch (crev) {
case 1:
- num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
- sizeof(ATOM_VOLTAGE_OBJECT_V3);
-
- for (i = 0; i < num_indices; i++) {
- if ((voltage_info->v3.asVoltageObj[i].asGpioVoltageObj.sHeader.ucVoltageType ==
- voltage_type) &&
- (voltage_info->v3.asVoltageObj[i].asGpioVoltageObj.sHeader.ucVoltageMode ==
- voltage_mode)) {
- ATOM_GPIO_VOLTAGE_OBJECT_V3 *gpio =
- &voltage_info->v3.asVoltageObj[i].asGpioVoltageObj;
- if (gpio->ucGpioEntryNum > MAX_VOLTAGE_ENTRIES)
- return -EINVAL;
- for (j = 0; j < gpio->ucGpioEntryNum; j++) {
- voltage_table->entries[j].value =
- le16_to_cpu(gpio->asVolGpioLut[j].usVoltageValue);
- voltage_table->entries[j].smio_low =
- le32_to_cpu(gpio->asVolGpioLut[j].ulVoltageId);
- }
- voltage_table->mask_low = le32_to_cpu(gpio->ulGpioMaskVal);
- voltage_table->count = gpio->ucGpioEntryNum;
- voltage_table->phase_delay = gpio->ucPhaseDelay;
- return 0;
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v3(&voltage_info->v3,
+ voltage_type, voltage_mode);
+ if (voltage_object) {
+ ATOM_GPIO_VOLTAGE_OBJECT_V3 *gpio =
+ &voltage_object->v3.asGpioVoltageObj;
+ if (gpio->ucGpioEntryNum > MAX_VOLTAGE_ENTRIES)
+ return -EINVAL;
+ for (i = 0; i < gpio->ucGpioEntryNum; i++) {
+ voltage_table->entries[i].value =
+ le16_to_cpu(gpio->asVolGpioLut[i].usVoltageValue);
+ voltage_table->entries[i].smio_low =
+ le32_to_cpu(gpio->asVolGpioLut[i].ulVoltageId);
}
+ voltage_table->mask_low = le32_to_cpu(gpio->ulGpioMaskVal);
+ voltage_table->count = gpio->ucGpioEntryNum;
+ voltage_table->phase_delay = gpio->ucPhaseDelay;
+ return 0;
}
break;
default:
OpenPOWER on IntegriCloud