[kernel/f15] nouveau: fix two instances of an oops in ttm clear() (rhbz#751753)
Josh Boyer
jwboyer at fedoraproject.org
Mon Nov 28 21:10:26 UTC 2011
commit 27ec4e1df273046c07768b94c7d6f2662838566c
Author: Ben Skeggs <bskeggs at redhat.com>
Date: Mon Nov 28 12:10:12 2011 +1000
nouveau: fix two instances of an oops in ttm clear() (rhbz#751753)
drm-nouveau-updates.patch | 998 ++++++++++++++++++++++-----------------------
kernel.spec | 5 +-
2 files changed, 498 insertions(+), 505 deletions(-)
---
diff --git a/drm-nouveau-updates.patch b/drm-nouveau-updates.patch
index 1e7c927..cd9bded 100644
--- a/drm-nouveau-updates.patch
+++ b/drm-nouveau-updates.patch
@@ -781,10 +781,10 @@ index 890d50e..7226f41 100644
else
page_shift = 12;
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
-index b0d753f..a319d56 100644
+index 0e3241c..bb6ec9e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
-@@ -411,13 +411,17 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
+@@ -412,13 +412,17 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
return ret;
init->channel = chan->id;
@@ -960,12 +960,19 @@ diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouv
index 7beb82a..de5efe7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
-@@ -28,418 +28,619 @@
+@@ -28,557 +28,669 @@
#include "nouveau_i2c.h"
#include "nouveau_connector.h"
#include "nouveau_encoder.h"
+#include "nouveau_crtc.h"
-+
+
+-static int
+-auxch_rd(struct drm_encoder *encoder, int address, uint8_t *buf, int size)
+-{
+- struct drm_device *dev = encoder->dev;
+- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+- struct nouveau_i2c_chan *auxch;
+- int ret;
+/******************************************************************************
+ * aux channel util functions
+ *****************************************************************************/
@@ -975,34 +982,38 @@ index 7beb82a..de5efe7 100644
+ } \
+} while (0)
+#define AUX_ERR(fmt, args...) NV_ERROR(dev, "AUXCH(%d): " fmt, ch, ##args)
-+
+
+- auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
+- if (!auxch)
+- return -ENODEV;
+-
+- ret = nouveau_dp_auxch(auxch, 9, address, buf, size);
+- if (ret)
+- return ret;
+-
+- return 0;
+static void
+auxch_fini(struct drm_device *dev, int ch)
+{
+ nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000);
-+}
+ }
static int
--auxch_rd(struct drm_encoder *encoder, int address, uint8_t *buf, int size)
+-auxch_wr(struct drm_encoder *encoder, int address, uint8_t *buf, int size)
+auxch_init(struct drm_device *dev, int ch)
{
- struct drm_device *dev = encoder->dev;
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nouveau_i2c_chan *auxch;
- int ret;
--
-- auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
-- if (!auxch)
-- return -ENODEV;
--
-- ret = nouveau_dp_auxch(auxch, 9, address, buf, size);
-- if (ret)
-- return ret;
+ const u32 unksel = 1; /* nfi which to use, or if it matters.. */
+ const u32 ureq = unksel ? 0x00100000 : 0x00200000;
+ const u32 urep = unksel ? 0x01000000 : 0x02000000;
+ u32 ctrl, timeout;
-+
+
+- auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
+- if (!auxch)
+- return -ENODEV;
+ /* wait up to 1ms for any previous transaction to be done... */
+ timeout = 1000;
+ do {
@@ -1013,7 +1024,9 @@ index 7beb82a..de5efe7 100644
+ return -EBUSY;
+ }
+ } while (ctrl & 0x03010000);
-+
+
+- ret = nouveau_dp_auxch(auxch, 8, address, buf, size);
+- return ret;
+ /* set some magic, and wait up to 1ms for it to appear */
+ nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq);
+ timeout = 1000;
@@ -1026,52 +1039,44 @@ index 7beb82a..de5efe7 100644
+ return -EBUSY;
+ }
+ } while ((ctrl & 0x03000000) != urep);
-
- return 0;
++
++ return 0;
}
static int
--auxch_wr(struct drm_encoder *encoder, int address, uint8_t *buf, int size)
+-nouveau_dp_lane_count_set(struct drm_encoder *encoder, uint8_t cmd)
+auxch_tx(struct drm_device *dev, int ch, u8 type, u32 addr, u8 *data, u8 size)
{
- struct drm_device *dev = encoder->dev;
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-- struct nouveau_i2c_chan *auxch;
-- int ret;
+- uint32_t tmp;
+- int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1);
+ u32 ctrl, stat, timeout, retries;
+ u32 xbuf[4] = {};
+ int ret, i;
-- auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
-- if (!auxch)
-- return -ENODEV;
+- tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
+- tmp &= ~(NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED |
+- NV50_SOR_DP_CTRL_LANE_MASK);
+- tmp |= ((1 << (cmd & DP_LANE_COUNT_MASK)) - 1) << 16;
+- if (cmd & DP_LANE_COUNT_ENHANCED_FRAME_EN)
+- tmp |= NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED;
+- nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp);
+ AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
-- ret = nouveau_dp_auxch(auxch, 8, address, buf, size);
-- return ret;
+- return auxch_wr(encoder, DP_LANE_COUNT_SET, &cmd, 1);
-}
+ ret = auxch_init(dev, ch);
+ if (ret)
+ goto out;
-static int
--nouveau_dp_lane_count_set(struct drm_encoder *encoder, uint8_t cmd)
+-nouveau_dp_link_bw_set(struct drm_encoder *encoder, uint8_t cmd)
-{
- struct drm_device *dev = encoder->dev;
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- uint32_t tmp;
-- int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1);
--
-- tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
-- tmp &= ~(NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED |
-- NV50_SOR_DP_CTRL_LANE_MASK);
-- tmp |= ((1 << (cmd & DP_LANE_COUNT_MASK)) - 1) << 16;
-- if (cmd & DP_LANE_COUNT_ENHANCED_FRAME_EN)
-- tmp |= NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED;
-- nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp);
--
-- return auxch_wr(encoder, DP_LANE_COUNT_SET, &cmd, 1);
--}
+- int reg = 0x614300 + (nv_encoder->or * 0x800);
+ stat = nv_rd32(dev, 0x00e4e8 + (ch * 0x50));
+ if (!(stat & 0x10000000)) {
+ AUX_DBG("sink not detected\n");
@@ -1079,13 +1084,11 @@ index 7beb82a..de5efe7 100644
+ goto out;
+ }
--static int
--nouveau_dp_link_bw_set(struct drm_encoder *encoder, uint8_t cmd)
--{
-- struct drm_device *dev = encoder->dev;
-- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-- uint32_t tmp;
-- int reg = 0x614300 + (nv_encoder->or * 0x800);
+- tmp = nv_rd32(dev, reg);
+- tmp &= 0xfff3ffff;
+- if (cmd == DP_LINK_BW_2_7)
+- tmp |= 0x00040000;
+- nv_wr32(dev, reg, tmp);
+ if (!(type & 1)) {
+ memcpy(xbuf, data, size);
+ for (i = 0; i < 16; i += 4) {
@@ -1094,17 +1097,23 @@ index 7beb82a..de5efe7 100644
+ }
+ }
-- tmp = nv_rd32(dev, reg);
-- tmp &= 0xfff3ffff;
-- if (cmd == DP_LINK_BW_2_7)
-- tmp |= 0x00040000;
-- nv_wr32(dev, reg, tmp);
+- return auxch_wr(encoder, DP_LINK_BW_SET, &cmd, 1);
+-}
+ ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
+ ctrl &= ~0x0001f0ff;
+ ctrl |= type << 12;
+ ctrl |= size - 1;
+ nv_wr32(dev, 0x00e4e0 + (ch * 0x50), addr);
-+
+
+-static int
+-nouveau_dp_link_train_set(struct drm_encoder *encoder, int pattern)
+-{
+- struct drm_device *dev = encoder->dev;
+- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+- uint32_t tmp;
+- uint8_t cmd;
+- int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1);
+- int ret;
+ /* retry transaction a number of times on failure... */
+ ret = -EREMOTEIO;
+ for (retries = 0; retries < 32; retries++) {
@@ -1113,10 +1122,21 @@ index 7beb82a..de5efe7 100644
+ nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
+ if (retries)
+ udelay(400);
-+
+
+- tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
+- tmp &= ~NV50_SOR_DP_CTRL_TRAINING_PATTERN;
+- tmp |= (pattern << 24);
+- nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp);
+ /* transaction request, wait up to 1ms for it to complete */
+ nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl);
-+
+
+- ret = auxch_rd(encoder, DP_TRAINING_PATTERN_SET, &cmd, 1);
+- if (ret)
+- return ret;
+- cmd &= ~DP_TRAINING_PATTERN_MASK;
+- cmd |= (pattern & DP_TRAINING_PATTERN_MASK);
+- return auxch_wr(encoder, DP_TRAINING_PATTERN_SET, &cmd, 1);
+-}
+ timeout = 1000;
+ do {
+ ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
@@ -1127,8 +1147,14 @@ index 7beb82a..de5efe7 100644
+ }
+ } while (ctrl & 0x00010000);
-- return auxch_wr(encoder, DP_LINK_BW_SET, &cmd, 1);
--}
+-static int
+-nouveau_dp_max_voltage_swing(struct drm_encoder *encoder)
+-{
+- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+- struct drm_device *dev = encoder->dev;
+- struct bit_displayport_encoder_table_entry *dpse;
+- struct bit_displayport_encoder_table *dpe;
+- int i, dpe_headerlen, max_vs = 0;
+ /* read status, and check if transaction completed ok */
+ stat = nv_mask(dev, 0x00e4e8 + (ch * 0x50), 0, 0);
+ if (!(stat & 0x000f0f00)) {
@@ -1136,43 +1162,32 @@ index 7beb82a..de5efe7 100644
+ break;
+ }
--static int
--nouveau_dp_link_train_set(struct drm_encoder *encoder, int pattern)
--{
-- struct drm_device *dev = encoder->dev;
-- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-- uint32_t tmp;
-- uint8_t cmd;
-- int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1);
-- int ret;
+- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
+- if (!dpe)
+- return false;
+- dpse = (void *)((char *)dpe + dpe_headerlen);
+ AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
+ }
-- tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
-- tmp &= ~NV50_SOR_DP_CTRL_TRAINING_PATTERN;
-- tmp |= (pattern << 24);
-- nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp);
+- for (i = 0; i < dpe_headerlen; i++, dpse++) {
+- if (dpse->vs_level > max_vs)
+- max_vs = dpse->vs_level;
+ if (type & 1) {
+ for (i = 0; i < 16; i += 4) {
+ xbuf[i / 4] = nv_rd32(dev, 0x00e4d0 + (ch * 0x50) + i);
+ AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
+ }
+ memcpy(data, xbuf, size);
-+ }
+ }
-- ret = auxch_rd(encoder, DP_TRAINING_PATTERN_SET, &cmd, 1);
-- if (ret)
-- return ret;
-- cmd &= ~DP_TRAINING_PATTERN_MASK;
-- cmd |= (pattern & DP_TRAINING_PATTERN_MASK);
-- return auxch_wr(encoder, DP_TRAINING_PATTERN_SET, &cmd, 1);
+- return max_vs;
+out:
+ auxch_fini(dev, ch);
+ return ret;
}
-static int
--nouveau_dp_max_voltage_swing(struct drm_encoder *encoder)
+-nouveau_dp_max_pre_emphasis(struct drm_encoder *encoder, int vs)
+static u32
+dp_link_bw_get(struct drm_device *dev, int or, int link)
{
@@ -1180,21 +1195,24 @@ index 7beb82a..de5efe7 100644
- struct drm_device *dev = encoder->dev;
- struct bit_displayport_encoder_table_entry *dpse;
- struct bit_displayport_encoder_table *dpe;
-- int i, dpe_headerlen, max_vs = 0;
+- int i, dpe_headerlen, max_pre = 0;
-
- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
- if (!dpe)
- return false;
- dpse = (void *)((char *)dpe + dpe_headerlen);
+-
+- for (i = 0; i < dpe_headerlen; i++, dpse++) {
+- if (dpse->vs_level != vs)
+- continue;
+ u32 ctrl = nv_rd32(dev, 0x614300 + (or * 0x800));
+ if (!(ctrl & 0x000c0000))
+ return 162000;
+ return 270000;
+}
-- for (i = 0; i < dpe_headerlen; i++, dpse++) {
-- if (dpse->vs_level > max_vs)
-- max_vs = dpse->vs_level;
+- if (dpse->pre_level > max_pre)
+- max_pre = dpse->pre_level;
+static int
+dp_lane_count_get(struct drm_device *dev, int or, int link)
+{
@@ -1206,40 +1224,52 @@ index 7beb82a..de5efe7 100644
+ return 4;
}
-
-- return max_vs;
+- return max_pre;
}
--static int
--nouveau_dp_max_pre_emphasis(struct drm_encoder *encoder, int vs)
+-static bool
+-nouveau_dp_link_train_adjust(struct drm_encoder *encoder, uint8_t *config)
+void
+nouveau_dp_tu_update(struct drm_device *dev, int or, int link, u32 clk, u32 bpp)
{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct drm_device *dev = encoder->dev;
-- struct bit_displayport_encoder_table_entry *dpse;
- struct bit_displayport_encoder_table *dpe;
-- int i, dpe_headerlen, max_pre = 0;
+- int ret, i, dpe_headerlen, vs = 0, pre = 0;
+- uint8_t request[2];
+ const u32 symbol = 100000;
+ int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
+ int TU, VTUi, VTUf, VTUa;
+ u64 link_data_rate, link_ratio, unk;
+ u32 best_diff = 64 * symbol;
+ u32 link_nr, link_bw, r;
-+
+
+- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
+- if (!dpe)
+- return false;
+ /* calculate packed data rate for each lane */
+ link_nr = dp_lane_count_get(dev, or, link);
+ link_data_rate = (clk * bpp / 8) / link_nr;
-+
+
+- ret = auxch_rd(encoder, DP_ADJUST_REQUEST_LANE0_1, request, 2);
+- if (ret)
+- return false;
+ /* calculate ratio of packed data rate to link symbol rate */
+ link_bw = dp_link_bw_get(dev, or, link);
+ link_ratio = link_data_rate * symbol;
+ r = do_div(link_ratio, link_bw);
-+
+
+- NV_DEBUG_KMS(dev, "\t\tadjust 0x%02x 0x%02x\n", request[0], request[1]);
+ for (TU = 64; TU >= 32; TU--) {
+ /* calculate average number of valid symbols in each TU */
+ u32 tu_valid = link_ratio * TU;
+ u32 calc, diff;
-+
+
+- /* Keep all lanes at the same level.. */
+- for (i = 0; i < nv_encoder->dp.link_nr; i++) {
+- int lane_req = (request[i >> 1] >> ((i & 1) << 2)) & 0xf;
+- int lane_vs = lane_req & 3;
+- int lane_pre = (lane_req >> 2) & 3;
+ /* find a hw representation for the fraction.. */
+ VTUi = tu_valid / symbol;
+ calc = VTUi * symbol;
@@ -1249,7 +1279,12 @@ index 7beb82a..de5efe7 100644
+ VTUf = symbol / (symbol - diff);
+ if (symbol - (VTUf * diff))
+ VTUf++;
-+
+
+- if (lane_vs > vs)
+- vs = lane_vs;
+- if (lane_pre > pre)
+- pre = lane_pre;
+- }
+ if (VTUf <= 15) {
+ VTUa = 1;
+ calc += symbol - (symbol / VTUf);
@@ -1264,10 +1299,9 @@ index 7beb82a..de5efe7 100644
+ calc += symbol / VTUf;
+ }
-- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
-- if (!dpe)
-- return false;
-- dpse = (void *)((char *)dpe + dpe_headerlen);
+- if (vs >= nouveau_dp_max_voltage_swing(encoder)) {
+- vs = nouveau_dp_max_voltage_swing(encoder);
+- vs |= 4;
+ diff = calc - tu_valid;
+ } else {
+ /* no remainder, but the hw doesn't like the fractional
@@ -1278,10 +1312,7 @@ index 7beb82a..de5efe7 100644
+ VTUf = 1;
+ VTUi--;
+ }
-
-- for (i = 0; i < dpe_headerlen; i++, dpse++) {
-- if (dpse->vs_level != vs)
-- continue;
++
+ if (diff < best_diff) {
+ best_diff = diff;
+ bestTU = TU;
@@ -1291,23 +1322,27 @@ index 7beb82a..de5efe7 100644
+ if (diff == 0)
+ break;
+ }
-+ }
+ }
-- if (dpse->pre_level > max_pre)
-- max_pre = dpse->pre_level;
+- if (pre >= nouveau_dp_max_pre_emphasis(encoder, vs & 3)) {
+- pre = nouveau_dp_max_pre_emphasis(encoder, vs & 3);
+- pre |= 4;
+ if (!bestTU) {
+ NV_ERROR(dev, "DP: unable to find suitable config\n");
+ return;
}
-- return max_pre;
+- /* Update the configuration for all lanes.. */
+- for (i = 0; i < nv_encoder->dp.link_nr; i++)
+- config[i] = (pre << 3) | vs;
+ /* XXX close to vbios numbers, but not right */
+ unk = (symbol - link_ratio) * bestTU;
+ unk *= link_ratio;
+ r = do_div(unk, symbol);
+ r = do_div(unk, symbol);
+ unk += 6;
-+
+
+- return true;
+ nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x000001fc, bestTU << 2);
+ nv_mask(dev, NV50_SOR_DP_SCFG(or, link), 0x010f7f3f, bestVTUa << 24 |
+ bestVTUf << 16 |
@@ -1316,63 +1351,63 @@ index 7beb82a..de5efe7 100644
}
-static bool
--nouveau_dp_link_train_adjust(struct drm_encoder *encoder, uint8_t *config)
+-nouveau_dp_link_train_commit(struct drm_encoder *encoder, uint8_t *config)
+u8 *
+nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry)
{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct drm_device *dev = encoder->dev;
+- struct bit_displayport_encoder_table_entry *dpse;
- struct bit_displayport_encoder_table *dpe;
-- int ret, i, dpe_headerlen, vs = 0, pre = 0;
-- uint8_t request[2];
+- int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1);
+- int dpe_headerlen, ret, i;
-
+- NV_DEBUG_KMS(dev, "\t\tconfig 0x%02x 0x%02x 0x%02x 0x%02x\n",
+- config[0], config[1], config[2], config[3]);
++ struct drm_nouveau_private *dev_priv = dev->dev_private;
++ struct nvbios *bios = &dev_priv->vbios;
++ struct bit_entry d;
++ u8 *table;
++ int i;
+
- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
- if (!dpe)
- return false;
--
-- ret = auxch_rd(encoder, DP_ADJUST_REQUEST_LANE0_1, request, 2);
-- if (ret)
-- return false;
--
-- NV_DEBUG_KMS(dev, "\t\tadjust 0x%02x 0x%02x\n", request[0], request[1]);
--
-- /* Keep all lanes at the same level.. */
-- for (i = 0; i < nv_encoder->dp.link_nr; i++) {
-- int lane_req = (request[i >> 1] >> ((i & 1) << 2)) & 0xf;
-- int lane_vs = lane_req & 3;
-- int lane_pre = (lane_req >> 2) & 3;
-+ struct drm_nouveau_private *dev_priv = dev->dev_private;
-+ struct nvbios *bios = &dev_priv->vbios;
-+ struct bit_entry d;
-+ u8 *table;
-+ int i;
-+
+- dpse = (void *)((char *)dpe + dpe_headerlen);
+ if (bit_table(dev, 'd', &d)) {
+ NV_ERROR(dev, "BIT 'd' table not found\n");
+ return NULL;
+ }
-- if (lane_vs > vs)
-- vs = lane_vs;
-- if (lane_pre > pre)
-- pre = lane_pre;
+- for (i = 0; i < dpe->record_nr; i++, dpse++) {
+- if (dpse->vs_level == (config[0] & 3) &&
+- dpse->pre_level == ((config[0] >> 3) & 3))
+- break;
+ if (d.version != 1) {
+ NV_ERROR(dev, "BIT 'd' table version %d unknown\n", d.version);
+ return NULL;
}
+- BUG_ON(i == dpe->record_nr);
-- if (vs >= nouveau_dp_max_voltage_swing(encoder)) {
-- vs = nouveau_dp_max_voltage_swing(encoder);
-- vs |= 4;
+- for (i = 0; i < nv_encoder->dp.link_nr; i++) {
+- const int shift[4] = { 16, 8, 0, 24 };
+- uint32_t mask = 0xff << shift[i];
+- uint32_t reg0, reg1, reg2;
+ table = ROMPTR(bios, d.data[0]);
+ if (!table) {
+ NV_ERROR(dev, "displayport table pointer invalid\n");
+ return NULL;
- }
++ }
-- if (pre >= nouveau_dp_max_pre_emphasis(encoder, vs & 3)) {
-- pre = nouveau_dp_max_pre_emphasis(encoder, vs & 3);
-- pre |= 4;
+- reg0 = nv_rd32(dev, NV50_SOR_DP_UNK118(or, link)) & ~mask;
+- reg0 |= (dpse->reg0 << shift[i]);
+- reg1 = nv_rd32(dev, NV50_SOR_DP_UNK120(or, link)) & ~mask;
+- reg1 |= (dpse->reg1 << shift[i]);
+- reg2 = nv_rd32(dev, NV50_SOR_DP_UNK130(or, link)) & 0xffff00ff;
+- reg2 |= (dpse->reg2 << 8);
+- nv_wr32(dev, NV50_SOR_DP_UNK118(or, link), reg0);
+- nv_wr32(dev, NV50_SOR_DP_UNK120(or, link), reg1);
+- nv_wr32(dev, NV50_SOR_DP_UNK130(or, link), reg2);
+ switch (table[0]) {
+ case 0x20:
+ case 0x21:
@@ -1383,9 +1418,9 @@ index 7beb82a..de5efe7 100644
+ return NULL;
}
-- /* Update the configuration for all lanes.. */
-- for (i = 0; i < nv_encoder->dp.link_nr; i++)
-- config[i] = (pre << 3) | vs;
+- ret = auxch_wr(encoder, DP_TRAINING_LANE0_SET, config, 4);
+- if (ret)
+- return false;
+ for (i = 0; i < table[3]; i++) {
+ *entry = ROMPTR(bios, table[table[1] + (i * table[2])]);
+ if (*entry && bios_encoder_match(dcb, ROM32((*entry)[0])))
@@ -1397,15 +1432,8 @@ index 7beb82a..de5efe7 100644
+ return NULL;
}
--static bool
--nouveau_dp_link_train_commit(struct drm_encoder *encoder, uint8_t *config)
--{
-- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-- struct drm_device *dev = encoder->dev;
-- struct bit_displayport_encoder_table_entry *dpse;
-- struct bit_displayport_encoder_table *dpe;
-- int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1);
-- int dpe_headerlen, ret, i;
+-bool
+-nouveau_dp_link_train(struct drm_encoder *encoder)
+/******************************************************************************
+ * link training
+ *****************************************************************************/
@@ -1423,20 +1451,36 @@ index 7beb82a..de5efe7 100644
+ u8 stat[6];
+ u8 conf[4];
+};
-
-- NV_DEBUG_KMS(dev, "\t\tconfig 0x%02x 0x%02x 0x%02x 0x%02x\n",
-- config[0], config[1], config[2], config[3]);
++
+static void
+dp_set_link_config(struct drm_device *dev, struct dp_state *dp)
-+{
-+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ {
+- struct drm_device *dev = encoder->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+- struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
+- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+- struct nouveau_connector *nv_connector;
+- struct bit_displayport_encoder_table *dpe;
+- int dpe_headerlen;
+- uint8_t config[4], status[3];
+- bool cr_done, cr_max_vs, eq_done, hpd_state;
+- int ret = 0, i, tries, voltage;
+ int or = dp->or, link = dp->link;
+ u8 *entry, sink[2];
+ u32 dp_ctrl;
+ u16 script;
-+
+
+- NV_DEBUG_KMS(dev, "link training!!\n");
+ NV_DEBUG_KMS(dev, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
-+
+
+- nv_connector = nouveau_encoder_connector_get(nv_encoder);
+- if (!nv_connector)
+- return false;
+-
+- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
+- if (!dpe) {
+- NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or);
+- return false;
+ /* set selected link rate on source */
+ switch (dp->link_bw) {
+ case 270000:
@@ -1447,16 +1491,15 @@ index 7beb82a..de5efe7 100644
+ nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00000000);
+ sink[0] = DP_LINK_BW_1_62;
+ break;
-+ }
+ }
-- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
-- if (!dpe)
-- return false;
-- dpse = (void *)((char *)dpe + dpe_headerlen);
+- /* disable hotplug detect, this flips around on some panels during
+- * link training.
+ /* offset +0x0a of each dp encoder table entry is a pointer to another
+ * table, that has (among other things) pointers to more scripts that
+ * need to be executed, this time depending on link speed.
-+ */
+ */
+- hpd_state = pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false);
+ entry = ROMPTR(&dev_priv->vbios, dp->entry[10]);
+ if (entry) {
+ if (dp->table[0] < 0x30) {
@@ -1469,90 +1512,77 @@ index 7beb82a..de5efe7 100644
+ script = ROM16(entry[1]);
+ }
-- for (i = 0; i < dpe->record_nr; i++, dpse++) {
-- if (dpse->vs_level == (config[0] & 3) &&
-- dpse->pre_level == ((config[0] >> 3) & 3))
-- break;
+- if (dpe->script0) {
+- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
+- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0),
+- nv_encoder->dcb);
+ nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
}
-- BUG_ON(i == dpe->record_nr);
--
-- for (i = 0; i < nv_encoder->dp.link_nr; i++) {
-- const int shift[4] = { 16, 8, 0, 24 };
-- uint32_t mask = 0xff << shift[i];
-- uint32_t reg0, reg1, reg2;
--
-- reg0 = nv_rd32(dev, NV50_SOR_DP_UNK118(or, link)) & ~mask;
-- reg0 |= (dpse->reg0 << shift[i]);
-- reg1 = nv_rd32(dev, NV50_SOR_DP_UNK120(or, link)) & ~mask;
-- reg1 |= (dpse->reg1 << shift[i]);
-- reg2 = nv_rd32(dev, NV50_SOR_DP_UNK130(or, link)) & 0xffff00ff;
-- reg2 |= (dpse->reg2 << 8);
-- nv_wr32(dev, NV50_SOR_DP_UNK118(or, link), reg0);
-- nv_wr32(dev, NV50_SOR_DP_UNK120(or, link), reg1);
-- nv_wr32(dev, NV50_SOR_DP_UNK130(or, link), reg2);
-+
+
+-train:
+- cr_done = eq_done = false;
+ /* configure lane count on the source */
+ dp_ctrl = ((1 << dp->link_nr) - 1) << 16;
+ sink[1] = dp->link_nr;
+ if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP) {
+ dp_ctrl |= 0x00004000;
+ sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
- }
++ }
-- ret = auxch_wr(encoder, DP_TRAINING_LANE0_SET, config, 4);
-- if (ret)
-- return false;
+- /* set link configuration */
+- NV_DEBUG_KMS(dev, "\tbegin train: bw %d, lanes %d\n",
+- nv_encoder->dp.link_bw, nv_encoder->dp.link_nr);
+ nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x001f4000, dp_ctrl);
-- return true;
+- ret = nouveau_dp_link_bw_set(encoder, nv_encoder->dp.link_bw);
+- if (ret)
+- return false;
+ /* inform the sink of the new configuration */
+ auxch_tx(dev, dp->auxch, 8, DP_LINK_BW_SET, sink, 2);
- }
++}
--bool
--nouveau_dp_link_train(struct drm_encoder *encoder)
+- config[0] = nv_encoder->dp.link_nr;
+- if (nv_encoder->dp.dpcd_version >= 0x11 &&
+- nv_encoder->dp.enhanced_frame)
+- config[0] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+static void
+dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 tp)
- {
-- struct drm_device *dev = encoder->dev;
-- struct drm_nouveau_private *dev_priv = dev->dev_private;
-- struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
-- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-- struct nouveau_connector *nv_connector;
-- struct bit_displayport_encoder_table *dpe;
-- int dpe_headerlen;
-- uint8_t config[4], status[3];
-- bool cr_done, cr_max_vs, eq_done, hpd_state;
-- int ret = 0, i, tries, voltage;
++{
+ u8 sink_tp;
-- NV_DEBUG_KMS(dev, "link training!!\n");
+- ret = nouveau_dp_lane_count_set(encoder, config[0]);
+- if (ret)
+- return false;
+ NV_DEBUG_KMS(dev, "training pattern %d\n", tp);
-- nv_connector = nouveau_encoder_connector_get(nv_encoder);
-- if (!nv_connector)
-- return false;
+- /* clock recovery */
+- NV_DEBUG_KMS(dev, "\tbegin cr\n");
+- ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_1);
+- if (ret)
+- goto stop;
+ nv_mask(dev, NV50_SOR_DP_CTRL(dp->or, dp->link), 0x0f000000, tp << 24);
-- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
-- if (!dpe) {
-- NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or);
-- return false;
-- }
+- tries = 0;
+- voltage = -1;
+- memset(config, 0x00, sizeof(config));
+- for (;;) {
+- if (!nouveau_dp_link_train_commit(encoder, config))
+- break;
+ auxch_tx(dev, dp->auxch, 9, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
+ sink_tp &= ~DP_TRAINING_PATTERN_MASK;
+ sink_tp |= tp;
+ auxch_tx(dev, dp->auxch, 8, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
+}
-- /* disable hotplug detect, this flips around on some panels during
-- * link training.
-- */
-- hpd_state = pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false);
+- udelay(100);
+static const u8 nv50_lane_map[] = { 16, 8, 0, 24 };
+static const u8 nvaf_lane_map[] = { 24, 16, 8, 0 };
-+
+
+- ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 2);
+- if (ret)
+- break;
+- NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n",
+- status[0], status[1]);
+static int
+dp_link_train_commit(struct drm_device *dev, struct dp_state *dp)
+{
@@ -1562,12 +1592,21 @@ index 7beb82a..de5efe7 100644
+ int link = dp->link;
+ int or = dp->or;
+ int i;
-+
+
+- cr_done = true;
+- cr_max_vs = false;
+- for (i = 0; i < nv_encoder->dp.link_nr; i++) {
+- int lane = (status[i >> 1] >> ((i & 1) * 4)) & 0xf;
+ if (dev_priv->chipset != 0xaf)
+ shifts = nv50_lane_map;
+ else
+ shifts = nvaf_lane_map;
-+
+
+- if (!(lane & DP_LANE_CR_DONE)) {
+- cr_done = false;
+- if (config[i] & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED)
+- cr_max_vs = true;
+- break;
+ for (i = 0; i < dp->link_nr; i++) {
+ u8 *conf = dp->entry + dp->table[4];
+ u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
@@ -1591,8 +1630,13 @@ index 7beb82a..de5efe7 100644
+ conf += dp->table[5];
+ if (conf >= last)
+ return -EINVAL;
-+ }
-+
+ }
+- }
+
+- if ((config[0] & DP_TRAIN_VOLTAGE_SWING_MASK) != voltage) {
+- voltage = config[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+- tries = 0;
+- }
+ conf += 2;
+ } else {
+ /* no lookup table anymore, set entries for each
@@ -1605,69 +1649,57 @@ index 7beb82a..de5efe7 100644
+ case 2: lpre += 7; break;
+ case 3: lpre += 9; break;
+ }
-+
+
+- if (cr_done || cr_max_vs || (++tries == 5))
+- break;
+ conf = conf + (lpre * dp->table[5]);
+ conf++;
+ }
-- if (dpe->script0) {
-- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
-- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0),
-- nv_encoder->dcb);
+- if (!nouveau_dp_link_train_adjust(encoder, config))
+- break;
+ drv |= conf[0] << shifts[i];
+ pre |= conf[1] << shifts[i];
+ unk = (unk & ~0x0000ff00) | (conf[2] << 8);
}
--train:
-- cr_done = eq_done = false;
+- if (!cr_done)
+- goto stop;
+ nv_mask(dev, NV50_SOR_DP_UNK118(or, link), mask, drv);
+ nv_mask(dev, NV50_SOR_DP_UNK120(or, link), mask, pre);
+ nv_mask(dev, NV50_SOR_DP_UNK130(or, link), 0x0000ff0f, unk);
-
-- /* set link configuration */
-- NV_DEBUG_KMS(dev, "\tbegin train: bw %d, lanes %d\n",
-- nv_encoder->dp.link_bw, nv_encoder->dp.link_nr);
++
+ return auxch_tx(dev, dp->auxch, 8, DP_TRAINING_LANE0_SET, dp->conf, 4);
+}
-
-- ret = nouveau_dp_link_bw_set(encoder, nv_encoder->dp.link_bw);
-- if (ret)
-- return false;
++
+static int
+dp_link_train_update(struct drm_device *dev, struct dp_state *dp, u32 delay)
+{
+ int ret;
-
-- config[0] = nv_encoder->dp.link_nr;
-- if (nv_encoder->dp.dpcd_version >= 0x11 &&
-- nv_encoder->dp.enhanced_frame)
-- config[0] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
++
+ udelay(delay);
-- ret = nouveau_dp_lane_count_set(encoder, config[0]);
+- /* channel equalisation */
+- NV_DEBUG_KMS(dev, "\tbegin eq\n");
+- ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_2);
+ ret = auxch_tx(dev, dp->auxch, 9, DP_LANE0_1_STATUS, dp->stat, 6);
if (ret)
-- return false;
+- goto stop;
+ return ret;
-- /* clock recovery */
-- NV_DEBUG_KMS(dev, "\tbegin cr\n");
-- ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_1);
-- if (ret)
-- goto stop;
+- for (tries = 0; tries <= 5; tries++) {
+- udelay(400);
+ NV_DEBUG_KMS(dev, "status %02x %02x %02x %02x %02x %02x\n",
+ dp->stat[0], dp->stat[1], dp->stat[2], dp->stat[3],
+ dp->stat[4], dp->stat[5]);
+ return 0;
+}
-- tries = 0;
-- voltage = -1;
-- memset(config, 0x00, sizeof(config));
-- for (;;) {
-- if (!nouveau_dp_link_train_commit(encoder, config))
+- ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 3);
+- if (ret)
- break;
+- NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n",
+- status[0], status[1]);
+static int
+dp_link_train_cr(struct drm_device *dev, struct dp_state *dp)
+{
@@ -1675,136 +1707,61 @@ index 7beb82a..de5efe7 100644
+ int voltage = dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+ int tries = 0, i;
-- udelay(100);
+- eq_done = true;
+- if (!(status[2] & DP_INTERLANE_ALIGN_DONE))
+- eq_done = false;
+ dp_set_training_pattern(dev, dp, DP_TRAINING_PATTERN_1);
-- ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 2);
-- if (ret)
+- for (i = 0; eq_done && i < nv_encoder->dp.link_nr; i++) {
+- int lane = (status[i >> 1] >> ((i & 1) * 4)) & 0xf;
+ do {
+ if (dp_link_train_commit(dev, dp) ||
+ dp_link_train_update(dev, dp, 100))
- break;
-- NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n",
-- status[0], status[1]);
++ break;
- cr_done = true;
-- cr_max_vs = false;
-- for (i = 0; i < nv_encoder->dp.link_nr; i++) {
-- int lane = (status[i >> 1] >> ((i & 1) * 4)) & 0xf;
--
++ cr_done = true;
+ for (i = 0; i < dp->link_nr; i++) {
+ u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
if (!(lane & DP_LANE_CR_DONE)) {
cr_done = false;
-- if (config[i] & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED)
-- cr_max_vs = true;
+ if (dp->conf[i] & DP_TRAIN_MAX_SWING_REACHED)
+ abort = true;
break;
}
- }
++ }
-- if ((config[0] & DP_TRAIN_VOLTAGE_SWING_MASK) != voltage) {
-- voltage = config[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+- if (!(lane & DP_LANE_CHANNEL_EQ_DONE) ||
+- !(lane & DP_LANE_SYMBOL_LOCKED)) {
+- eq_done = false;
+- break;
+- }
+ if ((dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK) != voltage) {
+ voltage = dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
- tries = 0;
++ tries = 0;
}
+ } while (!cr_done && !abort && ++tries < 5);
-- if (cr_done || cr_max_vs || (++tries == 5))
-- break;
--
-- if (!nouveau_dp_link_train_adjust(encoder, config))
+- if (eq_done || !cr_done)
- break;
-- }
--
-- if (!cr_done)
-- goto stop;
+ return cr_done ? 0 : -1;
+}
-- /* channel equalisation */
-- NV_DEBUG_KMS(dev, "\tbegin eq\n");
-- ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_2);
-- if (ret)
-- goto stop;
+- if (!nouveau_dp_link_train_adjust(encoder, config) ||
+- !nouveau_dp_link_train_commit(encoder, config))
+- break;
+- }
+static int
+dp_link_train_eq(struct drm_device *dev, struct dp_state *dp)
+{
+ bool eq_done, cr_done = true;
+ int tries = 0, i;
-- for (tries = 0; tries <= 5; tries++) {
-- udelay(400);
-+ dp_set_training_pattern(dev, dp, DP_TRAINING_PATTERN_2);
-
-- ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 3);
-- if (ret)
-+ do {
-+ if (dp_link_train_update(dev, dp, 400))
- break;
-- NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n",
-- status[0], status[1]);
-
-- eq_done = true;
-- if (!(status[2] & DP_INTERLANE_ALIGN_DONE))
-- eq_done = false;
--
-- for (i = 0; eq_done && i < nv_encoder->dp.link_nr; i++) {
-- int lane = (status[i >> 1] >> ((i & 1) * 4)) & 0xf;
--
-- if (!(lane & DP_LANE_CR_DONE)) {
-+ eq_done = !!(dp->stat[2] & DP_INTERLANE_ALIGN_DONE);
-+ for (i = 0; i < dp->link_nr && eq_done; i++) {
-+ u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
-+ if (!(lane & DP_LANE_CR_DONE))
- cr_done = false;
-- break;
-- }
--
- if (!(lane & DP_LANE_CHANNEL_EQ_DONE) ||
-- !(lane & DP_LANE_SYMBOL_LOCKED)) {
-+ !(lane & DP_LANE_SYMBOL_LOCKED))
- eq_done = false;
-- break;
-- }
- }
-
-- if (eq_done || !cr_done)
-+ if (dp_link_train_commit(dev, dp))
- break;
-+ } while (!eq_done && cr_done && ++tries <= 5);
-
-- if (!nouveau_dp_link_train_adjust(encoder, config) ||
-- !nouveau_dp_link_train_commit(encoder, config))
-- break;
-- }
-+ return eq_done ? 0 : -1;
-+}
-
-stop:
- /* end link training */
- ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_DISABLE);
- if (ret)
-+bool
-+nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
-+{
-+ struct drm_nouveau_private *dev_priv = encoder->dev->dev_private;
-+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
-+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-+ struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
-+ struct nouveau_connector *nv_connector =
-+ nouveau_encoder_connector_get(nv_encoder);
-+ struct drm_device *dev = encoder->dev;
-+ struct nouveau_i2c_chan *auxch;
-+ const u32 bw_list[] = { 270000, 162000, 0 };
-+ const u32 *link_bw = bw_list;
-+ struct dp_state dp;
-+
-+ auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
-+ if (!auxch)
- return false;
+- return false;
++ dp_set_training_pattern(dev, dp, DP_TRAINING_PATTERN_2);
- /* retry at a lower setting, if possible */
- if (!ret && !(eq_done && cr_done)) {
@@ -1814,90 +1771,53 @@ index 7beb82a..de5efe7 100644
- nv_encoder->dp.link_bw = DP_LINK_BW_1_62;
- goto train;
- }
-+ dp.table = nouveau_dp_bios_data(dev, nv_encoder->dcb, &dp.entry);
-+ if (!dp.table)
-+ return -EINVAL;
-+
-+ dp.dcb = nv_encoder->dcb;
-+ dp.crtc = nv_crtc->index;
-+ dp.auxch = auxch->rd;
-+ dp.or = nv_encoder->or;
-+ dp.link = !(nv_encoder->dcb->sorconf.link & 1);
-+ dp.dpcd = nv_encoder->dp.dpcd;
-+
-+ /* some sinks toggle hotplug in response to some of the actions
-+ * we take during link training (DP_SET_POWER is one), we need
-+ * to ignore them for the moment to avoid races.
-+ */
-+ pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false);
-+
-+ /* enable down-spreading, if possible */
-+ if (dp.table[1] >= 16) {
-+ u16 script = ROM16(dp.entry[14]);
-+ if (nv_encoder->dp.dpcd[3] & 1)
-+ script = ROM16(dp.entry[12]);
-+
-+ nouveau_bios_run_init_table(dev, script, dp.dcb, dp.crtc);
- }
-
-- if (dpe->script1) {
-- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
-- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1),
-- nv_encoder->dcb);
-+ /* execute pre-train script from vbios */
-+ nouveau_bios_run_init_table(dev, ROM16(dp.entry[6]), dp.dcb, dp.crtc);
-+
-+ /* start off at highest link rate supported by encoder and display */
-+ while (*link_bw > nv_encoder->dp.link_bw)
-+ link_bw++;
-+
-+ while (link_bw[0]) {
-+ /* find minimum required lane count at this link rate */
-+ dp.link_nr = nv_encoder->dp.link_nr;
-+ while ((dp.link_nr >> 1) * link_bw[0] > datarate)
-+ dp.link_nr >>= 1;
-+
-+ /* drop link rate to minimum with this lane count */
-+ while ((link_bw[1] * dp.link_nr) > datarate)
-+ link_bw++;
-+ dp.link_bw = link_bw[0];
-+
-+ /* program selected link configuration */
-+ dp_set_link_config(dev, &dp);
-+
-+ /* attempt to train the link at this configuration */
-+ memset(dp.stat, 0x00, sizeof(dp.stat));
-+ if (!dp_link_train_cr(dev, &dp) &&
-+ !dp_link_train_eq(dev, &dp))
-+ break;
-+
-+ /* retry at lower rate */
-+ link_bw++;
- }
+- }
++ do {
++ if (dp_link_train_update(dev, dp, 400))
++ break;
+
+- if (dpe->script1) {
+- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
+- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1),
+- nv_encoder->dcb);
+- }
++ eq_done = !!(dp->stat[2] & DP_INTERLANE_ALIGN_DONE);
++ for (i = 0; i < dp->link_nr && eq_done; i++) {
++ u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
++ if (!(lane & DP_LANE_CR_DONE))
++ cr_done = false;
++ if (!(lane & DP_LANE_CHANNEL_EQ_DONE) ||
++ !(lane & DP_LANE_SYMBOL_LOCKED))
++ eq_done = false;
++ }
- /* re-enable hotplug detect */
- pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, hpd_state);
-+ /* finish link training */
-+ dp_set_training_pattern(dev, &dp, DP_TRAINING_PATTERN_DISABLE);
++ if (dp_link_train_commit(dev, dp))
++ break;
++ } while (!eq_done && cr_done && ++tries <= 5);
- return eq_done;
-+ /* execute post-train script from vbios */
-+ nouveau_bios_run_init_table(dev, ROM16(dp.entry[8]), dp.dcb, dp.crtc);
-+
-+ /* re-enable hotplug detect */
-+ pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true);
-+ return true;
++ return eq_done ? 0 : -1;
}
bool
-@@ -447,31 +648,34 @@ nouveau_dp_detect(struct drm_encoder *encoder)
+-nouveau_dp_detect(struct drm_encoder *encoder)
++nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
{
++ struct drm_nouveau_private *dev_priv = encoder->dev->dev_private;
++ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
++ struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
++ struct nouveau_connector *nv_connector =
++ nouveau_encoder_connector_get(nv_encoder);
struct drm_device *dev = encoder->dev;
- uint8_t dpcd[4];
+- int ret;
+ struct nouveau_i2c_chan *auxch;
-+ u8 *dpcd = nv_encoder->dp.dpcd;
- int ret;
++ const u32 bw_list[] = { 270000, 162000, 0 };
++ const u32 *link_bw = bw_list;
++ struct dp_state dp;
- ret = auxch_rd(encoder, 0x0000, dpcd, 4);
- if (ret)
@@ -1910,47 +1830,64 @@ index 7beb82a..de5efe7 100644
- nv_encoder->dcb->dpconf.link_bw,
- nv_encoder->dcb->dpconf.link_nr,
- dpcd[1], dpcd[2] & 0x0f, dpcd[0]);
-+ ret = auxch_tx(dev, auxch->rd, 9, DP_DPCD_REV, dpcd, 8);
-+ if (ret)
-+ return false;
++ dp.table = nouveau_dp_bios_data(dev, nv_encoder->dcb, &dp.entry);
++ if (!dp.table)
++ return -EINVAL;
- nv_encoder->dp.dpcd_version = dpcd[0];
-+ nv_encoder->dp.link_bw = 27000 * dpcd[1];
-+ nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK;
++ dp.dcb = nv_encoder->dcb;
++ dp.crtc = nv_crtc->index;
++ dp.auxch = auxch->rd;
++ dp.or = nv_encoder->or;
++ dp.link = !(nv_encoder->dcb->sorconf.link & 1);
++ dp.dpcd = nv_encoder->dp.dpcd;
- nv_encoder->dp.link_bw = dpcd[1];
- if (nv_encoder->dp.link_bw != DP_LINK_BW_1_62 &&
- !nv_encoder->dcb->dpconf.link_bw)
- nv_encoder->dp.link_bw = DP_LINK_BW_1_62;
-+ NV_DEBUG_KMS(dev, "display: %dx%d dpcd 0x%02x\n",
-+ nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, dpcd[0]);
-+ NV_DEBUG_KMS(dev, "encoder: %dx%d\n",
-+ nv_encoder->dcb->dpconf.link_nr,
-+ nv_encoder->dcb->dpconf.link_bw);
++ /* some sinks toggle hotplug in response to some of the actions
++ * we take during link training (DP_SET_POWER is one), we need
++ * to ignore them for the moment to avoid races.
++ */
++ pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false);
- nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK;
- if (nv_encoder->dp.link_nr > nv_encoder->dcb->dpconf.link_nr)
-+ if (nv_encoder->dcb->dpconf.link_nr < nv_encoder->dp.link_nr)
- nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr;
-+ if (nv_encoder->dcb->dpconf.link_bw < nv_encoder->dp.link_bw)
-+ nv_encoder->dp.link_bw = nv_encoder->dcb->dpconf.link_bw;
+- nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr;
++ /* enable down-spreading, if possible */
++ if (dp.table[1] >= 16) {
++ u16 script = ROM16(dp.entry[14]);
++ if (nv_encoder->dp.dpcd[3] & 1)
++ script = ROM16(dp.entry[12]);
- nv_encoder->dp.enhanced_frame = (dpcd[2] & DP_ENHANCED_FRAME_CAP);
-+ NV_DEBUG_KMS(dev, "maximum: %dx%d\n",
-+ nv_encoder->dp.link_nr, nv_encoder->dp.link_bw);
++ nouveau_bios_run_init_table(dev, script, dp.dcb, dp.crtc);
++ }
- return true;
- }
-@@ -480,105 +684,13 @@ int
- nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
- uint8_t *data, int data_nr)
- {
+- return true;
+-}
++ /* execute pre-train script from vbios */
++ nouveau_bios_run_init_table(dev, ROM16(dp.entry[6]), dp.dcb, dp.crtc);
+
+-int
+-nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
+- uint8_t *data, int data_nr)
+-{
- struct drm_device *dev = auxch->dev;
- uint32_t tmp, ctrl, stat = 0, data32[4] = {};
- int ret = 0, i, index = auxch->rd;
--
++ /* start off at highest link rate supported by encoder and display */
++ while (*link_bw > nv_encoder->dp.link_bw)
++ link_bw++;
+
- NV_DEBUG_KMS(dev, "ch %d cmd %d addr 0x%x len %d\n", index, cmd, addr, data_nr);
--
++ while (link_bw[0]) {
++ /* find minimum required lane count at this link rate */
++ dp.link_nr = nv_encoder->dp.link_nr;
++ while ((dp.link_nr >> 1) * link_bw[0] > datarate)
++ dp.link_nr >>= 1;
+
- tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd));
- nv_wr32(dev, NV50_AUXCH_CTRL(auxch->rd), tmp | 0x00100000);
- tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd));
@@ -1959,19 +1896,32 @@ index 7beb82a..de5efe7 100644
- ret = -EIO;
- goto out;
- }
--
++ /* drop link rate to minimum with this lane count */
++ while ((link_bw[1] * dp.link_nr) > datarate)
++ link_bw++;
++ dp.link_bw = link_bw[0];
++
++ /* program selected link configuration */
++ dp_set_link_config(dev, &dp);
+
- for (i = 0; i < 3; i++) {
- tmp = nv_rd32(dev, NV50_AUXCH_STAT(auxch->rd));
- if (tmp & NV50_AUXCH_STAT_STATE_READY)
-- break;
++ /* attempt to train the link at this configuration */
++ memset(dp.stat, 0x00, sizeof(dp.stat));
++ if (!dp_link_train_cr(dev, &dp) &&
++ !dp_link_train_eq(dev, &dp))
+ break;
- udelay(100);
- }
--
+
- if (i == 3) {
- ret = -EBUSY;
- goto out;
-- }
--
++ /* retry at lower rate */
++ link_bw++;
+ }
+
- if (!(cmd & 1)) {
- memcpy(data32, data, data_nr);
- for (i = 0; i < 4; i++) {
@@ -1979,13 +1929,17 @@ index 7beb82a..de5efe7 100644
- nv_wr32(dev, NV50_AUXCH_DATA_OUT(index, i), data32[i]);
- }
- }
--
++ /* finish link training */
++ dp_set_training_pattern(dev, &dp, DP_TRAINING_PATTERN_DISABLE);
+
- nv_wr32(dev, NV50_AUXCH_ADDR(index), addr);
- ctrl = nv_rd32(dev, NV50_AUXCH_CTRL(index));
- ctrl &= ~(NV50_AUXCH_CTRL_CMD | NV50_AUXCH_CTRL_LEN);
- ctrl |= (cmd << NV50_AUXCH_CTRL_CMD_SHIFT);
- ctrl |= ((data_nr - 1) << NV50_AUXCH_CTRL_LEN_SHIFT);
--
++ /* execute post-train script from vbios */
++ nouveau_bios_run_init_table(dev, ROM16(dp.entry[8]), dp.dcb, dp.crtc);
+
- for (i = 0; i < 16; i++) {
- nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x80000000);
- nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl);
@@ -1997,34 +1951,64 @@ index 7beb82a..de5efe7 100644
- ret = -EBUSY;
- goto out;
- }
--
++ /* re-enable hotplug detect */
++ pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true);
++ return true;
++}
++
++bool
++nouveau_dp_detect(struct drm_encoder *encoder)
++{
++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
++ struct drm_device *dev = encoder->dev;
++ struct nouveau_i2c_chan *auxch;
++ u8 *dpcd = nv_encoder->dp.dpcd;
++ int ret;
+
- udelay(400);
--
++ auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
++ if (!auxch)
++ return false;
+
- stat = nv_rd32(dev, NV50_AUXCH_STAT(index));
- if ((stat & NV50_AUXCH_STAT_REPLY_AUX) !=
- NV50_AUXCH_STAT_REPLY_AUX_DEFER)
- break;
- }
--
++ ret = auxch_tx(dev, auxch->rd, 9, DP_DPCD_REV, dpcd, 8);
++ if (ret)
++ return false;
+
- if (i == 16) {
- NV_ERROR(dev, "auxch DEFER too many times, bailing\n");
- ret = -EREMOTEIO;
- goto out;
- }
--
++ nv_encoder->dp.link_bw = 27000 * dpcd[1];
++ nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK;
+
- if (cmd & 1) {
- if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) {
- ret = -EREMOTEIO;
- goto out;
- }
--
++ NV_DEBUG_KMS(dev, "display: %dx%d dpcd 0x%02x\n",
++ nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, dpcd[0]);
++ NV_DEBUG_KMS(dev, "encoder: %dx%d\n",
++ nv_encoder->dcb->dpconf.link_nr,
++ nv_encoder->dcb->dpconf.link_bw);
+
- for (i = 0; i < 4; i++) {
- data32[i] = nv_rd32(dev, NV50_AUXCH_DATA_IN(index, i));
- NV_DEBUG_KMS(dev, "rd %d: 0x%08x\n", i, data32[i]);
- }
- memcpy(data, data32, data_nr);
- }
--
++ if (nv_encoder->dcb->dpconf.link_nr < nv_encoder->dp.link_nr)
++ nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr;
++ if (nv_encoder->dcb->dpconf.link_bw < nv_encoder->dp.link_bw)
++ nv_encoder->dp.link_bw = nv_encoder->dcb->dpconf.link_bw;
+
-out:
- tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd));
- nv_wr32(dev, NV50_AUXCH_CTRL(auxch->rd), tmp & ~0x00100000);
@@ -2033,10 +2017,18 @@ index 7beb82a..de5efe7 100644
- NV_ERROR(dev, "expected bit 24 == 0, got 0x%08x\n", tmp);
- ret = -EIO;
- }
--
++ NV_DEBUG_KMS(dev, "maximum: %dx%d\n",
++ nv_encoder->dp.link_nr, nv_encoder->dp.link_bw);
+
- udelay(400);
--
++ return true;
++}
+
- return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY);
++int
++nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
++ uint8_t *data, int data_nr)
++{
+ return auxch_tx(auxch->dev, auxch->rd, cmd, addr, data, data_nr);
}
@@ -2165,9 +2157,6 @@ index d7d51de..29837da 100644
u32 shader;
- u32 unk05;
- u32 unk0a;
--
-- u8 voltage;
-- u8 fanspeed;
+ u32 rop;
+ u32 copy;
+ u32 daemon;
@@ -2177,7 +2166,9 @@ index d7d51de..29837da 100644
+ u32 hub01; /* nvc0- */
+ u32 hub06; /* nvc0- */
+ u32 hub07; /* nvc0- */
-+
+
+- u8 voltage;
+- u8 fanspeed;
+ u32 volt_min; /* microvolts */
+ u32 volt_max;
+ u8 fanspeed;
@@ -2410,7 +2401,7 @@ index ae69b61..e5d6e3f 100644
-
#endif /* __NOUVEAU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
-index c919cfc..81116cf 100644
+index ae22dfa..2f6daae 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -519,7 +519,7 @@ nouveau_fence_channel_init(struct nouveau_channel *chan)
@@ -2848,7 +2839,9 @@ index f9ae2fc..36bec48 100644
- /* XXX: reg_100240? */
- }
timing->id = i;
--
++ timing->WR = entry[0];
++ timing->CL = entry[2];
+
- NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
- timing->reg_100220, timing->reg_100224,
- timing->reg_100228, timing->reg_10022c);
@@ -2856,9 +2849,6 @@ index f9ae2fc..36bec48 100644
- timing->reg_100230, timing->reg_100234,
- timing->reg_100238, timing->reg_10023c);
- NV_DEBUG(dev, " 240: %08x\n", timing->reg_100240);
-+ timing->WR = entry[0];
-+ timing->CL = entry[2];
-+
+ if(dev_priv->card_type <= NV_40) {
+ nv40_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]);
+ } else if(dev_priv->card_type == NV_50){
@@ -2993,7 +2983,12 @@ index 1640dec..b29ffb3 100644
- struct nouveau_mm *rmm;
- struct nouveau_mm_node *heap;
+ struct nouveau_mm_node *node;
-+
+
+- heap = kzalloc(sizeof(*heap), GFP_KERNEL);
+- if (!heap)
+- return -ENOMEM;
+- heap->offset = roundup(offset, block);
+- heap->length = rounddown(offset + length, block) - heap->offset;
+ if (block) {
+ mutex_init(&mm->mutex);
+ INIT_LIST_HEAD(&mm->nodes);
@@ -3002,20 +2997,12 @@ index 1640dec..b29ffb3 100644
+ mm->heap_nodes = 0;
+ }
-- heap = kzalloc(sizeof(*heap), GFP_KERNEL);
-- if (!heap)
-+ node = kzalloc(sizeof(*node), GFP_KERNEL);
-+ if (!node)
- return -ENOMEM;
-- heap->offset = roundup(offset, block);
-- heap->length = rounddown(offset + length, block) - heap->offset;
-+ node->offset = roundup(offset, mm->block_size);
-+ node->length = rounddown(offset + length, mm->block_size) - node->offset;
-
- rmm = kzalloc(sizeof(*rmm), GFP_KERNEL);
- if (!rmm) {
- kfree(heap);
-- return -ENOMEM;
++ node = kzalloc(sizeof(*node), GFP_KERNEL);
++ if (!node)
+ return -ENOMEM;
- }
- rmm->block_size = block;
- mutex_init(&rmm->mutex);
@@ -3023,7 +3010,9 @@ index 1640dec..b29ffb3 100644
- INIT_LIST_HEAD(&rmm->free);
- list_add(&heap->nl_entry, &rmm->nodes);
- list_add(&heap->fl_entry, &rmm->free);
--
++ node->offset = roundup(offset, mm->block_size);
++ node->length = rounddown(offset + length, mm->block_size) - node->offset;
+
- *prmm = rmm;
+ list_add_tail(&node->nl_entry, &mm->nodes);
+ list_add_tail(&node->fl_entry, &mm->free);
@@ -3038,15 +3027,14 @@ index 1640dec..b29ffb3 100644
- struct nouveau_mm *rmm = *prmm;
struct nouveau_mm_node *node, *heap =
- list_first_entry(&rmm->nodes, struct nouveau_mm_node, nl_entry);
--
++ list_first_entry(&mm->nodes, struct nouveau_mm_node, nl_entry);
++ int nodes = 0;
+
- if (!list_is_singular(&rmm->nodes)) {
- printk(KERN_ERR "nouveau_mm not empty at destroy time!\n");
- list_for_each_entry(node, &rmm->nodes, nl_entry) {
- printk(KERN_ERR "0x%02x: 0x%08x 0x%08x\n",
- node->type, node->offset, node->length);
-+ list_first_entry(&mm->nodes, struct nouveau_mm_node, nl_entry);
-+ int nodes = 0;
-+
+ list_for_each_entry(node, &mm->nodes, nl_entry) {
+ if (nodes++ == mm->heap_nodes) {
+ printk(KERN_ERR "nouveau_mm in use at destroy time!\n");
@@ -3621,7 +3609,7 @@ index f18cdfc..43a96b9 100644
#define NV50_PDISPLAY_USER(i) ((i) * 0x1000 + 0x00640000)
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
-index 2706cb3..b75258a 100644
+index 2706cb3..c8a463b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -12,8 +12,8 @@ struct nouveau_sgdma_be {
@@ -3693,7 +3681,7 @@ index 2706cb3..b75258a 100644
}
return 0;
-@@ -72,25 +57,16 @@ static void
+@@ -72,26 +57,20 @@ static void
nouveau_sgdma_clear(struct ttm_backend *be)
{
struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
@@ -3721,9 +3709,13 @@ index 2706cb3..b75258a 100644
- nvbe->pages = NULL;
- nvbe->ttm_alloced = NULL;
- nvbe->nr_pages = 0;
++ nvbe->unmap_pages = false;
}
++
++ nvbe->pages = NULL;
}
+ static void
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 10656e4..82478e0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -5809,9 +5801,8 @@ index d43c46c..8c979b3 100644
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- int i;
--
-- NV_DEBUG(dev, "\n");
+- NV_DEBUG(dev, "\n");
+ /* upload context program, initialise ctxctl defaults */
+ nv_wr32(dev, 0x400324, 0x00000000);
+ for (i = 0; i < pgraph->ctxprog_size; i++)
@@ -5823,7 +5814,7 @@ index d43c46c..8c979b3 100644
+ nv_wr32(dev, 0x400724, 0x00000000);
+ nv_wr32(dev, 0x40032c, 0x00000000);
+ nv_wr32(dev, 0x400320, 4); /* CTXCTL_CMD = NEWCTXDMA */
-+
+
+ /* some unknown zcull magic */
switch (dev_priv->chipset & 0xf0) {
case 0x50:
@@ -6088,14 +6079,13 @@ index e4b2b9e..618c144 100644
- 0x00, 0x00
- };
- const u32 *map = pll_map;
--
++ struct drm_nouveau_private *dev_priv = dev->dev_private;
++ u32 sctl, sdiv, sclk;
+
- while (map[1]) {
- if (id == map[1])
- return map[0];
- map += 2;
-+ struct drm_nouveau_private *dev_priv = dev->dev_private;
-+ u32 sctl, sdiv, sclk;
-+
+ /* refclk for the 0xe8xx plls is a fixed frequency */
+ if (clk >= 0x40) {
+ if (dev_priv->chipset == 0xaf) {
@@ -6178,8 +6168,7 @@ index e4b2b9e..618c144 100644
+ NV_DEBUG(dev, "no clock for 0x%04x/0x%02x\n", pll, clk);
+ return 0;
+ }
-
-- ret = get_pll_limits(dev, id, &pll);
++
+ switch (khz) {
+ case 27000:
+ reg->clk = 0x00000100;
@@ -6209,7 +6198,8 @@ index e4b2b9e..618c144 100644
+ return oclk;
+ }
+ }
-+
+
+- ret = get_pll_limits(dev, id, &pll);
+ if (!pll) {
+ NV_ERROR(dev, "bad freq %02x: %d %d\n", clk, khz, sclk);
+ return -ERANGE;
@@ -6325,23 +6315,20 @@ index e4b2b9e..618c144 100644
+ int ret;
- ret = get_pll_limits(dev, id, &limits);
+- if (ret < 0)
+- return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return ERR_PTR(-ENOMEM);
-+
-+ ret = calc_clk(dev, 0x10, 0x4200, perflvl->core, &info->nclk);
- if (ret < 0)
-- return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
-+ goto out;
- off = nva3_pm_pll_offset(id);
- if (id < 0)
- return ERR_PTR(-EINVAL);
-+ ret = calc_clk(dev, 0x11, 0x4220, perflvl->shader, &info->sclk);
++ ret = calc_clk(dev, 0x10, 0x4200, perflvl->core, &info->nclk);
+ if (ret < 0)
+ goto out;
-+ ret = calc_clk(dev, 0x12, 0x4000, perflvl->memory, &info->mclk);
++ ret = calc_clk(dev, 0x11, 0x4220, perflvl->shader, &info->sclk);
+ if (ret < 0)
+ goto out;
@@ -6353,7 +6340,10 @@ index e4b2b9e..618c144 100644
- pll->src1 = 0x004160 + (off * 4);
- pll->ctrl = limits.reg + 0;
- pll->coef = limits.reg + 4;
--
++ ret = calc_clk(dev, 0x12, 0x4000, perflvl->memory, &info->mclk);
++ if (ret < 0)
++ goto out;
+
- /* If target clock is within [-2, 3) MHz of a divisor, we'll
- * use that instead of calculating MNP values
- */
diff --git a/kernel.spec b/kernel.spec
index 0239834..bd9edeb 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -42,7 +42,7 @@ Summary: The Linux kernel
# When changing real_sublevel below, reset this by hand to 1
# (or to 0 and then use rpmdev-bumpspec).
#
-%global baserelease 1
+%global baserelease 2
%global fedora_build %{baserelease}
# real_sublevel is the 3.x kernel version we're starting with
@@ -1878,6 +1878,9 @@ fi
# and build.
%changelog
+* Mon Nov 28 2011 Ben Skeggs <bskeggs at redhat.com> 3.1.3-2
+- nouveau: fix two instances of an oops in ttm clear() (rhbz#751753)
+
* Mon Nov 28 2011 Chuck Ebbert <cebbert at redhat.com> 2.6.41.3-1
- Fake version 2.6.4X by changing UTSNAME
(instead of changing the internal kernel version)
More information about the scm-commits
mailing list