drm/nouveau: downgrade severity of most init table parser errors
authorBen Skeggs <bskeggs@redhat.com>
Tue, 29 Jun 2010 06:09:24 +0000 (16:09 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 13 Jul 2010 00:13:10 +0000 (10:13 +1000)
As long as we know the length of the opcode, we're probably better off
trying to parse the remainder of an init table rather than aborting in
the middle of it.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_bios.c

index ed0f5303850d1c68aed15b08cc5c6fc47c60498e..2e8cdd71a6ecda24ae0b98eaf80a6f11fdba16ed 100644 (file)
@@ -935,7 +935,7 @@ init_io_restrict_prog(struct nvbios *bios, uint16_t offset,
                NV_ERROR(bios->dev,
                         "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
                         offset, config, count);
-               return -EINVAL;
+               return len;
        }
 
        configval = ROM32(bios->data[offset + 11 + config * 4]);
@@ -1037,7 +1037,7 @@ init_io_restrict_pll(struct nvbios *bios, uint16_t offset,
                NV_ERROR(bios->dev,
                         "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
                         offset, config, count);
-               return -EINVAL;
+               return len;
        }
 
        freq = ROM16(bios->data[offset + 12 + config * 2]);
@@ -1209,7 +1209,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        dpe = nouveau_bios_dp_table(dev, dcb, &dummy);
        if (!dpe) {
                NV_ERROR(dev, "0x%04X: INIT_3A: no encoder table!!\n", offset);
-               return -EINVAL;
+               return 3;
        }
 
        switch (cond) {
@@ -1233,12 +1233,16 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                int ret;
 
                auxch = nouveau_i2c_find(dev, bios->display.output->i2c_index);
-               if (!auxch)
-                       return -ENODEV;
+               if (!auxch) {
+                       NV_ERROR(dev, "0x%04X: couldn't get auxch\n", offset);
+                       return 3;
+               }
 
                ret = nouveau_dp_auxch(auxch, 9, 0xd, &cond, 1);
-               if (ret)
-                       return ret;
+               if (ret) {
+                       NV_ERROR(dev, "0x%04X: auxch rd fail: %d\n", offset, ret);
+                       return 3;
+               }
 
                if (cond & 1)
                        iexec->execute = false;
@@ -1407,7 +1411,7 @@ init_io_restrict_pll2(struct nvbios *bios, uint16_t offset,
                NV_ERROR(bios->dev,
                         "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
                         offset, config, count);
-               return -EINVAL;
+               return len;
        }
 
        freq = ROM32(bios->data[offset + 11 + config * 4]);
@@ -1467,6 +1471,7 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         * "mask n" and OR it with "data n" before writing it back to the device
         */
 
+       struct drm_device *dev = bios->dev;
        uint8_t i2c_index = bios->data[offset + 1];
        uint8_t i2c_address = bios->data[offset + 2] >> 1;
        uint8_t count = bios->data[offset + 3];
@@ -1481,9 +1486,11 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                      "Count: 0x%02X\n",
                offset, i2c_index, i2c_address, count);
 
-       chan = init_i2c_device_find(bios->dev, i2c_index);
-       if (!chan)
-               return -ENODEV;
+       chan = init_i2c_device_find(dev, i2c_index);
+       if (!chan) {
+               NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset);
+               return len;
+       }
 
        for (i = 0; i < count; i++) {
                uint8_t reg = bios->data[offset + 4 + i * 3];
@@ -1494,8 +1501,10 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
                                     I2C_SMBUS_READ, reg,
                                     I2C_SMBUS_BYTE_DATA, &val);
-               if (ret < 0)
-                       return ret;
+               if (ret < 0) {
+                       NV_ERROR(dev, "0x%04X: i2c rd fail: %d\n", offset, ret);
+                       return len;
+               }
 
                BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, "
                              "Mask: 0x%02X, Data: 0x%02X\n",
@@ -1509,8 +1518,10 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
                                     I2C_SMBUS_WRITE, reg,
                                     I2C_SMBUS_BYTE_DATA, &val);
-               if (ret < 0)
-                       return ret;
+               if (ret < 0) {
+                       NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret);
+                       return len;
+               }
        }
 
        return len;
@@ -1535,6 +1546,7 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         * "DCB I2C table entry index", set the register to "data n"
         */
 
+       struct drm_device *dev = bios->dev;
        uint8_t i2c_index = bios->data[offset + 1];
        uint8_t i2c_address = bios->data[offset + 2] >> 1;
        uint8_t count = bios->data[offset + 3];
@@ -1549,9 +1561,11 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                      "Count: 0x%02X\n",
                offset, i2c_index, i2c_address, count);
 
-       chan = init_i2c_device_find(bios->dev, i2c_index);
-       if (!chan)
-               return -ENODEV;
+       chan = init_i2c_device_find(dev, i2c_index);
+       if (!chan) {
+               NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset);
+               return len;
+       }
 
        for (i = 0; i < count; i++) {
                uint8_t reg = bios->data[offset + 4 + i * 2];
@@ -1568,8 +1582,10 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
                                     I2C_SMBUS_WRITE, reg,
                                     I2C_SMBUS_BYTE_DATA, &val);
-               if (ret < 0)
-                       return ret;
+               if (ret < 0) {
+                       NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret);
+                       return len;
+               }
        }
 
        return len;
@@ -1592,6 +1608,7 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         * address" on the I2C bus given by "DCB I2C table entry index"
         */
 
+       struct drm_device *dev = bios->dev;
        uint8_t i2c_index = bios->data[offset + 1];
        uint8_t i2c_address = bios->data[offset + 2] >> 1;
        uint8_t count = bios->data[offset + 3];
@@ -1599,7 +1616,7 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        struct nouveau_i2c_chan *chan;
        struct i2c_msg msg;
        uint8_t data[256];
-       int i;
+       int ret, i;
 
        if (!iexec->execute)
                return len;
@@ -1608,9 +1625,11 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                      "Count: 0x%02X\n",
                offset, i2c_index, i2c_address, count);
 
-       chan = init_i2c_device_find(bios->dev, i2c_index);
-       if (!chan)
-               return -ENODEV;
+       chan = init_i2c_device_find(dev, i2c_index);
+       if (!chan) {
+               NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset);
+               return len;
+       }
 
        for (i = 0; i < count; i++) {
                data[i] = bios->data[offset + 4 + i];
@@ -1623,8 +1642,11 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                msg.flags = 0;
                msg.len = count;
                msg.buf = data;
-               if (i2c_transfer(&chan->adapter, &msg, 1) != 1)
-                       return -EIO;
+               ret = i2c_transfer(&chan->adapter, &msg, 1);
+               if (ret != 1) {
+                       NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret);
+                       return len;
+               }
        }
 
        return len;
@@ -1648,6 +1670,7 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         * used -- see get_tmds_index_reg()
         */
 
+       struct drm_device *dev = bios->dev;
        uint8_t mlv = bios->data[offset + 1];
        uint32_t tmdsaddr = bios->data[offset + 2];
        uint8_t mask = bios->data[offset + 3];
@@ -1662,8 +1685,10 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                offset, mlv, tmdsaddr, mask, data);
 
        reg = get_tmds_index_reg(bios->dev, mlv);
-       if (!reg)
-               return -EINVAL;
+       if (!reg) {
+               NV_ERROR(dev, "0x%04X: no tmds_index_reg\n", offset);
+               return 5;
+       }
 
        bios_wr32(bios, reg,
                  tmdsaddr | NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE);
@@ -1693,6 +1718,7 @@ init_zm_tmds_group(struct nvbios *bios, uint16_t offset,
         * register is used -- see get_tmds_index_reg()
         */
 
+       struct drm_device *dev = bios->dev;
        uint8_t mlv = bios->data[offset + 1];
        uint8_t count = bios->data[offset + 2];
        int len = 3 + count * 2;
@@ -1706,8 +1732,10 @@ init_zm_tmds_group(struct nvbios *bios, uint16_t offset,
                offset, mlv, count);
 
        reg = get_tmds_index_reg(bios->dev, mlv);
-       if (!reg)
-               return -EINVAL;
+       if (!reg) {
+               NV_ERROR(dev, "0x%04X: no tmds_index_reg\n", offset);
+               return len;
+       }
 
        for (i = 0; i < count; i++) {
                uint8_t tmdsaddr = bios->data[offset + 3 + i * 2];
@@ -2816,7 +2844,7 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
        if (dev_priv->card_type != NV_50) {
                NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n");
-               return -ENODEV;
+               return 1;
        }
 
        if (!iexec->execute)
@@ -2888,10 +2916,7 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset,
        uint8_t index;
        int i;
 
-
-       if (!iexec->execute)
-               return len;
-
+       /* critical! to know the length of the opcode */;
        if (!blocklen) {
                NV_ERROR(bios->dev,
                         "0x%04X: Zero block length - has the M table "
@@ -2899,6 +2924,9 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset,
                return -EINVAL;
        }
 
+       if (!iexec->execute)
+               return len;
+
        strap_ramcfg = (bios_rd32(bios, NV_PEXTDEV_BOOT_0) >> 2) & 0xf;
        index = bios->data[bios->ram_restrict_tbl_ptr + strap_ramcfg];
 
@@ -3080,14 +3108,14 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
        if (!bios->display.output) {
                NV_ERROR(dev, "INIT_AUXCH: no active output\n");
-               return -EINVAL;
+               return len;
        }
 
        auxch = init_i2c_device_find(dev, bios->display.output->i2c_index);
        if (!auxch) {
                NV_ERROR(dev, "INIT_AUXCH: couldn't get auxch %d\n",
                         bios->display.output->i2c_index);
-               return -ENODEV;
+               return len;
        }
 
        if (!iexec->execute)
@@ -3100,7 +3128,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                ret = nouveau_dp_auxch(auxch, 9, addr, &data, 1);
                if (ret) {
                        NV_ERROR(dev, "INIT_AUXCH: rd auxch fail %d\n", ret);
-                       return ret;
+                       return len;
                }
 
                data &= bios->data[offset + 0];
@@ -3109,7 +3137,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                ret = nouveau_dp_auxch(auxch, 8, addr, &data, 1);
                if (ret) {
                        NV_ERROR(dev, "INIT_AUXCH: wr auxch fail %d\n", ret);
-                       return ret;
+                       return len;
                }
        }
 
@@ -3139,14 +3167,14 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
        if (!bios->display.output) {
                NV_ERROR(dev, "INIT_ZM_AUXCH: no active output\n");
-               return -EINVAL;
+               return len;
        }
 
        auxch = init_i2c_device_find(dev, bios->display.output->i2c_index);
        if (!auxch) {
                NV_ERROR(dev, "INIT_ZM_AUXCH: couldn't get auxch %d\n",
                         bios->display.output->i2c_index);
-               return -ENODEV;
+               return len;
        }
 
        if (!iexec->execute)
@@ -3157,7 +3185,7 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                ret = nouveau_dp_auxch(auxch, 8, addr, &bios->data[offset], 1);
                if (ret) {
                        NV_ERROR(dev, "INIT_ZM_AUXCH: wr auxch fail %d\n", ret);
-                       return ret;
+                       return len;
                }
        }